Bug 1584007 - allow ClientManager to register "future" ClientSources r=dom-workers-and-storage-reviewers,asuth

Differential Revision: https://phabricator.services.mozilla.com/D66520
This commit is contained in:
Eden Chuang 2021-05-24 13:55:06 +00:00
parent 2ed195d384
commit 9ca5730156
7 changed files with 138 additions and 0 deletions

View File

@ -226,6 +226,36 @@ WorkerPrivate* ClientManager::GetWorkerPrivate() const {
return GetActor()->GetWorkerPrivate();
}
// Used to share logic between ExpectFutureSource and ForgetFutureSource.
/* static */ bool ClientManager::ExpectOrForgetFutureSource(
const ClientInfo& aClientInfo,
bool (PClientManagerChild::*aMethod)(const IPCClientInfo&)) {
bool rv = true;
RefPtr<ClientManager> mgr = ClientManager::GetOrCreateForCurrentThread();
mgr->MaybeExecute(
[&](ClientManagerChild* aActor) {
if (!(aActor->*aMethod)(aClientInfo.ToIPC())) {
rv = false;
}
},
[&] { rv = false; });
return rv;
}
/* static */ bool ClientManager::ExpectFutureSource(
const ClientInfo& aClientInfo) {
return ExpectOrForgetFutureSource(
aClientInfo, &PClientManagerChild::SendExpectFutureClientSource);
}
/* static */ bool ClientManager::ForgetFutureSource(
const ClientInfo& aClientInfo) {
return ExpectOrForgetFutureSource(
aClientInfo, &PClientManagerChild::SendForgetFutureClientSource);
}
// static
void ClientManager::Startup() {
MOZ_ASSERT(NS_IsMainThread());

View File

@ -8,6 +8,7 @@
#include "mozilla/dom/ClientOpPromise.h"
#include "mozilla/dom/ClientThing.h"
#include "mozilla/dom/PClientManagerChild.h"
class nsIPrincipal;
@ -73,7 +74,29 @@ class ClientManager final : public ClientThing<ClientManagerChild> {
// Private methods called by ClientSource
mozilla::dom::WorkerPrivate* GetWorkerPrivate() const;
// Don't use - use {Expect,Forget}FutureSource instead.
static bool ExpectOrForgetFutureSource(
const ClientInfo& aClientInfo,
bool (PClientManagerChild::*aMethod)(const IPCClientInfo&));
public:
// Asynchronously declare that a ClientSource will possibly be constructed
// from an equivalent ClientInfo in the future. This must be called before any
// any ClientHandles are created with the ClientInfo to avoid race conditions
// when ClientHandles query the ClientManagerService.
//
// This method exists so that the ClientManagerService can determine if a
// particular ClientSource can be expected to exist in the future or has
// already existed and been destroyed.
//
// If it's later known that the expected ClientSource will not be
// constructed, ForgetFutureSource must be called.
static bool ExpectFutureSource(const ClientInfo& aClientInfo);
// May also be called even when the "future" source has become a "real"
// source, in which case this is a no-op.
static bool ForgetFutureSource(const ClientInfo& aClientInfo);
// Initialize the ClientManager at process start. This
// does book-keeping like creating a TLS identifier, etc.
// This should only be called by process startup code.

View File

@ -11,6 +11,7 @@
#include "ClientManagerOpParent.h"
#include "ClientManagerService.h"
#include "ClientSourceParent.h"
#include "ClientValidation.h"
#include "mozilla/dom/PClientNavigateOpParent.h"
#include "mozilla/Unused.h"
@ -106,4 +107,27 @@ ClientManagerParent::~ClientManagerParent() { mService->RemoveManager(this); }
void ClientManagerParent::Init() { mService->AddManager(this); }
IPCResult ClientManagerParent::RecvExpectFutureClientSource(
const IPCClientInfo& aClientInfo) {
if (NS_WARN_IF(!ClientIsValidPrincipalInfo(aClientInfo.principalInfo()))) {
return IPC_FAIL(this, "Invalid PrincipalInfo.");
}
RefPtr<ClientManagerService> cms =
ClientManagerService::GetOrCreateInstance();
Unused << NS_WARN_IF(!cms->ExpectFutureSource(aClientInfo));
return IPC_OK();
}
IPCResult ClientManagerParent::RecvForgetFutureClientSource(
const IPCClientInfo& aClientInfo) {
if (NS_WARN_IF(!ClientIsValidPrincipalInfo(aClientInfo.principalInfo()))) {
return IPC_FAIL(this, "Invalid PrincipalInfo.");
}
RefPtr<ClientManagerService> cms = ClientManagerService::GetInstance();
cms->ForgetFutureSource(aClientInfo);
return IPC_OK();
}
} // namespace mozilla::dom

View File

@ -52,6 +52,12 @@ class ClientManagerParent final : public PClientManagerParent {
PClientSourceParent* aActor,
const ClientSourceConstructorArgs& aArgs) override;
mozilla::ipc::IPCResult RecvExpectFutureClientSource(
const IPCClientInfo& aClientInfo) override;
mozilla::ipc::IPCResult RecvForgetFutureClientSource(
const IPCClientInfo& aClientInfo) override;
public:
ClientManagerParent();
~ClientManagerParent();

View File

@ -294,6 +294,50 @@ bool ClientManagerService::RemoveSource(ClientSourceParent* aSource) {
return true;
}
bool ClientManagerService::ExpectFutureSource(
const IPCClientInfo& aClientInfo) {
AssertIsOnBackgroundThread();
if (!mSourceTable.WithEntryHandle(
aClientInfo.id(), [&aClientInfo](auto&& entry) {
// Prevent overwrites.
if (entry.HasEntry()) {
return false;
}
entry.Insert(SourceTableEntry(
VariantIndex<0>(), FutureClientSourceParent(aClientInfo)));
return true;
})) {
return false;
}
return true;
}
void ClientManagerService::ForgetFutureSource(
const IPCClientInfo& aClientInfo) {
AssertIsOnBackgroundThread();
auto entry = mSourceTable.Lookup(aClientInfo.id());
if (entry) {
if (entry.Data().is<ClientSourceParent*>()) {
return;
}
if (!XRE_IsE10sParentProcess() &&
entry.Data().as<FutureClientSourceParent>().IsAssociated()) {
return;
}
CopyableErrorResult rv;
rv.ThrowInvalidStateError("Client creation aborted.");
entry.Data().as<FutureClientSourceParent>().RejectPromiseIfExists(rv);
entry.Remove();
}
}
RefPtr<SourcePromise> ClientManagerService::FindSource(
const nsID& aID, const PrincipalInfo& aPrincipalInfo) {
AssertIsOnBackgroundThread();
@ -306,6 +350,7 @@ RefPtr<SourcePromise> ClientManagerService::FindSource(
}
if (entry.Data().is<FutureClientSourceParent>()) {
entry.Data().as<FutureClientSourceParent>().SetAsAssociated();
return entry.Data().as<FutureClientSourceParent>().Promise();
}

View File

@ -115,6 +115,13 @@ class ClientManagerService final {
bool RemoveSource(ClientSourceParent* aSource);
// Returns true when a FutureClientSourceParent is successfully added.
bool ExpectFutureSource(const IPCClientInfo& aClientInfo);
// May still be called if it's possible that the FutureClientSourceParent
// no longer exists.
void ForgetFutureSource(const IPCClientInfo& aClientInfo);
RefPtr<SourcePromise> FindSource(
const nsID& aID, const mozilla::ipc::PrincipalInfo& aPrincipalInfo);

View File

@ -32,6 +32,9 @@ parent:
async PClientManagerOp(ClientOpConstructorArgs aArgs);
async PClientSource(ClientSourceConstructorArgs aArgs);
async ExpectFutureClientSource(IPCClientInfo aClientInfo);
async ForgetFutureClientSource(IPCClientInfo aClientInfo);
child:
async PClientNavigateOp(ClientNavigateOpConstructorArgs aArgs);