1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MessagePort.h"
9 #include "MessageEvent.h"
10 #include "MessagePortChild.h"
11 #include "mozilla/dom/BlobBinding.h"
12 #include "mozilla/dom/Event.h"
13 #include "mozilla/dom/File.h"
14 #include "mozilla/dom/MessageChannel.h"
15 #include "mozilla/dom/MessageEventBinding.h"
16 #include "mozilla/dom/MessagePortBinding.h"
17 #include "mozilla/dom/MessagePortChild.h"
18 #include "mozilla/dom/PMessagePort.h"
19 #include "mozilla/dom/RootedDictionary.h"
20 #include "mozilla/dom/ScriptSettings.h"
21 #include "mozilla/dom/StructuredCloneTags.h"
22 #include "mozilla/dom/WorkerCommon.h"
23 #include "mozilla/dom/WorkerRef.h"
24 #include "mozilla/dom/WorkerScope.h"
25 #include "mozilla/ipc/BackgroundChild.h"
26 #include "mozilla/dom/RefMessageBodyService.h"
27 #include "mozilla/dom/SharedMessageBody.h"
28 #include "mozilla/ipc/PBackgroundChild.h"
29 #include "mozilla/MessagePortTimelineMarker.h"
30 #include "mozilla/ScopeExit.h"
31 #include "mozilla/TimelineConsumers.h"
32 #include "mozilla/TimelineMarker.h"
33 #include "mozilla/Unused.h"
34 #include "nsContentUtils.h"
35 #include "nsGlobalWindow.h"
36 #include "nsPresContext.h"
42 namespace mozilla::dom
{
44 void UniqueMessagePortId::ForceClose() {
45 if (!mIdentifier
.neutered()) {
46 MessagePort::ForceClose(mIdentifier
);
47 mIdentifier
.neutered() = true;
51 class PostMessageRunnable final
: public CancelableRunnable
{
52 friend class MessagePort
;
55 PostMessageRunnable(MessagePort
* aPort
, SharedMessageBody
* aData
)
56 : CancelableRunnable("dom::PostMessageRunnable"),
65 NS_ASSERT_OWNINGTHREAD(Runnable
);
67 // The port can be cycle collected while this runnable is pending in
73 MOZ_ASSERT(mPort
->mPostMessageRunnable
== this);
77 // We must check if we were waiting for this message in order to shutdown
79 mPort
->UpdateMustKeepAlive();
81 mPort
->mPostMessageRunnable
= nullptr;
87 nsresult
Cancel() override
{
88 NS_ASSERT_OWNINGTHREAD(Runnable
);
96 void DispatchMessage() const {
97 NS_ASSERT_OWNINGTHREAD(Runnable
);
99 if (NS_FAILED(mPort
->CheckCurrentGlobalCorrectness())) {
103 nsCOMPtr
<nsIGlobalObject
> globalObject
= mPort
->GetParentObject();
106 if (!globalObject
|| !jsapi
.Init(globalObject
)) {
107 NS_WARNING("Failed to initialize AutoJSAPI object.");
111 JSContext
* cx
= jsapi
.cx();
113 IgnoredErrorResult rv
;
114 JS::Rooted
<JS::Value
> value(cx
);
116 UniquePtr
<AbstractTimelineMarker
> start
;
117 UniquePtr
<AbstractTimelineMarker
> end
;
118 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
119 bool isTimelineRecording
= timelines
&& !timelines
->IsEmpty();
121 if (isTimelineRecording
) {
122 start
= MakeUnique
<MessagePortTimelineMarker
>(
123 ProfileTimelineMessagePortOperationType::DeserializeData
,
124 MarkerTracingType::START
);
127 mData
->Read(cx
, &value
, mPort
->mRefMessageBodyService
,
128 SharedMessageBody::ReadMethod::StealRefMessageBody
, rv
);
130 if (isTimelineRecording
) {
131 end
= MakeUnique
<MessagePortTimelineMarker
>(
132 ProfileTimelineMessagePortOperationType::DeserializeData
,
133 MarkerTracingType::END
);
134 timelines
->AddMarkerForAllObservedDocShells(start
);
135 timelines
->AddMarkerForAllObservedDocShells(end
);
138 if (NS_WARN_IF(rv
.Failed())) {
139 JS_ClearPendingException(cx
);
140 mPort
->DispatchError();
145 nsCOMPtr
<mozilla::dom::EventTarget
> eventTarget
=
146 do_QueryInterface(mPort
->GetOwner());
147 RefPtr
<MessageEvent
> event
=
148 new MessageEvent(eventTarget
, nullptr, nullptr);
150 Sequence
<OwningNonNull
<MessagePort
>> ports
;
151 if (!mData
->TakeTransferredPortsAsSequence(ports
)) {
152 mPort
->DispatchError();
156 event
->InitMessageEvent(nullptr, u
"message"_ns
, CanBubble::eNo
,
157 Cancelable::eNo
, value
, u
""_ns
, u
""_ns
, nullptr,
159 event
->SetTrusted(true);
161 mPort
->DispatchEvent(*event
);
165 ~PostMessageRunnable() = default;
167 RefPtr
<MessagePort
> mPort
;
168 RefPtr
<SharedMessageBody
> mData
;
171 NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort
)
173 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort
,
174 DOMEventTargetHelper
)
175 if (tmp
->mPostMessageRunnable
) {
176 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPostMessageRunnable
->mPort
);
179 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort
);
182 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort
,
185 DOMEventTargetHelper
)
186 if (tmp
->mPostMessageRunnable
) {
187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPostMessageRunnable
->mPort
);
190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort
);
191 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
193 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePort
)
194 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
196 NS_IMPL_ADDREF_INHERITED(MessagePort
, DOMEventTargetHelper
)
197 NS_IMPL_RELEASE_INHERITED(MessagePort
, DOMEventTargetHelper
)
199 MessagePort::MessagePort(nsIGlobalObject
* aGlobal
, State aState
)
200 : DOMEventTargetHelper(aGlobal
),
201 mRefMessageBodyService(RefMessageBodyService::GetOrCreate()),
203 mMessageQueueEnabled(false),
205 mHasBeenTransferredOrClosed(false) {
208 mIdentifier
= MakeUnique
<MessagePortIdentifier
>();
209 mIdentifier
->neutered() = true;
210 mIdentifier
->sequenceId() = 0;
213 MessagePort::~MessagePort() {
215 MOZ_ASSERT(!mWorkerRef
);
219 already_AddRefed
<MessagePort
> MessagePort::Create(nsIGlobalObject
* aGlobal
,
221 const nsID
& aDestinationUUID
,
225 RefPtr
<MessagePort
> mp
= new MessagePort(aGlobal
, eStateUnshippedEntangled
);
226 mp
->Initialize(aUUID
, aDestinationUUID
, 1 /* 0 is an invalid sequence ID */,
227 false /* Neutered */, aRv
);
232 already_AddRefed
<MessagePort
> MessagePort::Create(
233 nsIGlobalObject
* aGlobal
, UniqueMessagePortId
& aIdentifier
,
237 RefPtr
<MessagePort
> mp
= new MessagePort(aGlobal
, eStateEntangling
);
238 mp
->Initialize(aIdentifier
.uuid(), aIdentifier
.destinationUuid(),
239 aIdentifier
.sequenceId(), aIdentifier
.neutered(), aRv
);
240 aIdentifier
.neutered() = true;
244 void MessagePort::UnshippedEntangle(MessagePort
* aEntangledPort
) {
245 MOZ_DIAGNOSTIC_ASSERT(aEntangledPort
);
246 MOZ_DIAGNOSTIC_ASSERT(!mUnshippedEntangledPort
);
248 mUnshippedEntangledPort
= aEntangledPort
;
251 void MessagePort::Initialize(const nsID
& aUUID
, const nsID
& aDestinationUUID
,
252 uint32_t aSequenceID
, bool aNeutered
,
254 MOZ_ASSERT(mIdentifier
);
255 mIdentifier
->uuid() = aUUID
;
256 mIdentifier
->destinationUuid() = aDestinationUUID
;
257 mIdentifier
->sequenceId() = aSequenceID
;
260 // If this port is neutered we don't want to keep it alive artificially nor
261 // we want to add listeners or WorkerRefs.
262 mState
= eStateDisentangled
;
266 if (mState
== eStateEntangling
) {
267 if (!ConnectToPBackground()) {
268 aRv
.Throw(NS_ERROR_FAILURE
);
272 MOZ_ASSERT(mState
== eStateUnshippedEntangled
);
275 // The port has to keep itself alive until it's entangled.
276 UpdateMustKeepAlive();
278 if (WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate()) {
279 RefPtr
<MessagePort
> self
= this;
281 // When the callback is executed, we cannot process messages anymore because
282 // we cannot dispatch new runnables. Let's force a Close().
283 RefPtr
<StrongWorkerRef
> strongWorkerRef
= StrongWorkerRef::Create(
284 workerPrivate
, "MessagePort", [self
]() { self
->CloseForced(); });
285 if (NS_WARN_IF(!strongWorkerRef
)) {
286 // The worker is shutting down.
287 mState
= eStateDisentangled
;
288 UpdateMustKeepAlive();
289 aRv
.Throw(NS_ERROR_FAILURE
);
293 MOZ_ASSERT(!mWorkerRef
);
294 mWorkerRef
= std::move(strongWorkerRef
);
298 JSObject
* MessagePort::WrapObject(JSContext
* aCx
,
299 JS::Handle
<JSObject
*> aGivenProto
) {
300 return MessagePort_Binding::Wrap(aCx
, this, aGivenProto
);
303 void MessagePort::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
304 const Sequence
<JSObject
*>& aTransferable
,
306 // We *must* clone the data here, or the JS::Value could be modified
309 // Here we want to check if the transerable object list contains
311 for (uint32_t i
= 0; i
< aTransferable
.Length(); ++i
) {
312 JS::Rooted
<JSObject
*> object(aCx
, aTransferable
[i
]);
317 MessagePort
* port
= nullptr;
318 nsresult rv
= UNWRAP_OBJECT(MessagePort
, &object
, port
);
319 if (NS_SUCCEEDED(rv
) && port
== this) {
320 aRv
.Throw(NS_ERROR_DOM_DATA_CLONE_ERR
);
325 JS::Rooted
<JS::Value
> transferable(aCx
, JS::UndefinedValue());
327 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransferable
,
329 if (NS_WARN_IF(aRv
.Failed())) {
333 Maybe
<nsID
> agentClusterId
;
334 nsCOMPtr
<nsIGlobalObject
> global
= GetOwnerGlobal();
336 agentClusterId
= global
->GetAgentClusterId();
339 RefPtr
<SharedMessageBody
> data
= new SharedMessageBody(
340 StructuredCloneHolder::TransferringSupported
, agentClusterId
);
342 UniquePtr
<AbstractTimelineMarker
> start
;
343 UniquePtr
<AbstractTimelineMarker
> end
;
344 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
345 bool isTimelineRecording
= timelines
&& !timelines
->IsEmpty();
347 if (isTimelineRecording
) {
348 start
= MakeUnique
<MessagePortTimelineMarker
>(
349 ProfileTimelineMessagePortOperationType::SerializeData
,
350 MarkerTracingType::START
);
353 data
->Write(aCx
, aMessage
, transferable
, mIdentifier
->uuid(),
354 mRefMessageBodyService
, aRv
);
356 if (isTimelineRecording
) {
357 end
= MakeUnique
<MessagePortTimelineMarker
>(
358 ProfileTimelineMessagePortOperationType::SerializeData
,
359 MarkerTracingType::END
);
360 timelines
->AddMarkerForAllObservedDocShells(start
);
361 timelines
->AddMarkerForAllObservedDocShells(end
);
364 if (NS_WARN_IF(aRv
.Failed())) {
368 // This message has to be ignored.
369 if (mState
> eStateEntangled
) {
373 // If we are unshipped we are connected to the other port on the same thread.
374 if (mState
== eStateUnshippedEntangled
) {
375 MOZ_DIAGNOSTIC_ASSERT(mUnshippedEntangledPort
);
376 mUnshippedEntangledPort
->mMessages
.AppendElement(data
);
377 mUnshippedEntangledPort
->Dispatch();
381 // Not entangled yet, but already closed/disentangled.
382 if (mState
== eStateEntanglingForDisentangle
||
383 mState
== eStateEntanglingForClose
) {
387 RemoveDocFromBFCache();
389 // Not entangled yet.
390 if (mState
== eStateEntangling
) {
391 mMessagesForTheOtherPort
.AppendElement(data
);
396 MOZ_ASSERT(mMessagesForTheOtherPort
.IsEmpty());
398 AutoTArray
<RefPtr
<SharedMessageBody
>, 1> array
;
399 array
.AppendElement(data
);
401 AutoTArray
<MessageData
, 1> messages
;
402 // note: `messages` will borrow the underlying buffer, but this is okay
403 // because reverse destruction order means `messages` will be destroyed prior
404 // to `array`/`data`.
405 SharedMessageBody::FromSharedToMessagesChild(mActor
->Manager(), array
,
407 mActor
->SendPostMessages(messages
);
410 void MessagePort::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
411 const StructuredSerializeOptions
& aOptions
,
413 PostMessage(aCx
, aMessage
, aOptions
.mTransfer
, aRv
);
416 void MessagePort::Start() {
417 if (mMessageQueueEnabled
) {
421 mMessageQueueEnabled
= true;
425 void MessagePort::Dispatch() {
426 if (!mMessageQueueEnabled
|| mMessages
.IsEmpty() || mPostMessageRunnable
) {
431 case eStateUnshippedEntangled
:
432 // Everything is fine here. We have messages because the other
433 // port populates our queue directly.
436 case eStateEntangling
:
437 // Everything is fine here as well. We have messages because the other
438 // port populated our queue directly when we were in the
439 // eStateUnshippedEntangled state.
442 case eStateEntanglingForDisentangle
:
443 // Here we don't want to ship messages because these messages must be
444 // delivered by the cloned version of this one. They will be sent in the
445 // SendDisentangle().
448 case eStateEntanglingForClose
:
449 // We still want to deliver messages if we are closing. These messages
450 // are here from the previous eStateUnshippedEntangled state.
453 case eStateEntangled
:
454 // This port is up and running.
457 case eStateDisentangling
:
458 // If we are in the process to disentangle the port, we cannot dispatch
459 // messages. They will be sent to the cloned version of this port via
460 // SendDisentangle();
463 case eStateDisentangled
:
464 MOZ_CRASH("This cannot happen.");
465 // It cannot happen because Disentangle should take off all the pending
469 case eStateDisentangledForClose
:
470 // If we are here is because the port has been closed. We can still
471 // process the pending messages.
475 RefPtr
<SharedMessageBody
> data
= mMessages
.ElementAt(0);
476 mMessages
.RemoveElementAt(0);
478 mPostMessageRunnable
= new PostMessageRunnable(this, data
);
480 nsCOMPtr
<nsIGlobalObject
> global
= GetOwnerGlobal();
481 if (NS_IsMainThread() && global
) {
483 global
->Dispatch(TaskCategory::Other
, do_AddRef(mPostMessageRunnable
)));
487 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(mPostMessageRunnable
));
490 void MessagePort::Close() {
491 mHasBeenTransferredOrClosed
= true;
492 CloseInternal(true /* aSoftly */);
495 void MessagePort::CloseForced() { CloseInternal(false /* aSoftly */); }
497 void MessagePort::CloseInternal(bool aSoftly
) {
498 // If we have some messages to send but we don't want a 'soft' close, we have
499 // to flush them now.
504 // Let's inform the RefMessageBodyService that any our shared messages are
506 mRefMessageBodyService
->ForgetPort(mIdentifier
->uuid());
508 if (mState
== eStateUnshippedEntangled
) {
509 MOZ_DIAGNOSTIC_ASSERT(mUnshippedEntangledPort
);
511 // This avoids loops.
512 RefPtr
<MessagePort
> port
= std::move(mUnshippedEntangledPort
);
514 mState
= eStateDisentangledForClose
;
515 port
->CloseInternal(aSoftly
);
517 UpdateMustKeepAlive();
521 // Not entangled yet, we have to wait.
522 if (mState
== eStateEntangling
) {
523 mState
= eStateEntanglingForClose
;
527 // Not entangled but already cloned or closed
528 if (mState
== eStateEntanglingForDisentangle
||
529 mState
== eStateEntanglingForClose
) {
533 // Maybe we were already closing the port but softly. In this case we call
534 // UpdateMustKeepAlive() to consider the empty pending message queue.
535 if (mState
== eStateDisentangledForClose
&& !aSoftly
) {
536 UpdateMustKeepAlive();
540 if (mState
> eStateEntangled
) {
544 // We don't care about stopping the sending of messages because from now all
545 // the incoming messages will be ignored.
546 mState
= eStateDisentangledForClose
;
551 mActor
->SetPort(nullptr);
554 UpdateMustKeepAlive();
557 EventHandlerNonNull
* MessagePort::GetOnmessage() {
558 return GetEventHandler(nsGkAtoms::onmessage
);
561 void MessagePort::SetOnmessage(EventHandlerNonNull
* aCallback
) {
562 SetEventHandler(nsGkAtoms::onmessage
, aCallback
);
564 // When using onmessage, the call to start() is implied.
568 // This method is called when the PMessagePortChild actor is entangled to
569 // another actor. It receives a list of messages to be dispatch. It can be that
570 // we were waiting for this entangling step in order to disentangle the port or
572 void MessagePort::Entangled(nsTArray
<MessageData
>& aMessages
) {
573 MOZ_ASSERT(mState
== eStateEntangling
||
574 mState
== eStateEntanglingForDisentangle
||
575 mState
== eStateEntanglingForClose
);
577 State oldState
= mState
;
578 mState
= eStateEntangled
;
580 // If we have pending messages, these have to be sent.
581 if (!mMessagesForTheOtherPort
.IsEmpty()) {
583 nsTArray
<MessageData
> messages
;
584 SharedMessageBody::FromSharedToMessagesChild(
585 mActor
->Manager(), mMessagesForTheOtherPort
, messages
);
586 mActor
->SendPostMessages(messages
);
588 // Because `messages` borrow the underlying JSStructuredCloneData buffers,
589 // only clear after `messages` have gone out of scope.
590 mMessagesForTheOtherPort
.Clear();
593 // We must convert the messages into SharedMessageBodys to avoid leaks.
594 FallibleTArray
<RefPtr
<SharedMessageBody
>> data
;
596 !SharedMessageBody::FromMessagesToSharedChild(aMessages
, data
))) {
601 // If the next step is to close the port, we do it ignoring the received
603 if (oldState
== eStateEntanglingForClose
) {
608 mMessages
.AppendElements(data
);
610 // We were waiting for the entangling callback in order to disentangle this
611 // port immediately after.
612 if (oldState
== eStateEntanglingForDisentangle
) {
613 StartDisentangling();
620 void MessagePort::StartDisentangling() {
622 MOZ_ASSERT(mState
== eStateEntangled
);
624 mState
= eStateDisentangling
;
626 // Sending this message we communicate to the parent actor that we don't want
627 // to receive any new messages. It is possible that a message has been
628 // already sent but not received yet. So we have to collect all of them and
629 // we send them in the SendDispatch() request.
630 mActor
->SendStopSendingData();
633 void MessagePort::MessagesReceived(nsTArray
<MessageData
>& aMessages
) {
634 MOZ_ASSERT(mState
== eStateEntangled
|| mState
== eStateDisentangling
||
635 // This last step can happen only if Close() has been called
636 // manually. At this point SendClose() is sent but we can still
637 // receive something until the Closing request is processed.
638 mState
== eStateDisentangledForClose
);
639 MOZ_ASSERT(mMessagesForTheOtherPort
.IsEmpty());
641 RemoveDocFromBFCache();
643 FallibleTArray
<RefPtr
<SharedMessageBody
>> data
;
645 !SharedMessageBody::FromMessagesToSharedChild(aMessages
, data
))) {
650 mMessages
.AppendElements(data
);
652 if (mState
== eStateEntangled
) {
657 void MessagePort::StopSendingDataConfirmed() {
658 MOZ_ASSERT(mState
== eStateDisentangling
);
664 void MessagePort::Disentangle() {
665 MOZ_ASSERT(mState
== eStateDisentangling
);
668 mState
= eStateDisentangled
;
671 nsTArray
<MessageData
> messages
;
672 SharedMessageBody::FromSharedToMessagesChild(mActor
->Manager(), mMessages
,
674 mActor
->SendDisentangle(messages
);
677 // Let's inform the RefMessageBodyService that any our shared messages are
679 mRefMessageBodyService
->ForgetPort(mIdentifier
->uuid());
681 // Only clear mMessages after the MessageData instances have gone out of scope
682 // because they borrow mMessages' underlying JSStructuredCloneDatas.
685 mActor
->SetPort(nullptr);
688 UpdateMustKeepAlive();
691 void MessagePort::CloneAndDisentangle(UniqueMessagePortId
& aIdentifier
) {
692 MOZ_ASSERT(mIdentifier
);
693 MOZ_ASSERT(!mHasBeenTransferredOrClosed
);
695 mHasBeenTransferredOrClosed
= true;
697 // We can clone a port that has already been transfered. In this case, on the
698 // otherside will have a neutered port. Here we set neutered to true so that
699 // we are safe in case a early return.
700 aIdentifier
.neutered() = true;
702 if (mState
> eStateEntangled
) {
706 // We already have a 'next step'. We have to consider this port as already
707 // cloned/closed/disentangled.
708 if (mState
== eStateEntanglingForDisentangle
||
709 mState
== eStateEntanglingForClose
) {
713 aIdentifier
.uuid() = mIdentifier
->uuid();
714 aIdentifier
.destinationUuid() = mIdentifier
->destinationUuid();
715 aIdentifier
.sequenceId() = mIdentifier
->sequenceId() + 1;
716 aIdentifier
.neutered() = false;
718 // We have to entangle first.
719 if (mState
== eStateUnshippedEntangled
) {
720 MOZ_ASSERT(mUnshippedEntangledPort
);
721 MOZ_ASSERT(mMessagesForTheOtherPort
.IsEmpty());
723 RefPtr
<MessagePort
> port
= std::move(mUnshippedEntangledPort
);
725 // Disconnect the entangled port and connect it to PBackground.
726 if (!port
->ConnectToPBackground()) {
727 // We are probably shutting down. We cannot proceed.
728 mState
= eStateDisentangled
;
729 UpdateMustKeepAlive();
733 // In this case, we don't need to be connected to the PBackground service.
734 if (mMessages
.IsEmpty()) {
735 aIdentifier
.sequenceId() = mIdentifier
->sequenceId();
737 mState
= eStateDisentangled
;
738 UpdateMustKeepAlive();
742 // Register this component to PBackground.
743 if (!ConnectToPBackground()) {
744 // We are probably shutting down. We cannot proceed.
748 mState
= eStateEntanglingForDisentangle
;
752 // Not entangled yet, we have to wait.
753 if (mState
== eStateEntangling
) {
754 mState
= eStateEntanglingForDisentangle
;
758 MOZ_ASSERT(mState
== eStateEntangled
);
759 StartDisentangling();
762 void MessagePort::Closed() {
763 if (mState
>= eStateDisentangled
) {
767 mState
= eStateDisentangledForClose
;
770 mActor
->SetPort(nullptr);
774 UpdateMustKeepAlive();
777 bool MessagePort::ConnectToPBackground() {
778 RefPtr
<MessagePort
> self
= this;
779 auto raii
= MakeScopeExit([self
] {
780 self
->mState
= eStateDisentangled
;
781 self
->UpdateMustKeepAlive();
784 mozilla::ipc::PBackgroundChild
* actorChild
=
785 mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
786 if (NS_WARN_IF(!actorChild
)) {
790 PMessagePortChild
* actor
= actorChild
->SendPMessagePortConstructor(
791 mIdentifier
->uuid(), mIdentifier
->destinationUuid(),
792 mIdentifier
->sequenceId());
793 if (NS_WARN_IF(!actor
)) {
797 mActor
= static_cast<MessagePortChild
*>(actor
);
800 mActor
->SetPort(this);
801 mState
= eStateEntangling
;
807 void MessagePort::UpdateMustKeepAlive() {
808 if (mState
>= eStateDisentangled
&& mMessages
.IsEmpty() && mIsKeptAlive
) {
809 mIsKeptAlive
= false;
811 // The DTOR of this WorkerRef will release the worker for us.
812 mWorkerRef
= nullptr;
818 if (mState
< eStateDisentangled
&& !mIsKeptAlive
) {
824 void MessagePort::DisconnectFromOwner() {
826 DOMEventTargetHelper::DisconnectFromOwner();
829 void MessagePort::RemoveDocFromBFCache() {
830 if (!NS_IsMainThread()) {
834 if (nsPIDOMWindowInner
* window
= GetOwner()) {
835 window
->RemoveFromBFCacheSync();
840 void MessagePort::ForceClose(const MessagePortIdentifier
& aIdentifier
) {
841 mozilla::ipc::PBackgroundChild
* actorChild
=
842 mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
843 if (NS_WARN_IF(!actorChild
)) {
844 MOZ_CRASH("Failed to create a PBackgroundChild actor!");
847 Unused
<< actorChild
->SendMessagePortForceClose(aIdentifier
.uuid(),
848 aIdentifier
.destinationUuid(),
849 aIdentifier
.sequenceId());
852 void MessagePort::DispatchError() {
853 nsCOMPtr
<nsIGlobalObject
> globalObject
= GetParentObject();
856 if (!globalObject
|| !jsapi
.Init(globalObject
)) {
857 NS_WARNING("Failed to initialize AutoJSAPI object.");
861 RootedDictionary
<MessageEventInit
> init(jsapi
.cx());
862 init
.mBubbles
= false;
863 init
.mCancelable
= false;
865 RefPtr
<Event
> event
=
866 MessageEvent::Constructor(this, u
"messageerror"_ns
, init
);
867 event
->SetTrusted(true);
869 DispatchEvent(*event
);
872 } // namespace mozilla::dom