mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Backed out changeset daecd36223c9 (bug 1584007) for ClientManagerService.cpp failures CLOSED TREE
This commit is contained in:
parent
846d70ee89
commit
e2c099719a
@ -9,8 +9,6 @@
|
|||||||
#include "ClientManager.h"
|
#include "ClientManager.h"
|
||||||
#include "ClientSource.h"
|
#include "ClientSource.h"
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
#include "mozilla/Result.h"
|
|
||||||
#include "mozilla/ResultExtensions.h"
|
|
||||||
#include "mozilla/dom/ServiceWorkerDescriptor.h"
|
#include "mozilla/dom/ServiceWorkerDescriptor.h"
|
||||||
#include "mozilla/ipc/BackgroundUtils.h"
|
#include "mozilla/ipc/BackgroundUtils.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
@ -141,17 +139,10 @@ class ClientChannelHelper final : public nsIInterfaceRequestor,
|
|||||||
// create a ClientSource when the final channel propagates back
|
// create a ClientSource when the final channel propagates back
|
||||||
// to the child.
|
// to the child.
|
||||||
if (mMode == Mode::Mode_Parent) {
|
if (mMode == Mode::Mode_Parent) {
|
||||||
const Maybe<ClientInfo>& oldReservedInfo =
|
Maybe<ClientInfo> reservedInfo =
|
||||||
oldLoadInfo->GetReservedClientInfo();
|
|
||||||
if (oldReservedInfo) {
|
|
||||||
MOZ_TRY(ClientManager::ForgetFutureClientSource(*oldReservedInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<ClientInfo> newReservedInfo =
|
|
||||||
ClientManager::CreateInfo(ClientType::Window, principal);
|
ClientManager::CreateInfo(ClientType::Window, principal);
|
||||||
if (newReservedInfo) {
|
if (reservedInfo) {
|
||||||
MOZ_TRY(ClientManager::ExpectFutureClientSource(*newReservedInfo));
|
newLoadInfo->SetReservedClientInfo(*reservedInfo);
|
||||||
newLoadInfo->SetReservedClientInfo(*newReservedInfo);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reservedClient.reset();
|
reservedClient.reset();
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "ClientHandleOpParent.h"
|
#include "ClientHandleOpParent.h"
|
||||||
#include "ClientManagerService.h"
|
#include "ClientManagerService.h"
|
||||||
#include "ClientPrincipalUtils.h"
|
|
||||||
#include "ClientSourceParent.h"
|
#include "ClientSourceParent.h"
|
||||||
#include "mozilla/dom/ClientIPCTypes.h"
|
#include "mozilla/dom/ClientIPCTypes.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
@ -28,10 +27,12 @@ void ClientHandleParent::ActorDestroy(ActorDestroyReason aReason) {
|
|||||||
mSource->DetachHandle(this);
|
mSource->DetachHandle(this);
|
||||||
mSource = nullptr;
|
mSource = nullptr;
|
||||||
} else {
|
} else {
|
||||||
mSourcePromiseRequestHolder.DisconnectIfExists();
|
mService->StopWaitingForSource(this, mClientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSourcePromiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
if (mSourcePromise) {
|
||||||
|
mSourcePromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PClientHandleOpParent* ClientHandleParent::AllocPClientHandleOpParent(
|
PClientHandleOpParent* ClientHandleParent::AllocPClientHandleOpParent(
|
||||||
@ -60,22 +61,13 @@ ClientHandleParent::~ClientHandleParent() { MOZ_DIAGNOSTIC_ASSERT(!mSource); }
|
|||||||
void ClientHandleParent::Init(const IPCClientInfo& aClientInfo) {
|
void ClientHandleParent::Init(const IPCClientInfo& aClientInfo) {
|
||||||
mClientId = aClientInfo.id();
|
mClientId = aClientInfo.id();
|
||||||
mPrincipalInfo = aClientInfo.principalInfo();
|
mPrincipalInfo = aClientInfo.principalInfo();
|
||||||
|
mSource = mService->FindSource(aClientInfo.id(), aClientInfo.principalInfo());
|
||||||
|
if (!mSource) {
|
||||||
|
mService->WaitForSource(this, aClientInfo.id());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Capturing `this` is okay because the callbacks are disconnected from the
|
mSource->AttachHandle(this);
|
||||||
// promise returned by `FindSource` in `ActorDestroy`, so the dangling
|
|
||||||
// pointers will never be used.
|
|
||||||
mService->FindSource(aClientInfo.id(), aClientInfo.principalInfo())
|
|
||||||
->Then(
|
|
||||||
GetCurrentThreadSerialEventTarget(), __func__,
|
|
||||||
[this](ClientSourceParent* aSource) {
|
|
||||||
mSourcePromiseRequestHolder.Complete();
|
|
||||||
FoundSource(aSource);
|
|
||||||
},
|
|
||||||
[this](nsresult) {
|
|
||||||
mSourcePromiseRequestHolder.Complete();
|
|
||||||
Unused << Send__delete__(this);
|
|
||||||
})
|
|
||||||
->Track(mSourcePromiseRequestHolder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientSourceParent* ClientHandleParent::GetSource() const { return mSource; }
|
ClientSourceParent* ClientHandleParent::GetSource() const { return mSource; }
|
||||||
@ -85,20 +77,28 @@ RefPtr<SourcePromise> ClientHandleParent::EnsureSource() {
|
|||||||
return SourcePromise::CreateAndResolve(mSource, __func__);
|
return SourcePromise::CreateAndResolve(mSource, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mSourcePromiseHolder.Ensure(__func__);
|
if (!mSourcePromise) {
|
||||||
|
mSourcePromise = new SourcePromise::Private(__func__);
|
||||||
|
}
|
||||||
|
return mSourcePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientHandleParent::FoundSource(ClientSourceParent* aSource) {
|
void ClientHandleParent::FoundSource(ClientSourceParent* aSource) {
|
||||||
MOZ_ASSERT(aSource->Info().Id() == mClientId);
|
MOZ_ASSERT(aSource->Info().Id() == mClientId);
|
||||||
if (!ClientMatchPrincipalInfo(aSource->Info().PrincipalInfo(),
|
if (!ClientMatchPrincipalInfo(aSource->Info().PrincipalInfo(),
|
||||||
mPrincipalInfo)) {
|
mPrincipalInfo)) {
|
||||||
|
if (mSourcePromise) {
|
||||||
|
mSourcePromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||||
|
}
|
||||||
Unused << Send__delete__(this);
|
Unused << Send__delete__(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSource = aSource;
|
mSource = aSource;
|
||||||
mSource->AttachHandle(this);
|
mSource->AttachHandle(this);
|
||||||
mSourcePromiseHolder.ResolveIfExists(aSource, __func__);
|
if (mSourcePromise) {
|
||||||
|
mSourcePromise->Resolve(aSource, __func__);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -6,26 +6,20 @@
|
|||||||
#ifndef _mozilla_dom_ClientHandleParent_h
|
#ifndef _mozilla_dom_ClientHandleParent_h
|
||||||
#define _mozilla_dom_ClientHandleParent_h
|
#define _mozilla_dom_ClientHandleParent_h
|
||||||
|
|
||||||
#include "ClientManagerService.h"
|
|
||||||
#include "mozilla/MozPromise.h"
|
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/dom/PClientHandleOpParent.h"
|
|
||||||
#include "mozilla/dom/PClientHandleParent.h"
|
#include "mozilla/dom/PClientHandleParent.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
class ClientManagerService;
|
||||||
class ClientSourceParent;
|
class ClientSourceParent;
|
||||||
|
|
||||||
|
typedef MozPromise<ClientSourceParent*, nsresult, /* IsExclusive = */ false>
|
||||||
|
SourcePromise;
|
||||||
|
|
||||||
class ClientHandleParent final : public PClientHandleParent {
|
class ClientHandleParent final : public PClientHandleParent {
|
||||||
RefPtr<ClientManagerService> mService;
|
RefPtr<ClientManagerService> mService;
|
||||||
|
|
||||||
// `mSource` and (`mSourcePromiseHolder`, `mSourcePromiseRequestHolder`) are
|
|
||||||
// mutually exclusive, so they could be combined in a `mozilla::Variant`.
|
|
||||||
ClientSourceParent* mSource;
|
ClientSourceParent* mSource;
|
||||||
MozPromiseHolder<SourcePromise> mSourcePromiseHolder;
|
|
||||||
|
|
||||||
MozPromiseRequestHolder<SourcePromise> mSourcePromiseRequestHolder;
|
|
||||||
|
|
||||||
nsID mClientId;
|
nsID mClientId;
|
||||||
PrincipalInfo mPrincipalInfo;
|
PrincipalInfo mPrincipalInfo;
|
||||||
|
@ -280,37 +280,6 @@ UniquePtr<ClientSource> ClientManager::CreateSourceFromInfo(
|
|||||||
return mgr->CreateSourceInternal(aClientInfo, aEventTarget);
|
return mgr->CreateSourceInternal(aClientInfo, aEventTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
nsresult ClientManager::ExpectOrForgetFutureClientSource(
|
|
||||||
bool aExpect, const ClientInfo& aClientInfo) {
|
|
||||||
nsresult rv = NS_OK;
|
|
||||||
|
|
||||||
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
|
|
||||||
mgr->MaybeExecute(
|
|
||||||
[&](ClientManagerChild* aActor) {
|
|
||||||
if (!aActor->SendExpectOrForgetFutureClientSource(
|
|
||||||
aExpect, aClientInfo.ToIPC())) {
|
|
||||||
rv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&] { rv = NS_ERROR_DOM_INVALID_STATE_ERR; });
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
nsresult ClientManager::ExpectFutureClientSource(
|
|
||||||
const ClientInfo& aClientInfo) {
|
|
||||||
return ExpectOrForgetFutureClientSource(true, aClientInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
nsresult ClientManager::ForgetFutureClientSource(
|
|
||||||
const ClientInfo& aClientInfo) {
|
|
||||||
return ExpectOrForgetFutureClientSource(false, aClientInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
Maybe<ClientInfo> ClientManager::CreateInfo(ClientType aType,
|
Maybe<ClientInfo> ClientManager::CreateInfo(ClientType aType,
|
||||||
nsIPrincipal* aPrincipal) {
|
nsIPrincipal* aPrincipal) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
@ -29,7 +29,6 @@ class ClientOpConstructorArgs;
|
|||||||
class ClientOpenWindowArgs;
|
class ClientOpenWindowArgs;
|
||||||
class ClientSource;
|
class ClientSource;
|
||||||
enum class ClientType : uint8_t;
|
enum class ClientType : uint8_t;
|
||||||
class PClientManagerChild;
|
|
||||||
class WorkerPrivate;
|
class WorkerPrivate;
|
||||||
|
|
||||||
// The ClientManager provides a per-thread singleton interface workering
|
// The ClientManager provides a per-thread singleton interface workering
|
||||||
@ -74,9 +73,6 @@ class ClientManager final : public ClientThing<ClientManagerChild> {
|
|||||||
// Private methods called by ClientSource
|
// Private methods called by ClientSource
|
||||||
mozilla::dom::WorkerPrivate* GetWorkerPrivate() const;
|
mozilla::dom::WorkerPrivate* GetWorkerPrivate() const;
|
||||||
|
|
||||||
static nsresult ExpectOrForgetFutureClientSource(
|
|
||||||
bool aExpect, const ClientInfo& aClientInfo);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initialize the ClientManager at process start. This
|
// Initialize the ClientManager at process start. This
|
||||||
// does book-keeping like creating a TLS identifier, etc.
|
// does book-keeping like creating a TLS identifier, etc.
|
||||||
@ -96,28 +92,9 @@ class ClientManager final : public ClientThing<ClientManagerChild> {
|
|||||||
static UniquePtr<ClientSource> CreateSourceFromInfo(
|
static UniquePtr<ClientSource> CreateSourceFromInfo(
|
||||||
const ClientInfo& aClientInfo, nsISerialEventTarget* aSerialEventTarget);
|
const ClientInfo& aClientInfo, nsISerialEventTarget* aSerialEventTarget);
|
||||||
|
|
||||||
// Asynchronously declare that a `ClientSource` will _possibly_ be constructed
|
|
||||||
// from an equivalent `ClientInfo` in the future. This must be called _before_
|
|
||||||
// any `ClientHandle`s are created with the `ClientInfo` to avoid race
|
|
||||||
// conditions when `ClientHandle`s 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, `ForgetFutureClientSource` _must_ be called.
|
|
||||||
static nsresult ExpectFutureClientSource(const ClientInfo& aClientInfo);
|
|
||||||
|
|
||||||
// Negates a prior call to `ExpectFutureClientSource`.
|
|
||||||
static nsresult ForgetFutureClientSource(const ClientInfo& aClientInfo);
|
|
||||||
|
|
||||||
// Allocate a new ClientInfo and id without creating a ClientSource. Used
|
// Allocate a new ClientInfo and id without creating a ClientSource. Used
|
||||||
// when we have a redirect that isn't exposed to the process that owns
|
// when we have a redirect that isn't exposed to the process that owns
|
||||||
// the global/ClientSource.
|
// the global/ClientSource.
|
||||||
//
|
|
||||||
// NOTE: callers should consider whether a call to `ExpectFutureClientSource`
|
|
||||||
// should be made when calling this method.
|
|
||||||
static Maybe<ClientInfo> CreateInfo(ClientType aType,
|
static Maybe<ClientInfo> CreateInfo(ClientType aType,
|
||||||
nsIPrincipal* aPrincipal);
|
nsIPrincipal* aPrincipal);
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "ClientManagerOpParent.h"
|
#include "ClientManagerOpParent.h"
|
||||||
#include "ClientManagerService.h"
|
#include "ClientManagerService.h"
|
||||||
#include "ClientSourceParent.h"
|
#include "ClientSourceParent.h"
|
||||||
#include "ClientValidation.h"
|
|
||||||
#include "mozilla/dom/PClientNavigateOpParent.h"
|
#include "mozilla/dom/PClientNavigateOpParent.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
@ -100,25 +99,6 @@ IPCResult ClientManagerParent::RecvPClientSourceConstructor(
|
|||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
|
||||||
ClientManagerParent::RecvExpectOrForgetFutureClientSource(
|
|
||||||
const bool& aExpect, const IPCClientInfo& aClientInfo) {
|
|
||||||
if (NS_WARN_IF(!ClientIsValidPrincipalInfo(aClientInfo.principalInfo()))) {
|
|
||||||
return IPC_FAIL(this, "Invalid PrincipalInfo.");
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<ClientManagerService> svc =
|
|
||||||
ClientManagerService::GetOrCreateInstance();
|
|
||||||
|
|
||||||
if (aExpect) {
|
|
||||||
svc->ExpectFutureSource(aClientInfo);
|
|
||||||
} else {
|
|
||||||
svc->ForgetFutureSource(aClientInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientManagerParent::ClientManagerParent()
|
ClientManagerParent::ClientManagerParent()
|
||||||
: mService(ClientManagerService::GetOrCreateInstance()) {}
|
: mService(ClientManagerService::GetOrCreateInstance()) {}
|
||||||
|
|
||||||
|
@ -52,9 +52,6 @@ class ClientManagerParent final : public PClientManagerParent {
|
|||||||
PClientSourceParent* aActor,
|
PClientSourceParent* aActor,
|
||||||
const ClientSourceConstructorArgs& aArgs) override;
|
const ClientSourceConstructorArgs& aArgs) override;
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvExpectOrForgetFutureClientSource(
|
|
||||||
const bool& aExpect, const IPCClientInfo& aClientInfo) override;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ClientManagerParent();
|
ClientManagerParent();
|
||||||
~ClientManagerParent();
|
~ClientManagerParent();
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "ClientOpenWindowUtils.h"
|
#include "ClientOpenWindowUtils.h"
|
||||||
#include "ClientPrincipalUtils.h"
|
#include "ClientPrincipalUtils.h"
|
||||||
#include "ClientSourceParent.h"
|
#include "ClientSourceParent.h"
|
||||||
#include "mozilla/dom/ClientIPCTypes.h"
|
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/dom/ServiceWorkerManager.h"
|
#include "mozilla/dom/ServiceWorkerManager.h"
|
||||||
#include "mozilla/dom/ServiceWorkerUtils.h"
|
#include "mozilla/dom/ServiceWorkerUtils.h"
|
||||||
@ -138,7 +137,7 @@ ClientManagerService::ClientManagerService() : mShutdown(false) {
|
|||||||
|
|
||||||
ClientManagerService::~ClientManagerService() {
|
ClientManagerService::~ClientManagerService() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mSourceTable.count() == 0);
|
MOZ_DIAGNOSTIC_ASSERT(mSourceTable.Count() == 0);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mManagerList.IsEmpty());
|
MOZ_DIAGNOSTIC_ASSERT(mManagerList.IsEmpty());
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceInstance == this);
|
MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceInstance == this);
|
||||||
@ -189,155 +188,52 @@ already_AddRefed<ClientManagerService> ClientManagerService::GetInstance() {
|
|||||||
return ref.forget();
|
return ref.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientManagerService::FutureClientSourceParent::FutureClientSourceParent(
|
|
||||||
const IPCClientInfo& aClientInfo)
|
|
||||||
: mPrincipalInfo(aClientInfo.principalInfo()) {}
|
|
||||||
|
|
||||||
// static
|
|
||||||
bool ClientManagerService::AddSource(ClientSourceParent* aSource) {
|
bool ClientManagerService::AddSource(ClientSourceParent* aSource) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(aSource);
|
MOZ_ASSERT(aSource);
|
||||||
|
auto entry = mSourceTable.LookupForAdd(aSource->Info().Id());
|
||||||
const nsID& id = aSource->Info().Id();
|
// Do not permit overwriting an existing ClientSource with the same
|
||||||
auto entryPtr = mSourceTable.lookupForAdd(id);
|
// UUID. This would allow a spoofed ClientParentSource actor to
|
||||||
|
// intercept postMessage() intended for the real actor.
|
||||||
if (entryPtr) {
|
if (NS_WARN_IF(!!entry)) {
|
||||||
SourceTableEntry& entry = entryPtr->value();
|
return false;
|
||||||
|
|
||||||
// Do not permit overwriting an existing ClientSource with the same
|
|
||||||
// UUID. This would allow a spoofed ClientParentSource actor to
|
|
||||||
// intercept postMessage() intended for the real actor.
|
|
||||||
if (NS_WARN_IF(entry.is<ClientSourceParent*>())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
FutureClientSourceParent& placeHolder =
|
|
||||||
entry.as<FutureClientSourceParent>();
|
|
||||||
|
|
||||||
if (NS_WARN_IF(!ClientMatchPrincipalInfo(
|
|
||||||
placeHolder.PrincipalInfo(), aSource->Info().PrincipalInfo()))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
placeHolder.ResolvePromiseIfExists(aSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = AsVariant(aSource);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
entry.OrInsert([&] { return aSource; });
|
||||||
|
|
||||||
return mSourceTable.add(entryPtr, id, AsVariant(aSource));
|
// Now that we've been created, notify any handles that were
|
||||||
|
// waiting on us.
|
||||||
|
auto* handles = mPendingHandles.GetValue(aSource->Info().Id());
|
||||||
|
if (handles) {
|
||||||
|
for (auto handle : *handles) {
|
||||||
|
handle->FoundSource(aSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mPendingHandles.Remove(aSource->Info().Id());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientManagerService::RemoveSource(ClientSourceParent* aSource) {
|
bool ClientManagerService::RemoveSource(ClientSourceParent* aSource) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(aSource);
|
MOZ_ASSERT(aSource);
|
||||||
|
auto entry = mSourceTable.Lookup(aSource->Info().Id());
|
||||||
auto entryPtr = mSourceTable.lookup(aSource->Info().Id());
|
if (NS_WARN_IF(!entry)) {
|
||||||
|
|
||||||
if (NS_WARN_IF(!entryPtr) ||
|
|
||||||
NS_WARN_IF(entryPtr->value().is<FutureClientSourceParent>())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
entry.Remove();
|
||||||
mSourceTable.remove(entryPtr);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientManagerService::ExpectFutureSource(
|
ClientSourceParent* ClientManagerService::FindSource(
|
||||||
const IPCClientInfo& aClientInfo) {
|
const nsID& aID, const PrincipalInfo& aPrincipalInfo) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
const nsID& id = aClientInfo.id();
|
auto entry = mSourceTable.Lookup(aID);
|
||||||
auto entryPtr = mSourceTable.lookupForAdd(id);
|
if (!entry) {
|
||||||
|
return nullptr;
|
||||||
// Prevent overwrites.
|
|
||||||
if (NS_WARN_IF(static_cast<bool>(entryPtr))) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mSourceTable.add(
|
ClientSourceParent* source = entry.Data();
|
||||||
entryPtr, id,
|
|
||||||
SourceTableEntry(VariantIndex<0>(),
|
|
||||||
FutureClientSourceParent(aClientInfo)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientManagerService::ForgetFutureSource(
|
|
||||||
const IPCClientInfo& aClientInfo) {
|
|
||||||
AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
auto entryPtr = mSourceTable.lookup(aClientInfo.id());
|
|
||||||
|
|
||||||
if (entryPtr) {
|
|
||||||
SourceTableEntry& entry = entryPtr->value();
|
|
||||||
|
|
||||||
if (NS_WARN_IF(entry.is<ClientSourceParent*>())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.as<FutureClientSourceParent>().RejectPromiseIfExists(
|
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mSourceTable.remove(entryPtr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<SourcePromise> ClientManagerService::FindSource(
|
|
||||||
const nsID& aID, const PrincipalInfo& aPrincipalInfo) const {
|
|
||||||
AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
auto entryPtr = mSourceTable.lookup(aID);
|
|
||||||
|
|
||||||
if (!entryPtr) {
|
|
||||||
return SourcePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceTableEntry& entry = entryPtr->value();
|
|
||||||
|
|
||||||
if (entry.is<FutureClientSourceParent>()) {
|
|
||||||
return entry.as<FutureClientSourceParent>().Promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientSourceParent* source = entry.as<ClientSourceParent*>();
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(source);
|
|
||||||
|
|
||||||
if (source->IsFrozen() ||
|
if (source->IsFrozen() ||
|
||||||
NS_WARN_IF(!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(),
|
|
||||||
aPrincipalInfo))) {
|
|
||||||
return SourcePromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
|
||||||
__func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SourcePromise::CreateAndResolve(source, __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ClientSourceParent* MaybeUnwrapAsExistingSource(
|
|
||||||
const ClientManagerService::SourceTableEntry& aEntry) {
|
|
||||||
AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
if (aEntry.is<ClientManagerService::FutureClientSourceParent>()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aEntry.as<ClientSourceParent*>());
|
|
||||||
return aEntry.as<ClientSourceParent*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientSourceParent* ClientManagerService::FindExistingSource(
|
|
||||||
const nsID& aID, const PrincipalInfo& aPrincipalInfo) const {
|
|
||||||
AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
auto entryPtr = mSourceTable.lookup(aID);
|
|
||||||
|
|
||||||
if (!entryPtr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientSourceParent* source = MaybeUnwrapAsExistingSource(entryPtr->value());
|
|
||||||
|
|
||||||
if (!source || source->IsFrozen() ||
|
|
||||||
!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(),
|
!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(),
|
||||||
aPrincipalInfo)) {
|
aPrincipalInfo)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -346,6 +242,20 @@ ClientSourceParent* ClientManagerService::FindExistingSource(
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientManagerService::WaitForSource(ClientHandleParent* aHandle,
|
||||||
|
const nsID& aID) {
|
||||||
|
auto& entry = mPendingHandles.GetOrInsert(aID);
|
||||||
|
entry.AppendElement(aHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientManagerService::StopWaitingForSource(ClientHandleParent* aHandle,
|
||||||
|
const nsID& aID) {
|
||||||
|
auto* entry = mPendingHandles.GetValue(aID);
|
||||||
|
if (entry) {
|
||||||
|
entry->RemoveElement(aHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClientManagerService::AddManager(ClientManagerParent* aManager) {
|
void ClientManagerService::AddManager(ClientManagerParent* aManager) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aManager);
|
MOZ_DIAGNOSTIC_ASSERT(aManager);
|
||||||
@ -368,7 +278,7 @@ void ClientManagerService::RemoveManager(ClientManagerParent* aManager) {
|
|||||||
RefPtr<ClientOpPromise> ClientManagerService::Navigate(
|
RefPtr<ClientOpPromise> ClientManagerService::Navigate(
|
||||||
const ClientNavigateArgs& aArgs) {
|
const ClientNavigateArgs& aArgs) {
|
||||||
ClientSourceParent* source =
|
ClientSourceParent* source =
|
||||||
FindExistingSource(aArgs.target().id(), aArgs.target().principalInfo());
|
FindSource(aArgs.target().id(), aArgs.target().principalInfo());
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
return ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||||
}
|
}
|
||||||
@ -475,11 +385,11 @@ RefPtr<ClientOpPromise> ClientManagerService::MatchAll(
|
|||||||
|
|
||||||
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
|
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
|
||||||
|
|
||||||
for (auto iter = mSourceTable.iter(); !iter.done(); iter.next()) {
|
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
|
||||||
ClientSourceParent* source =
|
ClientSourceParent* source = iter.UserData();
|
||||||
MaybeUnwrapAsExistingSource(iter.get().value());
|
MOZ_DIAGNOSTIC_ASSERT(source);
|
||||||
|
|
||||||
if (!source || source->IsFrozen() || !source->ExecutionReady()) {
|
if (source->IsFrozen() || !source->ExecutionReady()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,11 +467,11 @@ RefPtr<ClientOpPromise> ClientManagerService::Claim(
|
|||||||
|
|
||||||
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
|
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
|
||||||
|
|
||||||
for (auto iter = mSourceTable.iter(); !iter.done(); iter.next()) {
|
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
|
||||||
ClientSourceParent* source =
|
ClientSourceParent* source = iter.UserData();
|
||||||
MaybeUnwrapAsExistingSource(iter.get().value());
|
MOZ_DIAGNOSTIC_ASSERT(source);
|
||||||
|
|
||||||
if (!source || source->IsFrozen()) {
|
if (source->IsFrozen()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,8 +513,7 @@ RefPtr<ClientOpPromise> ClientManagerService::Claim(
|
|||||||
|
|
||||||
RefPtr<ClientOpPromise> ClientManagerService::GetInfoAndState(
|
RefPtr<ClientOpPromise> ClientManagerService::GetInfoAndState(
|
||||||
const ClientGetInfoAndStateArgs& aArgs) {
|
const ClientGetInfoAndStateArgs& aArgs) {
|
||||||
ClientSourceParent* source =
|
ClientSourceParent* source = FindSource(aArgs.id(), aArgs.principalInfo());
|
||||||
FindExistingSource(aArgs.id(), aArgs.principalInfo());
|
|
||||||
|
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
return ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||||
@ -616,10 +525,9 @@ RefPtr<ClientOpPromise> ClientManagerService::GetInfoAndState(
|
|||||||
// rejection ultimately converted to `undefined` in Clients::Get
|
// rejection ultimately converted to `undefined` in Clients::Get
|
||||||
return source->ExecutionReadyPromise()->Then(
|
return source->ExecutionReadyPromise()->Then(
|
||||||
GetCurrentThreadSerialEventTarget(), __func__,
|
GetCurrentThreadSerialEventTarget(), __func__,
|
||||||
[self = std::move(self), aArgs] {
|
[self, aArgs]() -> RefPtr<ClientOpPromise> {
|
||||||
// Execution ready implies the source had registered itself.
|
|
||||||
ClientSourceParent* source =
|
ClientSourceParent* source =
|
||||||
self->FindExistingSource(aArgs.id(), aArgs.principalInfo());
|
self->FindSource(aArgs.id(), aArgs.principalInfo());
|
||||||
|
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
return ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||||
@ -732,7 +640,7 @@ bool ClientManagerService::HasWindow(
|
|||||||
const PrincipalInfo& aPrincipalInfo, const nsID& aClientId) {
|
const PrincipalInfo& aPrincipalInfo, const nsID& aClientId) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
ClientSourceParent* source = FindExistingSource(aClientId, aPrincipalInfo);
|
ClientSourceParent* source = FindSource(aClientId, aPrincipalInfo);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,6 @@
|
|||||||
#define _mozilla_dom_ClientManagerService_h
|
#define _mozilla_dom_ClientManagerService_h
|
||||||
|
|
||||||
#include "ClientOpPromise.h"
|
#include "ClientOpPromise.h"
|
||||||
#include "mozilla/HashTable.h"
|
|
||||||
#include "mozilla/MozPromise.h"
|
|
||||||
#include "mozilla/Variant.h"
|
|
||||||
#include "mozilla/dom/ipc/IdType.h"
|
|
||||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@ -27,14 +22,29 @@ namespace dom {
|
|||||||
class ClientManagerParent;
|
class ClientManagerParent;
|
||||||
class ClientSourceParent;
|
class ClientSourceParent;
|
||||||
class ClientHandleParent;
|
class ClientHandleParent;
|
||||||
|
class ContentParent;
|
||||||
typedef MozPromise<ClientSourceParent*, nsresult, /* IsExclusive = */ false>
|
|
||||||
SourcePromise;
|
|
||||||
|
|
||||||
// Define a singleton service to manage client activity throughout the
|
// Define a singleton service to manage client activity throughout the
|
||||||
// browser. This service runs on the PBackground thread. To interact
|
// browser. This service runs on the PBackground thread. To interact
|
||||||
// it with it please use the ClientManager and ClientHandle classes.
|
// it with it please use the ClientManager and ClientHandle classes.
|
||||||
class ClientManagerService final {
|
class ClientManagerService final {
|
||||||
|
// Store the ClientSourceParent objects in a hash table. We want to
|
||||||
|
// optimize for insertion, removal, and lookup by UUID.
|
||||||
|
nsDataHashtable<nsIDHashKey, ClientSourceParent*> mSourceTable;
|
||||||
|
|
||||||
|
// The set of handles waiting for their corresponding ClientSourceParent
|
||||||
|
// to be created.
|
||||||
|
nsDataHashtable<nsIDHashKey, nsTArray<ClientHandleParent*>> mPendingHandles;
|
||||||
|
|
||||||
|
nsTArray<ClientManagerParent*> mManagerList;
|
||||||
|
|
||||||
|
bool mShutdown;
|
||||||
|
|
||||||
|
ClientManagerService();
|
||||||
|
~ClientManagerService();
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static already_AddRefed<ClientManagerService> GetOrCreateInstance();
|
static already_AddRefed<ClientManagerService> GetOrCreateInstance();
|
||||||
|
|
||||||
@ -45,18 +55,14 @@ class ClientManagerService final {
|
|||||||
|
|
||||||
bool RemoveSource(ClientSourceParent* aSource);
|
bool RemoveSource(ClientSourceParent* aSource);
|
||||||
|
|
||||||
bool ExpectFutureSource(const IPCClientInfo& aClientInfo);
|
ClientSourceParent* FindSource(
|
||||||
|
const nsID& aID, const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||||
|
|
||||||
bool ForgetFutureSource(const IPCClientInfo& aClientInfo);
|
// Called when a ClientHandle is created before the corresponding
|
||||||
|
// ClientSource. Will call FoundSource on the ClientHandleParent when it
|
||||||
// The returned promise rejects if:
|
// becomes available.
|
||||||
// - the corresponding `ClientSourceParent` has already removed itself from
|
void WaitForSource(ClientHandleParent* aHandle, const nsID& aID);
|
||||||
// the `ClientManagerService` (i.e. the corresponding `ClientSource` has been
|
void StopWaitingForSource(ClientHandleParent* aHandle, const nsID& aID);
|
||||||
// detroyed) or if
|
|
||||||
// - it's known that the corresponding `ClientSourceParent` will not exist
|
|
||||||
// (i.e. the corresponding `ClientSource` will not be created).
|
|
||||||
RefPtr<SourcePromise> FindSource(
|
|
||||||
const nsID& aID, const mozilla::ipc::PrincipalInfo& aPrincipalInfo) const;
|
|
||||||
|
|
||||||
void AddManager(ClientManagerParent* aManager);
|
void AddManager(ClientManagerParent* aManager);
|
||||||
|
|
||||||
@ -80,71 +86,6 @@ class ClientManagerService final {
|
|||||||
const nsID& aClientId);
|
const nsID& aClientId);
|
||||||
|
|
||||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManagerService)
|
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManagerService)
|
||||||
|
|
||||||
private:
|
|
||||||
ClientManagerService();
|
|
||||||
~ClientManagerService();
|
|
||||||
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
// Returns `nullptr` if the `ClientSourceParent*` doesn't exist.
|
|
||||||
ClientSourceParent* FindExistingSource(
|
|
||||||
const nsID& aID, const mozilla::ipc::PrincipalInfo& aPrincipalInfo) const;
|
|
||||||
|
|
||||||
// Represents a `ClientSourceParent` that may possibly be created and add
|
|
||||||
// itself in the future.
|
|
||||||
class FutureClientSourceParent {
|
|
||||||
public:
|
|
||||||
explicit FutureClientSourceParent(const IPCClientInfo& aClientInfo);
|
|
||||||
|
|
||||||
const mozilla::ipc::PrincipalInfo& PrincipalInfo() const {
|
|
||||||
return mPrincipalInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<SourcePromise> Promise() {
|
|
||||||
return mPromiseHolder.Ensure(__func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolvePromiseIfExists(ClientSourceParent* aSource) {
|
|
||||||
mPromiseHolder.ResolveIfExists(aSource, __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RejectPromiseIfExists(nsresult aRv) {
|
|
||||||
mPromiseHolder.RejectIfExists(aRv, __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const mozilla::ipc::PrincipalInfo mPrincipalInfo;
|
|
||||||
MozPromiseHolder<SourcePromise> mPromiseHolder;
|
|
||||||
};
|
|
||||||
|
|
||||||
using SourceTableEntry =
|
|
||||||
Variant<FutureClientSourceParent, ClientSourceParent*>;
|
|
||||||
|
|
||||||
// Returns `nullptr` if `aEntry` isn't a `ClientSourceParent*`.
|
|
||||||
friend inline ClientSourceParent* MaybeUnwrapAsExistingSource(
|
|
||||||
const SourceTableEntry& aEntry);
|
|
||||||
|
|
||||||
struct nsIDHasher {
|
|
||||||
using Key = nsID;
|
|
||||||
using Lookup = Key;
|
|
||||||
|
|
||||||
static HashNumber hash(const Lookup& aLookup) {
|
|
||||||
return HashBytes(&aLookup, sizeof(Lookup));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool match(const Key& aKey, const Lookup& aLookup) {
|
|
||||||
return aKey.Equals(aLookup);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store the possible ClientSourceParent objects in a hash table. We want to
|
|
||||||
// optimize for insertion, removal, and lookup by UUID.
|
|
||||||
HashMap<nsID, SourceTableEntry, nsIDHasher> mSourceTable;
|
|
||||||
|
|
||||||
nsTArray<ClientManagerParent*> mManagerList;
|
|
||||||
|
|
||||||
bool mShutdown;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -32,9 +32,6 @@ parent:
|
|||||||
async PClientManagerOp(ClientOpConstructorArgs aArgs);
|
async PClientManagerOp(ClientOpConstructorArgs aArgs);
|
||||||
async PClientSource(ClientSourceConstructorArgs aArgs);
|
async PClientSource(ClientSourceConstructorArgs aArgs);
|
||||||
|
|
||||||
async ExpectOrForgetFutureClientSource(bool aExpect,
|
|
||||||
IPCClientInfo aClientInfo);
|
|
||||||
|
|
||||||
child:
|
child:
|
||||||
async PClientNavigateOp(ClientNavigateOpConstructorArgs aArgs);
|
async PClientNavigateOp(ClientNavigateOpConstructorArgs aArgs);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user