Bug 1675850 - Add MOZ_BACKGROUNDTASKS flag, {nsI}BackgroundTasks IDL and class. r=mossop,firefox-build-system-reviewers,mhentges

This adds a build flag (defaulting to on in Nightly builds) and an
`AppConstants.jsm` definition.

It lays the foundation for managing an active background task.  A
singleton, exposed as an XPCOM service, owns the task name and lives
for the life of the application.

This will be wired into the application startup path in future
commits.  It's separated to allow the changes to category registration
to come early in the commit sequence.

Differential Revision: https://phabricator.services.mozilla.com/D96481
This commit is contained in:
Nick Alexander 2021-01-25 23:44:39 +00:00
parent 0492d8333a
commit 7360317f0c
9 changed files with 323 additions and 0 deletions

View File

@ -0,0 +1,91 @@
/* 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 "nsPrintfCString.h"
#include "SpecialSystemDirectory.h"
#include "mozilla/BackgroundTasks.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Maybe.h"
namespace mozilla {
NS_IMPL_ISUPPORTS(BackgroundTasks, nsIBackgroundTasks);
nsresult BackgroundTasks::GetOrCreateTemporaryProfileDirectoryImpl(
nsIFile** aFile) {
if (mBackgroundTask.isNothing()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv;
nsCOMPtr<nsIFile> file;
if (mProfD) {
rv = mProfD->Clone(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
} else {
// We don't have the directory service at this point.
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()));
NS_ENSURE_SUCCESS(rv, rv);
// Make sure that the profile path exists and it's a directory.
bool exists;
rv = file->Exists(&exists);
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;
}
nsresult BackgroundTasks::GetIsBackgroundTaskMode(bool* result) {
*result = mBackgroundTask.isSome();
return NS_OK;
}
nsresult BackgroundTasks::BackgroundTaskName(nsAString& name) {
name.SetIsVoid(true);
if (mBackgroundTask.isSome()) {
name.AssignASCII(mBackgroundTask.ref());
}
return NS_OK;
}
nsresult BackgroundTasks::OverrideBackgroundTaskNameForTesting(
const nsAString& name) {
if (name.IsVoid()) {
mBackgroundTask = Nothing();
} else {
mBackgroundTask = Some(NS_LossyConvertUTF16toASCII(name));
}
return NS_OK;
}
mozilla::StaticRefPtr<BackgroundTasks> BackgroundTasks::sSingleton;
} // namespace mozilla

View File

@ -0,0 +1,132 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 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/. */
#ifndef mozilla_BackgroundTasks_h
#define mozilla_BackgroundTasks_h
#include "nsCOMPtr.h"
#include "nsIBackgroundTasks.h"
#include "nsICommandLine.h"
#include "nsIFile.h"
#include "nsISupports.h"
#include "nsString.h"
#include "nsXULAppAPI.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Maybe.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Unused.h"
#include "prenv.h"
namespace mozilla {
class BackgroundTasks final : public nsIBackgroundTasks {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIBACKGROUNDTASKS
public:
explicit BackgroundTasks(Maybe<nsCString> aBackgroundTask)
: mBackgroundTask(aBackgroundTask) {}
static void Init(Maybe<nsCString> aBackgroundTask) {
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
MOZ_RELEASE_ASSERT(!sSingleton,
"BackgroundTasks singleton already initialized");
sSingleton = new BackgroundTasks(aBackgroundTask);
ClearOnShutdown(&sSingleton);
}
static void Shutdown() {
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
if (!sSingleton) {
return;
}
if (sSingleton->mProfD) {
sSingleton->mProfD->Remove(/* aRecursive */ true);
}
sSingleton = nullptr;
}
/**
* Return a raw pointer to the singleton instance. Use this accessor in C++
* code that just wants to call a method on the instance, but does not need to
* hold a reference.
*/
static BackgroundTasks* GetSingleton() {
if (!sSingleton) {
// xpcshell doesn't set up background tasks: default to no background
// task.
Init(Nothing());
}
MOZ_RELEASE_ASSERT(
sSingleton, "BackgroundTasks singleton should have been initialized");
return sSingleton.get();
}
/**
* Return an addRef'd pointer to the singleton instance. This is used by the
* XPCOM constructor that exists to support usage from JS.
*/
static already_AddRefed<BackgroundTasks> GetSingletonAddRefed() {
return RefPtr<BackgroundTasks>(GetSingleton()).forget();
}
static const Maybe<nsCString> GetBackgroundTasks() {
if (!XRE_IsParentProcess()) {
return Nothing();
}
return GetSingleton()->mBackgroundTask;
}
static bool IsBackgroundTaskMode() {
if (!XRE_IsParentProcess()) {
return false;
}
return GetBackgroundTasks().isSome();
}
static nsresult GetOrCreateTemporaryProfileDirectory(nsIFile** aFile) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
return GetSingleton()->GetOrCreateTemporaryProfileDirectoryImpl(aFile);
}
static nsresult RunBackgroundTask(nsICommandLine* aCmdLine) {
Maybe<nsCString> task = GetBackgroundTasks();
if (task.isNothing()) {
return NS_ERROR_NOT_AVAILABLE;
}
// For now, do nothing.
return NS_OK;
}
protected:
static StaticRefPtr<BackgroundTasks> sSingleton;
Maybe<nsCString> mBackgroundTask;
nsCOMPtr<nsIFile> mProfD;
nsresult GetOrCreateTemporaryProfileDirectoryImpl(nsIFile** aFile);
virtual ~BackgroundTasks() = default;
};
} // namespace mozilla
#endif // mozilla_BackgroundTasks_h

