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 "BroadcastChannelService.h"
8 #include "BroadcastChannelParent.h"
9 #include "mozilla/dom/BlobImpl.h"
10 #include "mozilla/dom/File.h"
11 #include "mozilla/dom/IPCBlobUtils.h"
12 #include "mozilla/ipc/BackgroundParent.h"
26 BroadcastChannelService
* sInstance
= nullptr;
28 ClonedMessageData
CloneClonedMessageData(const ClonedMessageData
& aOther
) {
29 auto cloneData
= SerializedStructuredCloneBuffer
{};
30 cloneData
.data
.initScope(aOther
.data().data
.scope());
31 const bool res
= cloneData
.data
.Append(aOther
.data().data
);
32 MOZ_RELEASE_ASSERT(res
, "out of memory");
33 return {std::move(cloneData
), aOther
.blobs(), aOther
.inputStreams(),
34 aOther
.identifiers()};
37 MessageData
CloneMessageData(const MessageData
& aOther
) {
38 switch (aOther
.data().type()) {
39 case MessageDataType::TClonedMessageData
:
40 return {aOther
.agentClusterId(),
41 CloneClonedMessageData(aOther
.data().get_ClonedMessageData())};
42 case MessageDataType::TRefMessageData
:
43 return {aOther
.agentClusterId(), aOther
.data().get_RefMessageData()};
45 MOZ_CRASH("Unexpected MessageDataType type");
51 BroadcastChannelService::BroadcastChannelService() {
52 AssertIsOnBackgroundThread();
54 // sInstance is a raw BroadcastChannelService*.
55 MOZ_ASSERT(!sInstance
);
59 BroadcastChannelService::~BroadcastChannelService() {
60 AssertIsOnBackgroundThread();
61 MOZ_ASSERT(sInstance
== this);
62 MOZ_ASSERT(mAgents
.Count() == 0);
68 already_AddRefed
<BroadcastChannelService
>
69 BroadcastChannelService::GetOrCreate() {
70 AssertIsOnBackgroundThread();
72 RefPtr
<BroadcastChannelService
> instance
= sInstance
;
74 instance
= new BroadcastChannelService();
76 return instance
.forget();
79 void BroadcastChannelService::RegisterActor(
80 BroadcastChannelParent
* aParent
, const nsAString
& aOriginChannelKey
) {
81 AssertIsOnBackgroundThread();
84 auto* const parents
= mAgents
.GetOrInsertNew(aOriginChannelKey
);
86 MOZ_ASSERT(!parents
->Contains(aParent
));
87 parents
->AppendElement(aParent
);
90 void BroadcastChannelService::UnregisterActor(
91 BroadcastChannelParent
* aParent
, const nsAString
& aOriginChannelKey
) {
92 AssertIsOnBackgroundThread();
95 if (auto entry
= mAgents
.Lookup(aOriginChannelKey
)) {
96 entry
.Data()->RemoveElement(aParent
);
97 // remove the entry if the array is now empty
98 if (entry
.Data()->IsEmpty()) {
102 MOZ_CRASH("Invalid state");
106 void BroadcastChannelService::PostMessage(BroadcastChannelParent
* aParent
,
107 const MessageData
& aData
,
108 const nsAString
& aOriginChannelKey
) {
109 AssertIsOnBackgroundThread();
112 nsTArray
<BroadcastChannelParent
*>* parents
;
113 if (!mAgents
.Get(aOriginChannelKey
, &parents
)) {
114 MOZ_CRASH("Invalid state");
117 // We need to keep the array alive for the life-time of this operation.
118 nsTArray
<RefPtr
<BlobImpl
>> blobImpls
;
119 if (aData
.data().type() == MessageDataType::TClonedMessageData
) {
120 const nsTArray
<IPCBlob
>& blobs
=
121 aData
.data().get_ClonedMessageData().blobs();
122 if (!blobs
.IsEmpty()) {
123 blobImpls
.SetCapacity(blobs
.Length());
125 for (uint32_t i
= 0, len
= blobs
.Length(); i
< len
; ++i
) {
126 RefPtr
<BlobImpl
> impl
= IPCBlobUtils::Deserialize(blobs
[i
]);
129 blobImpls
.AppendElement(impl
);
134 uint32_t selectedActorsOnSamePid
= 0;
136 // For each parent actor, we notify the message.
137 for (uint32_t i
= 0; i
< parents
->Length(); ++i
) {
138 BroadcastChannelParent
* parent
= parents
->ElementAt(i
);
141 if (parent
== aParent
) {
145 if (parent
->OtherPid() == aParent
->OtherPid()) {
146 ++selectedActorsOnSamePid
;
149 // We need to have a copy of the data for this parent.
150 MessageData newData
= CloneMessageData(aData
);
151 MOZ_ASSERT(newData
.data().type() == aData
.data().type());
153 if (!blobImpls
.IsEmpty()) {
154 nsTArray
<IPCBlob
>& newBlobImpls
=
155 newData
.data().get_ClonedMessageData().blobs();
156 MOZ_ASSERT(blobImpls
.Length() == newBlobImpls
.Length());
158 // Serialize Blob objects for this message.
159 for (uint32_t i
= 0, len
= blobImpls
.Length(); i
< len
; ++i
) {
160 nsresult rv
= IPCBlobUtils::Serialize(blobImpls
[i
], parent
->Manager(),
162 if (NS_WARN_IF(NS_FAILED(rv
))) {
168 Unused
<< parent
->SendNotify(newData
);
171 // If this is a refMessageData, we need to know when it can be released.
172 if (aData
.data().type() == MessageDataType::TRefMessageData
) {
173 Unused
<< aParent
->SendRefMessageDelivered(
174 aData
.data().get_RefMessageData().uuid(), selectedActorsOnSamePid
);
179 } // namespace mozilla