зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1700850 - Part 1: Make temporary background profiles per-installation and unique. r=bytesized,mossop
Differential Revision: https://phabricator.services.mozilla.com/D110310
This commit is contained in:
Родитель
b27ba19e6d
Коммит
ea97f27b52
|
@ -13,8 +13,8 @@ namespace mozilla {
|
|||
|
||||
NS_IMPL_ISUPPORTS(BackgroundTasks, nsIBackgroundTasks);
|
||||
|
||||
nsresult BackgroundTasks::GetOrCreateTemporaryProfileDirectoryImpl(
|
||||
nsIFile** aFile) {
|
||||
nsresult BackgroundTasks::CreateTemporaryProfileDirectoryImpl(
|
||||
const nsCString& aInstallHash, nsIFile** aFile) {
|
||||
if (mBackgroundTask.isNothing()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -30,35 +30,21 @@ nsresult BackgroundTasks::GetOrCreateTemporaryProfileDirectoryImpl(
|
|||
rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// TODO: mix in the application hash and perhaps add some additional
|
||||
// randomness.
|
||||
rv = file->AppendNative(
|
||||
nsPrintfCString("backgroundtask-%s", mBackgroundTask.ref().get()));
|
||||
// The base path is /tmp/[vendor]BackgroundTask-[pathHash]-[taskName].
|
||||
rv = file->AppendNative(nsPrintfCString("%sBackgroundTask-%s-%s",
|
||||
MOZ_APP_VENDOR, aInstallHash.get(),
|
||||
mBackgroundTask.ref().get()));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Make sure that the profile path exists and it's a directory.
|
||||
bool exists;
|
||||
rv = file->Exists(&exists);
|
||||
// Create a unique profile directory. This can fail if there are too many
|
||||
// (thousands) of existing directories, which is unlikely to happen.
|
||||
rv = file->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!exists) {
|
||||
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
bool isDir;
|
||||
rv = file->IsDirectory(&isDir);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!isDir) {
|
||||
return NS_ERROR_FILE_DESTINATION_NOT_DIR;
|
||||
}
|
||||
}
|
||||
|
||||
rv = file->Clone(getter_AddRefs(mProfD));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsString path;
|
||||
file->GetPath(path);
|
||||
|
||||
file.forget(aFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -99,12 +99,14 @@ class BackgroundTasks final : public nsIBackgroundTasks {
|
|||
return GetBackgroundTasks().isSome();
|
||||
}
|
||||
|
||||
static nsresult GetOrCreateTemporaryProfileDirectory(nsIFile** aFile) {
|
||||
static nsresult CreateTemporaryProfileDirectory(const nsCString& aInstallHash,
|
||||
nsIFile** aFile) {
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return GetSingleton()->GetOrCreateTemporaryProfileDirectoryImpl(aFile);
|
||||
return GetSingleton()->CreateTemporaryProfileDirectoryImpl(aInstallHash,
|
||||
aFile);
|
||||
}
|
||||
|
||||
static nsresult RunBackgroundTask(nsICommandLine* aCmdLine) {
|
||||
|
@ -131,7 +133,8 @@ class BackgroundTasks final : public nsIBackgroundTasks {
|
|||
Maybe<nsCString> mBackgroundTask;
|
||||
nsCOMPtr<nsIFile> mProfD;
|
||||
|
||||
nsresult GetOrCreateTemporaryProfileDirectoryImpl(nsIFile** aFile);
|
||||
nsresult CreateTemporaryProfileDirectoryImpl(const nsCString& aInstallHash,
|
||||
nsIFile** aFile);
|
||||
|
||||
virtual ~BackgroundTasks() = default;
|
||||
};
|
||||
|
|
|
@ -13,6 +13,9 @@ with Files("docs/**"):
|
|||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
for var in ("MOZ_APP_VENDOR",):
|
||||
DEFINES[var] = '"%s"' % CONFIG[var]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"BackgroundTasks.cpp",
|
||||
]
|
||||
|
@ -51,6 +54,7 @@ TESTING_JS_MODULES.backgroundtasks += [
|
|||
"tests/BackgroundTask_crash.jsm",
|
||||
"tests/BackgroundTask_policies.jsm",
|
||||
"tests/BackgroundTask_shouldprocessupdates.jsm",
|
||||
"tests/BackgroundTask_unique_profile.jsm",
|
||||
"tests/BackgroundTask_update_sync_manager.jsm",
|
||||
"tests/BackgroundTask_wait.jsm",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["runBackgroundTask"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Subprocess } = ChromeUtils.import(
|
||||
"resource://gre/modules/Subprocess.jsm"
|
||||
);
|
||||
|
||||
async function runBackgroundTask(commandLine) {
|
||||
let sentinel = commandLine.getArgument(0);
|
||||
let count =
|
||||
commandLine.length > 1
|
||||
? Number.parseInt(commandLine.getArgument(1), 10)
|
||||
: 1;
|
||||
|
||||
let main = await ChromeUtils.requestProcInfo();
|
||||
let info = [main.pid, Services.dirsvc.get("ProfD", Ci.nsIFile).path];
|
||||
|
||||
// `dump` prints to the console without formatting.
|
||||
dump(`${count}: ${sentinel}${JSON.stringify(info)}${sentinel}\n`);
|
||||
|
||||
// Maybe launch a child.
|
||||
if (count <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let command = Services.dirsvc.get("XREExeF", Ci.nsIFile).path;
|
||||
let args = [
|
||||
"--backgroundtask",
|
||||
"unique_profile",
|
||||
sentinel,
|
||||
(count - 1).toString(),
|
||||
];
|
||||
|
||||
// We must assemble all of the string fragments from stdout.
|
||||
let stdoutChunks = [];
|
||||
let proc = await Subprocess.call({
|
||||
command,
|
||||
arguments: args,
|
||||
stderr: "stdout",
|
||||
// Don't inherit this task's profile path.
|
||||
environmentAppend: true,
|
||||
environment: { XRE_PROFILE_PATH: null },
|
||||
}).then(p => {
|
||||
p.stdin.close();
|
||||
const dumpPipe = async pipe => {
|
||||
let data = await pipe.readString();
|
||||
while (data) {
|
||||
data = await pipe.readString();
|
||||
stdoutChunks.push(data);
|
||||
}
|
||||
};
|
||||
dumpPipe(p.stdout);
|
||||
|
||||
return p;
|
||||
});
|
||||
|
||||
let { exitCode } = await proc.wait();
|
||||
|
||||
let stdout = stdoutChunks.join("");
|
||||
for (let line of stdout.split(/\r\n|\r|\n/).slice(0, -1)) {
|
||||
dump(`${count}> ${line}\n`);
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
|
@ -32,7 +32,7 @@ function getFirefoxExecutableFile() {
|
|||
|
||||
async function do_backgroundtask(
|
||||
task,
|
||||
options = { extraArgs: [], extraEnv: {} }
|
||||
options = { extraArgs: [], extraEnv: {}, stdoutLines: null }
|
||||
) {
|
||||
options = Object.assign({}, options);
|
||||
options.extraArgs = options.extraArgs || [];
|
||||
|
@ -48,7 +48,7 @@ async function do_backgroundtask(
|
|||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
|
||||
let uri = protocolHandler.getSubstitution("testing-common");
|
||||
Assert.ok(uri, "resource://testing-common is not substituted");
|
||||
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;
|
||||
|
@ -59,6 +59,8 @@ async function do_backgroundtask(
|
|||
options.extraEnv
|
||||
)}`
|
||||
);
|
||||
// We must assemble all of the string fragments from stdout.
|
||||
let stdoutChunks = [];
|
||||
let proc = await Subprocess.call({
|
||||
command,
|
||||
arguments: args,
|
||||
|
@ -70,9 +72,7 @@ async function do_backgroundtask(
|
|||
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");
|
||||
}
|
||||
stdoutChunks.push(data);
|
||||
data = await pipe.readString();
|
||||
}
|
||||
};
|
||||
|
@ -82,6 +82,15 @@ async function do_backgroundtask(
|
|||
});
|
||||
|
||||
let { exitCode } = await proc.wait();
|
||||
|
||||
let stdout = stdoutChunks.join("");
|
||||
for (let line of stdout.split(/\r\n|\r|\n/).slice(0, -1)) {
|
||||
dump("> " + line + "\n");
|
||||
if (options.stdoutLines !== null && options.stdoutLines !== undefined) {
|
||||
options.stdoutLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Run a background task which itself waits for a launched background task, which itself waits for a
|
||||
// launched background task, etc. This is an easy way to ensure that tasks are running concurrently
|
||||
// without requiring concurrency primitives.
|
||||
add_task(async function test_backgroundtask_unique_profile() {
|
||||
let sentinel = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID()
|
||||
.toString();
|
||||
sentinel = sentinel.substring(1, sentinel.length - 1);
|
||||
|
||||
let count = 3;
|
||||
let stdoutLines = [];
|
||||
let exitCode = await do_backgroundtask("unique_profile", {
|
||||
extraArgs: [sentinel, count.toString()],
|
||||
stdoutLines,
|
||||
});
|
||||
Assert.equal(0, exitCode);
|
||||
|
||||
let infos = [];
|
||||
let profiles = new Set();
|
||||
for (let line of stdoutLines) {
|
||||
if (line.includes(sentinel)) {
|
||||
let info = JSON.parse(line.split(sentinel)[1]);
|
||||
infos.push(info);
|
||||
profiles.add(info[1]);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.equal(
|
||||
count,
|
||||
profiles.size,
|
||||
`Found ${count} distinct profiles: ${JSON.stringify(
|
||||
Array.from(profiles)
|
||||
)} in: ${JSON.stringify(infos)}`
|
||||
);
|
||||
});
|
|
@ -14,6 +14,7 @@ support-files =
|
|||
[test_backgroundtask_policies.js]
|
||||
[test_backgroundtask_shouldprocessupdates.js]
|
||||
[test_backgroundtask_specific_pref.js]
|
||||
[test_backgroundtask_unique_profile.js]
|
||||
[test_backgroundtask_update_sync_manager.js]
|
||||
[test_backgroundtasksutils.js]
|
||||
[test_manifest_with_backgroundtask.js]
|
||||
|
|
|
@ -4528,9 +4528,12 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
|
|||
if (BackgroundTasks::IsBackgroundTaskMode()) {
|
||||
// Allow tests to specify profile path via the environment.
|
||||
if (!EnvHasValue("XRE_PROFILE_PATH")) {
|
||||
nsString installHash;
|
||||
mDirProvider.GetInstallHash(installHash);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = BackgroundTasks::GetOrCreateTemporaryProfileDirectory(
|
||||
getter_AddRefs(file));
|
||||
nsresult rv = BackgroundTasks::CreateTemporaryProfileDirectory(
|
||||
NS_LossyConvertUTF16toASCII(installHash), getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче