зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1231213 - Refactor RemoteWorkerController to handle Service Workers' and Shared Workers' operations. r=asuth
Differential Revision: https://phabricator.services.mozilla.com/D26169 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
07c822e09b
Коммит
81d15b2970
|
@ -11,6 +11,7 @@ with Files("**"):
|
||||||
EXPORTS.mozilla.dom += [
|
EXPORTS.mozilla.dom += [
|
||||||
'ServiceWorker.h',
|
'ServiceWorker.h',
|
||||||
'ServiceWorkerActors.h',
|
'ServiceWorkerActors.h',
|
||||||
|
'ServiceWorkerCloneData.h',
|
||||||
'ServiceWorkerContainer.h',
|
'ServiceWorkerContainer.h',
|
||||||
'ServiceWorkerDescriptor.h',
|
'ServiceWorkerDescriptor.h',
|
||||||
'ServiceWorkerEvents.h',
|
'ServiceWorkerEvents.h',
|
||||||
|
|
|
@ -4,11 +4,20 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/dom/MessagePort.h"
|
#include "RemoteWorkerController.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "nsDebug.h"
|
||||||
|
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "mozilla/DebugOnly.h"
|
||||||
|
#include "mozilla/ScopeExit.h"
|
||||||
#include "mozilla/dom/MessagePortParent.h"
|
#include "mozilla/dom/MessagePortParent.h"
|
||||||
#include "mozilla/dom/RemoteWorkerTypes.h"
|
#include "mozilla/dom/RemoteWorkerTypes.h"
|
||||||
|
#include "mozilla/dom/ServiceWorkerCloneData.h"
|
||||||
#include "mozilla/ipc/BackgroundParent.h"
|
#include "mozilla/ipc/BackgroundParent.h"
|
||||||
#include "RemoteWorkerController.h"
|
#include "RemoteWorkerControllerParent.h"
|
||||||
#include "RemoteWorkerManager.h"
|
#include "RemoteWorkerManager.h"
|
||||||
#include "RemoteWorkerParent.h"
|
#include "RemoteWorkerParent.h"
|
||||||
|
|
||||||
|
@ -22,8 +31,8 @@ namespace dom {
|
||||||
already_AddRefed<RemoteWorkerController> RemoteWorkerController::Create(
|
already_AddRefed<RemoteWorkerController> RemoteWorkerController::Create(
|
||||||
const RemoteWorkerData& aData, RemoteWorkerObserver* aObserver,
|
const RemoteWorkerData& aData, RemoteWorkerObserver* aObserver,
|
||||||
base::ProcessId aProcessId) {
|
base::ProcessId aProcessId) {
|
||||||
|
AssertIsInMainProcess();
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(aObserver);
|
MOZ_ASSERT(aObserver);
|
||||||
|
|
||||||
RefPtr<RemoteWorkerController> controller =
|
RefPtr<RemoteWorkerController> controller =
|
||||||
|
@ -45,23 +54,36 @@ RemoteWorkerController::RemoteWorkerController(const RemoteWorkerData& aData,
|
||||||
OptionalServiceWorkerData::TServiceWorkerData) {
|
OptionalServiceWorkerData::TServiceWorkerData) {
|
||||||
AssertIsInMainProcess();
|
AssertIsInMainProcess();
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteWorkerController::~RemoteWorkerController() {
|
RemoteWorkerController::~RemoteWorkerController() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_DIAGNOSTIC_ASSERT(mPendingOps.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::SetWorkerActor(RemoteWorkerParent* aActor) {
|
void RemoteWorkerController::SetWorkerActor(RemoteWorkerParent* aActor) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(!mActor);
|
MOZ_ASSERT(!mActor);
|
||||||
MOZ_ASSERT(aActor);
|
MOZ_ASSERT(aActor);
|
||||||
|
|
||||||
mActor = aActor;
|
mActor = aActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteWorkerController::NoteDeadWorkerActor() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
|
||||||
|
// The actor has been destroyed without a proper close() notification. Let's
|
||||||
|
// inform the observer.
|
||||||
|
if (mState == eReady) {
|
||||||
|
mObserver->Terminated();
|
||||||
|
}
|
||||||
|
|
||||||
|
mActor = nullptr;
|
||||||
|
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::CreationFailed() {
|
void RemoteWorkerController::CreationFailed() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
@ -74,13 +96,13 @@ void RemoteWorkerController::CreationFailed() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shutdown();
|
NoteDeadWorker();
|
||||||
|
|
||||||
mObserver->CreationFailed();
|
mObserver->CreationFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::CreationSucceeded() {
|
void RemoteWorkerController::CreationSucceeded() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(mState == ePending || mState == eTerminated);
|
MOZ_ASSERT(mState == ePending || mState == eTerminated);
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
if (mState == eTerminated) {
|
||||||
|
@ -95,238 +117,301 @@ void RemoteWorkerController::CreationSucceeded() {
|
||||||
|
|
||||||
mObserver->CreationSucceeded();
|
mObserver->CreationSucceeded();
|
||||||
|
|
||||||
for (UniquePtr<Op>& op : mPendingOps) {
|
auto pendingOps = std::move(mPendingOps);
|
||||||
switch (op->mType) {
|
|
||||||
case Op::eTerminate:
|
|
||||||
Terminate();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Op::eSuspend:
|
for (auto& op : pendingOps) {
|
||||||
Suspend();
|
DebugOnly<bool> started = op->MaybeStart(this);
|
||||||
break;
|
MOZ_ASSERT(started);
|
||||||
|
|
||||||
case Op::eResume:
|
|
||||||
Resume();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Op::eFreeze:
|
|
||||||
Freeze();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Op::eThaw:
|
|
||||||
Thaw();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Op::ePortIdentifier:
|
|
||||||
AddPortIdentifier(op->mPortIdentifier);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Op::eAddWindowID:
|
|
||||||
AddWindowID(op->mWindowID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Op::eRemoveWindowID:
|
|
||||||
RemoveWindowID(op->mWindowID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Unknown op.");
|
|
||||||
}
|
|
||||||
|
|
||||||
op->Completed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mPendingOps.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::ErrorPropagation(const ErrorValue& aValue) {
|
void RemoteWorkerController::ErrorPropagation(const ErrorValue& aValue) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
mObserver->ErrorReceived(aValue);
|
mObserver->ErrorReceived(aValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::WorkerTerminated() {
|
void RemoteWorkerController::WorkerTerminated() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
NoteDeadWorker();
|
||||||
|
|
||||||
mObserver->Terminated();
|
mObserver->Terminated();
|
||||||
Shutdown();
|
}
|
||||||
|
|
||||||
|
void RemoteWorkerController::CancelAllPendingOps() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
auto pendingOps = std::move(mPendingOps);
|
||||||
|
|
||||||
|
for (auto& op : pendingOps) {
|
||||||
|
op->Cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::Shutdown() {
|
void RemoteWorkerController::Shutdown() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
Unused << NS_WARN_IF(mIsServiceWorker && !mPendingOps.IsEmpty());
|
||||||
MOZ_ASSERT(mState == ePending || mState == eReady);
|
|
||||||
|
if (mState == eTerminated) {
|
||||||
|
MOZ_ASSERT(mPendingOps.IsEmpty());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mState = eTerminated;
|
mState = eTerminated;
|
||||||
|
|
||||||
mPendingOps.Clear();
|
CancelAllPendingOps();
|
||||||
|
|
||||||
if (mActor) {
|
if (!mActor) {
|
||||||
mActor->SetController(nullptr);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mActor->SetController(nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "non-remote-side" of the Service Worker will have ensured that the
|
||||||
|
* remote worker is terminated before calling `Shutdown().`
|
||||||
|
*/
|
||||||
|
if (mIsServiceWorker) {
|
||||||
|
mActor->MaybeSendDelete();
|
||||||
|
} else {
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerTerminateOp());
|
Unused << mActor->SendExecOp(RemoteWorkerTerminateOp());
|
||||||
mActor = nullptr;
|
}
|
||||||
|
|
||||||
|
mActor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWorkerController::NoteDeadWorker() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
CancelAllPendingOps();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "non-remote-side" of the Service Worker will initiate `Shutdown()`
|
||||||
|
* once it's notified that all dispatched operations have either completed
|
||||||
|
* or canceled. That is, it'll explicitly call `Shutdown()` later.
|
||||||
|
*/
|
||||||
|
if (!mIsServiceWorker) {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void RemoteWorkerController::MaybeStartSharedWorkerOp(Args&&... aArgs) {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(!mIsServiceWorker);
|
||||||
|
|
||||||
|
UniquePtr<PendingSharedWorkerOp> op =
|
||||||
|
MakeUnique<PendingSharedWorkerOp>(std::forward<Args>(aArgs)...);
|
||||||
|
|
||||||
|
if (!op->MaybeStart(this)) {
|
||||||
|
mPendingOps.AppendElement(std::move(op));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::AddWindowID(uint64_t aWindowID) {
|
void RemoteWorkerController::AddWindowID(uint64_t aWindowID) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(aWindowID);
|
MOZ_ASSERT(aWindowID);
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eAddWindowID, aWindowID);
|
||||||
mPendingOps.AppendElement(new Op(Op::eAddWindowID, aWindowID));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerAddWindowIDOp(aWindowID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::RemoveWindowID(uint64_t aWindowID) {
|
void RemoteWorkerController::RemoveWindowID(uint64_t aWindowID) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(aWindowID);
|
MOZ_ASSERT(aWindowID);
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eRemoveWindowID, aWindowID);
|
||||||
mPendingOps.AppendElement(new Op(Op::eRemoveWindowID, aWindowID));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerRemoveWindowIDOp(aWindowID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::AddPortIdentifier(
|
void RemoteWorkerController::AddPortIdentifier(
|
||||||
const MessagePortIdentifier& aPortIdentifier) {
|
const MessagePortIdentifier& aPortIdentifier) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(aPortIdentifier);
|
||||||
mPendingOps.AppendElement(new Op(aPortIdentifier));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerPortIdentifierOp(aPortIdentifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteWorkerController::ForgetActorAndTerminate() {
|
|
||||||
AssertIsOnBackgroundThread();
|
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
// The actor has been destroyed without a proper close() notification. Let's
|
|
||||||
// inform the observer.
|
|
||||||
if (mState == eReady) {
|
|
||||||
mObserver->Terminated();
|
|
||||||
}
|
|
||||||
|
|
||||||
mActor = nullptr;
|
|
||||||
Terminate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::Terminate() {
|
void RemoteWorkerController::Terminate() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eTerminate);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::Suspend() {
|
void RemoteWorkerController::Suspend() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eSuspend);
|
||||||
mPendingOps.AppendElement(new Op(Op::eSuspend));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerSuspendOp());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::Resume() {
|
void RemoteWorkerController::Resume() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eResume);
|
||||||
mPendingOps.AppendElement(new Op(Op::eResume));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerResumeOp());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::Freeze() {
|
void RemoteWorkerController::Freeze() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eFreeze);
|
||||||
mPendingOps.AppendElement(new Op(Op::eFreeze));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerFreezeOp());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteWorkerController::Thaw() {
|
void RemoteWorkerController::Thaw() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
|
|
||||||
if (mState == ePending) {
|
MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eThaw);
|
||||||
mPendingOps.AppendElement(new Op(Op::eThaw));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState == eTerminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == eReady);
|
|
||||||
Unused << mActor->SendExecOp(RemoteWorkerThawOp());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteWorkerController::Op::~Op() {
|
RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
|
||||||
MOZ_COUNT_DTOR(Op);
|
Type aType, uint64_t aWindowID)
|
||||||
|
: mType(aType), mWindowID(aWindowID) {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
|
||||||
|
const MessagePortIdentifier& aPortIdentifier)
|
||||||
|
: mType(ePortIdentifier), mPortIdentifier(aPortIdentifier) {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteWorkerController::PendingSharedWorkerOp::~PendingSharedWorkerOp() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoteWorkerController::PendingSharedWorkerOp::MaybeStart(
|
||||||
|
RemoteWorkerController* const aOwner) {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(!mCompleted);
|
||||||
|
MOZ_ASSERT(aOwner);
|
||||||
|
|
||||||
|
if (aOwner->mState == RemoteWorkerController::eTerminated) {
|
||||||
|
Cancel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aOwner->mState == RemoteWorkerController::ePending &&
|
||||||
|
mType != eTerminate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mType) {
|
||||||
|
case eTerminate:
|
||||||
|
aOwner->Shutdown();
|
||||||
|
break;
|
||||||
|
case eSuspend:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(RemoteWorkerSuspendOp());
|
||||||
|
break;
|
||||||
|
case eResume:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(RemoteWorkerResumeOp());
|
||||||
|
break;
|
||||||
|
case eFreeze:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(RemoteWorkerFreezeOp());
|
||||||
|
break;
|
||||||
|
case eThaw:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(RemoteWorkerThawOp());
|
||||||
|
break;
|
||||||
|
case ePortIdentifier:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(
|
||||||
|
RemoteWorkerPortIdentifierOp(mPortIdentifier));
|
||||||
|
break;
|
||||||
|
case eAddWindowID:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(
|
||||||
|
RemoteWorkerAddWindowIDOp(mWindowID));
|
||||||
|
break;
|
||||||
|
case eRemoveWindowID:
|
||||||
|
Unused << aOwner->mActor->SendExecOp(
|
||||||
|
RemoteWorkerRemoveWindowIDOp(mWindowID));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_CRASH("Unknown op.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mCompleted = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWorkerController::PendingSharedWorkerOp::Cancel() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(!mCompleted);
|
||||||
|
|
||||||
// We don't want to leak the port if the operation has not been processed.
|
// We don't want to leak the port if the operation has not been processed.
|
||||||
if (!mCompleted && mType == ePortIdentifier) {
|
if (mType == ePortIdentifier) {
|
||||||
MessagePortParent::ForceClose(mPortIdentifier.uuid(),
|
MessagePortParent::ForceClose(mPortIdentifier.uuid(),
|
||||||
mPortIdentifier.destinationUuid(),
|
mPortIdentifier.destinationUuid(),
|
||||||
mPortIdentifier.sequenceId());
|
mPortIdentifier.sequenceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteWorkerController::PendingServiceWorkerOp::PendingServiceWorkerOp(
|
||||||
|
ServiceWorkerOpArgs&& aArgs,
|
||||||
|
RefPtr<ServiceWorkerOpPromise::Private> aPromise)
|
||||||
|
: mArgs(std::move(aArgs)), mPromise(std::move(aPromise)) {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(mPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteWorkerController::PendingServiceWorkerOp::~PendingServiceWorkerOp() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!mPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoteWorkerController::PendingServiceWorkerOp::MaybeStart(
|
||||||
|
RemoteWorkerController* const aOwner) {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(mPromise);
|
||||||
|
MOZ_ASSERT(aOwner);
|
||||||
|
|
||||||
|
if (NS_WARN_IF(aOwner->mState == RemoteWorkerController::eTerminated)) {
|
||||||
|
mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
|
||||||
|
mPromise = nullptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The target content process must still be starting up.
|
||||||
|
if (!aOwner->mActor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow termination operations to pass through while pending because the
|
||||||
|
* remote Service Worker can be terminated while still starting up.
|
||||||
|
*/
|
||||||
|
if (aOwner->mState == RemoteWorkerController::ePending &&
|
||||||
|
mArgs.type() !=
|
||||||
|
ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mArgs.type() == ServiceWorkerOpArgs::TServiceWorkerMessageEventOpArgs) {
|
||||||
|
auto& args = mArgs.get_ServiceWorkerMessageEventOpArgs();
|
||||||
|
|
||||||
|
ServiceWorkerMessageEventOpArgs copyArgs;
|
||||||
|
copyArgs.clientInfoAndState() = std::move(args.clientInfoAndState());
|
||||||
|
|
||||||
|
RefPtr<ServiceWorkerCloneData> copyData = new ServiceWorkerCloneData();
|
||||||
|
copyData->StealFromClonedMessageDataForBackgroundParent(args.clonedData());
|
||||||
|
|
||||||
|
if (!copyData->BuildClonedMessageDataForBackgroundParent(
|
||||||
|
aOwner->mActor->Manager(), copyArgs.clonedData())) {
|
||||||
|
mPromise->Reject(NS_ERROR_DOM_DATA_CLONE_ERR, __func__);
|
||||||
|
mPromise = nullptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mArgs = std::move(copyArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWorkerController::PendingServiceWorkerOp::Cancel() {
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
MOZ_ASSERT(mPromise);
|
||||||
|
|
||||||
|
mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
|
||||||
|
mPromise = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
#define mozilla_dom_RemoteWorkerController_h
|
#define mozilla_dom_RemoteWorkerController_h
|
||||||
|
|
||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
#include "mozilla/RefPtr.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
#include "mozilla/dom/DOMTypes.h"
|
||||||
|
#include "mozilla/dom/ServiceWorkerOpArgs.h"
|
||||||
|
#include "mozilla/dom/ServiceWorkerOpPromise.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
@ -79,7 +86,6 @@ namespace dom {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ErrorValue;
|
class ErrorValue;
|
||||||
class MessagePortIdentifier;
|
|
||||||
class RemoteWorkerControllerParent;
|
class RemoteWorkerControllerParent;
|
||||||
class RemoteWorkerData;
|
class RemoteWorkerData;
|
||||||
class RemoteWorkerManager;
|
class RemoteWorkerManager;
|
||||||
|
@ -134,18 +140,25 @@ class RemoteWorkerController final {
|
||||||
|
|
||||||
void SetWorkerActor(RemoteWorkerParent* aActor);
|
void SetWorkerActor(RemoteWorkerParent* aActor);
|
||||||
|
|
||||||
|
void NoteDeadWorkerActor();
|
||||||
|
|
||||||
void ErrorPropagation(const ErrorValue& aValue);
|
void ErrorPropagation(const ErrorValue& aValue);
|
||||||
|
|
||||||
void WorkerTerminated();
|
void WorkerTerminated();
|
||||||
|
|
||||||
void ForgetActorAndTerminate();
|
|
||||||
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void CreationFailed();
|
void CreationFailed();
|
||||||
|
|
||||||
void CreationSucceeded();
|
void CreationSucceeded();
|
||||||
|
|
||||||
|
void CancelAllPendingOps();
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void MaybeStartSharedWorkerOp(Args&&... aArgs);
|
||||||
|
|
||||||
|
void NoteDeadWorker();
|
||||||
|
|
||||||
RefPtr<RemoteWorkerObserver> mObserver;
|
RefPtr<RemoteWorkerObserver> mObserver;
|
||||||
RefPtr<RemoteWorkerParent> mActor;
|
RefPtr<RemoteWorkerParent> mActor;
|
||||||
|
|
||||||
|
@ -157,7 +170,33 @@ class RemoteWorkerController final {
|
||||||
|
|
||||||
const bool mIsServiceWorker;
|
const bool mIsServiceWorker;
|
||||||
|
|
||||||
struct Op {
|
/**
|
||||||
|
* `PendingOp` is responsible for encapsulating logic for starting and
|
||||||
|
* canceling pending remote worker operations, as this logic may vary
|
||||||
|
* depending on the type of the remote worker and the type of the operation.
|
||||||
|
*/
|
||||||
|
class PendingOp {
|
||||||
|
public:
|
||||||
|
PendingOp() = default;
|
||||||
|
|
||||||
|
PendingOp(const PendingOp&) = delete;
|
||||||
|
|
||||||
|
PendingOp& operator=(const PendingOp&) = delete;
|
||||||
|
|
||||||
|
virtual ~PendingOp() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if execution has started and `false` otherwise.
|
||||||
|
*
|
||||||
|
* Starting execution may depend the state of `aOwner.`
|
||||||
|
*/
|
||||||
|
virtual bool MaybeStart(RemoteWorkerController* const aOwner) = 0;
|
||||||
|
|
||||||
|
virtual void Cancel() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PendingSharedWorkerOp final : public PendingOp {
|
||||||
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
eTerminate,
|
eTerminate,
|
||||||
eSuspend,
|
eSuspend,
|
||||||
|
@ -169,34 +208,41 @@ class RemoteWorkerController final {
|
||||||
eRemoveWindowID,
|
eRemoveWindowID,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Op(Type aType, uint64_t aWindowID = 0)
|
explicit PendingSharedWorkerOp(Type aType, uint64_t aWindowID = 0);
|
||||||
: mType(aType), mWindowID(aWindowID), mCompleted(false) {
|
|
||||||
MOZ_COUNT_CTOR(Op);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Op(const MessagePortIdentifier& aPortIdentifier)
|
explicit PendingSharedWorkerOp(
|
||||||
: mType(ePortIdentifier),
|
const MessagePortIdentifier& aPortIdentifier);
|
||||||
mPortIdentifier(aPortIdentifier),
|
|
||||||
mCompleted(false) {
|
|
||||||
MOZ_COUNT_CTOR(Op);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This object cannot be copied.
|
~PendingSharedWorkerOp();
|
||||||
Op(Op const&) = delete;
|
|
||||||
Op& operator=(Op const&) = delete;
|
|
||||||
|
|
||||||
~Op();
|
bool MaybeStart(RemoteWorkerController* const aOwner) override;
|
||||||
|
|
||||||
void Completed() { mCompleted = true; }
|
void Cancel() override;
|
||||||
|
|
||||||
Type mType;
|
private:
|
||||||
|
const Type mType;
|
||||||
MessagePortIdentifier mPortIdentifier;
|
const MessagePortIdentifier mPortIdentifier;
|
||||||
uint64_t mWindowID;
|
const uint64_t mWindowID = 0;
|
||||||
bool mCompleted;
|
bool mCompleted = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
nsTArray<UniquePtr<Op>> mPendingOps;
|
class PendingServiceWorkerOp final : public PendingOp {
|
||||||
|
public:
|
||||||
|
PendingServiceWorkerOp(ServiceWorkerOpArgs&& aArgs,
|
||||||
|
RefPtr<ServiceWorkerOpPromise::Private> aPromise);
|
||||||
|
|
||||||
|
~PendingServiceWorkerOp();
|
||||||
|
|
||||||
|
bool MaybeStart(RemoteWorkerController* const aOwner) override;
|
||||||
|
|
||||||
|
void Cancel() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ServiceWorkerOpArgs mArgs;
|
||||||
|
RefPtr<ServiceWorkerOpPromise::Private> mPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
nsTArray<UniquePtr<PendingOp>> mPendingOps;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -84,7 +84,7 @@ void RemoteWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mController) {
|
if (mController) {
|
||||||
mController->ForgetActorAndTerminate();
|
mController->NoteDeadWorkerActor();
|
||||||
mController = nullptr;
|
mController = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,17 @@ IPCResult RemoteWorkerParent::RecvError(const ErrorValue& aValue) {
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteWorkerParent::MaybeSendDelete() {
|
||||||
|
if (mDeleteSent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For some reason, if the following two lines are swapped, ASan says there's
|
||||||
|
// a UAF...
|
||||||
|
mDeleteSent = true;
|
||||||
|
Unused << Send__delete__(this);
|
||||||
|
}
|
||||||
|
|
||||||
IPCResult RemoteWorkerParent::RecvClose() {
|
IPCResult RemoteWorkerParent::RecvClose() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
|
|
@ -26,6 +26,8 @@ class RemoteWorkerParent final : public PRemoteWorkerParent {
|
||||||
|
|
||||||
void SetController(RemoteWorkerController* aController);
|
void SetController(RemoteWorkerController* aController);
|
||||||
|
|
||||||
|
void MaybeSendDelete();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~RemoteWorkerParent();
|
~RemoteWorkerParent();
|
||||||
|
|
||||||
|
@ -37,6 +39,7 @@ class RemoteWorkerParent final : public PRemoteWorkerParent {
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvCreated(const bool& aStatus);
|
mozilla::ipc::IPCResult RecvCreated(const bool& aStatus);
|
||||||
|
|
||||||
|
bool mDeleteSent = false;
|
||||||
RefPtr<RemoteWorkerController> mController;
|
RefPtr<RemoteWorkerController> mController;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче