Files
tubestation/dom/ipc/UniqueContentParentKeepAlive.cpp
Nika Layzell d749c1f081 Bug 1942128 - Part 1: Add a mechanism to allow Chrome JS to manage headless content processes, r=smaug
This adds a new XPCOM type which will hold the
`UniqueContentParentKeepAlive` internally, and can be returned into
Chrome JS using a new method on ChromeUtils.sys.mjs.

The KeepAlive will be cleaned up when the cycle-collected JS object is
destroyed, or when the `invalidateKeepAlive()` method is called on the
object (for times when JS wants to take more direct control over the
lifecycle of the KeepAlive).

In the future it would be possible to add methods to e.g. get a
KeepAlive for a specific existing process, or clone a KeepAlive object,
however that is not required for the initial use-case.

This will be used in part 2 to replace the use of hidden iframes with
dummy pages to create the "inference" content process.

Differential Revision: https://phabricator.services.mozilla.com/D234906
2025-02-07 20:32:03 +00:00

120 lines
4.1 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/dom/UniqueContentParentKeepAlive.h"
#include "mozilla/dom/ContentParent.h"
namespace mozilla::dom {
void ContentParentKeepAliveDeleter::operator()(ContentParent* aProcess) {
AssertIsOnMainThread();
if (RefPtr<ContentParent> process = dont_AddRef(aProcess)) {
process->RemoveKeepAlive(mBrowserId);
}
}
void ContentParentKeepAliveDeleter::operator()(
ThreadsafeContentParentHandle* aHandle) {
if (RefPtr<ThreadsafeContentParentHandle> handle = dont_AddRef(aHandle)) {
NS_DispatchToMainThread(NS_NewRunnableFunction(
"ThreadsafeContentParentKeepAliveDeleter",
[handle = std::move(handle), browserId = mBrowserId]() {
AssertIsOnMainThread();
if (RefPtr<ContentParent> process = handle->GetContentParent()) {
process->RemoveKeepAlive(browserId);
}
}));
}
}
UniqueContentParentKeepAlive UniqueContentParentKeepAliveFromThreadsafe(
UniqueThreadsafeContentParentKeepAlive aKeepAlive) {
AssertIsOnMainThread();
if (aKeepAlive) {
uint64_t browserId = aKeepAlive.get_deleter().mBrowserId;
RefPtr<ThreadsafeContentParentHandle> handle =
dont_AddRef(aKeepAlive.release());
RefPtr<ContentParent> process = handle->GetContentParent();
return UniqueContentParentKeepAlive{process.forget().take(),
{.mBrowserId = browserId}};
}
return nullptr;
}
UniqueThreadsafeContentParentKeepAlive UniqueContentParentKeepAliveToThreadsafe(
UniqueContentParentKeepAlive aKeepAlive) {
AssertIsOnMainThread();
if (aKeepAlive) {
uint64_t browserId = aKeepAlive.get_deleter().mBrowserId;
RefPtr<ContentParent> process = dont_AddRef(aKeepAlive.release());
RefPtr<ThreadsafeContentParentHandle> handle = process->ThreadsafeHandle();
return UniqueThreadsafeContentParentKeepAlive{handle.forget().take(),
{.mBrowserId = browserId}};
}
return nullptr;
}
namespace {
class XpcomContentParentKeepAlive final : public nsIContentParentKeepAlive {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(XpcomContentParentKeepAlive)
explicit XpcomContentParentKeepAlive(
UniqueContentParentKeepAlive&& aKeepAlive)
: mKeepAlive(std::move(aKeepAlive)) {}
NS_IMETHOD GetDomProcess(nsIDOMProcessParent** aResult) override {
nsCOMPtr<nsIDOMProcessParent> process = mKeepAlive.get();
process.forget(aResult);
return NS_OK;
}
NS_IMETHOD InvalidateKeepAlive() override {
mKeepAlive = nullptr;
return NS_OK;
}
private:
~XpcomContentParentKeepAlive() = default;
UniqueContentParentKeepAlive mKeepAlive;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(XpcomContentParentKeepAlive)
NS_IMPL_CYCLE_COLLECTING_RELEASE(XpcomContentParentKeepAlive)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XpcomContentParentKeepAlive)
NS_INTERFACE_MAP_ENTRY(nsIContentParentKeepAlive)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_CLASS(XpcomContentParentKeepAlive)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XpcomContentParentKeepAlive)
tmp->mKeepAlive = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XpcomContentParentKeepAlive)
// NOTE: We traverse through mKeepAlive as it is acting as a non-copyable
// `RefPtr<ContentParent>`.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mKeepAlive.get())
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
} // namespace
already_AddRefed<nsIContentParentKeepAlive> WrapContentParentKeepAliveForJS(
UniqueContentParentKeepAlive aKeepAlive) {
if (!aKeepAlive) {
return nullptr;
}
MOZ_ASSERT(!aKeepAlive->IsLaunching(),
"Cannot expose still-launching ContentParent to JS");
return MakeAndAddRef<XpcomContentParentKeepAlive>(std::move(aKeepAlive));
}
} // namespace mozilla::dom