View File

@ -0,0 +1,13 @@
Classes = [
{
'cid': '{cdc33a1f-e8ae-4a4f-85d0-6ec633fe872c}',
'contract_ids': [
'@mozilla.org/backgroundtasks;1',
],
'type': 'BackgroundTasks',
'singleton': True,
'constructor': 'BackgroundTasks::GetSingletonAddRefed',
'headers': ['mozilla/BackgroundTasks.h'],
'processes': ProcessSelector.ANY_PROCESS,
},
]

View File

@ -0,0 +1,27 @@
# 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/.
with Files("**"):
# TODO: House this somewhere more specific?
BUG_COMPONENT = ("Toolkit", "Startup and Profile System")
FINAL_LIBRARY = "xul"
UNIFIED_SOURCES += [
"BackgroundTasks.cpp",
]
EXPORTS.mozilla += [
"BackgroundTasks.h",
]
XPCOM_MANIFESTS += [
"components.conf",
]
XPIDL_SOURCES += [
"nsIBackgroundTasks.idl",
]
XPIDL_MODULE = "toolkit_backgroundtasks"

View File

@ -0,0 +1,32 @@
/* -*- 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"
/**
* Determine if this instance is running background task mode and
* what, if any, task is active.
*/
[scriptable, uuid(353dccb8-a863-49e4-941b-007382eac168)]
interface nsIBackgroundTasks : nsISupports
{
/**
* True if and only if this invocation is running in background task mode.
*/
readonly attribute boolean isBackgroundTaskMode;
/**
* A non-empty task name if this invocation is running in background
* task mode, or `null` if this invocation is not running in
* background task mode.
*/
AString backgroundTaskName();
/**
* Should only be used for testing.
* Set the background task name.
*/
void overrideBackgroundTaskNameForTesting(in AString taskName);
};

View File

@ -129,6 +129,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] != "android":
if CONFIG["MOZ_BUILD_APP"] == "browser":
DIRS += ["normandy", "messaging-system"]
if CONFIG["MOZ_BACKGROUNDTASKS"]:
DIRS += ["backgroundtasks"]
# This is only packaged for browser since corrupt JAR and XPI files tend to be a desktop-OS problem.
if CONFIG["MOZ_BUILD_APP"] == "browser":
DIRS += ["corroborator"]

View File

@ -219,6 +219,13 @@ this.AppConstants = Object.freeze({
false,
#endif
MOZ_BACKGROUNDTASKS:
#ifdef MOZ_BACKGROUNDTASKS
true,
#else
false,
#endif
MOZ_UPDATE_AGENT:
#ifdef MOZ_UPDATE_AGENT
true,

View File

@ -292,6 +292,7 @@ for var in (
for var in (
"MOZ_ALLOW_ADDON_SIDELOAD",
"MOZ_BACKGROUNDTASKS",
"MOZ_SYSTEM_NSS",
"MOZ_UNSIGNED_APP_SCOPE",
"MOZ_UNSIGNED_SYSTEM_SCOPE",

View File

@ -2495,3 +2495,20 @@ def oxidized_breakpad(target):
set_config("MOZ_OXIDIZED_BREAKPAD", True, when=oxidized_breakpad)
set_define("MOZ_OXIDIZED_BREAKPAD", True, when=oxidized_breakpad)
# Enable or disable running in background task mode: headless for
# periodic, short-lived, maintenance tasks.
# ==============================================================================
option(
"--enable-backgroundtasks",
default=milestone.is_nightly,
help="{Enable|Disable} running in background task mode",
)
set_config(
"MOZ_BACKGROUNDTASKS", depends_if("--enable-backgroundtasks")(lambda _: True)
)