Files
palemoon27/dom/broadcastchannel/BroadcastChannel.cpp
T
roytam1 8f529f64f5 import changes from rmottola/Arctic-Fox:
- Bug 932865 - Add ThreadHangStats for collecting background hang telemetry; r=vladan (2f08a076b)
- Bug 932865 - Add way for telemetry to iterate over active threads; r=froydnj (535615d3d)
- Bug 1128768: Part 3 - Update BHR to allow for hang annotations; r=vladan (0b880a667)
- Bug 935092 - Add ThreadStackHelper to get a thread's pesudo-stack; r=BenWa (1422cfe4d)
- Bug 942488 - Don't report pseudo-stacks without SPS profiler. r=nchen (e160a7a08)
- Bug 946817 - Don't assert mPseudoStack on B2G. r=BenWa (9f846df3b)
- Bug 951431 - Don't get stacks during profiler runs on Linux; r=BenWa (15036e907)
- Bug 978262 - Ignore duplicate frames when getting BHR stack. r=froydnj (964721b1b)
- Bug 985155 - Add signal trampoline on ARM Linux to work around kernel bug. r=snorp (cb8a7846c)
- Bug 995730 - Convert xpcom/threads/ to Gecko style. r=froydnj (fe150404e)
- Bug 1013326 - Distinguish chrome and content scripts in pseudostack; r=snorp (81273c977)
- Bug 1023461 - Remove temporary stack buffer in ThreadStackHelper; r=snorp (cf5a717c2)
- Bug 1023461 - Record filename and line number for chrome JS entries; r=snorp (10c89808f)
- Bug 1022456 - Fix modelines in xpcom/{base,glue,io,string,threads}/. (48dbc0416)
- Bug 1016441 - Switch to using real-time signal in ThreadStackHelper; (2c5f818be)
- Bug 1016629 - b. Use RAII class to assign mStackToFill; r=snorp (769eae130)
- Bug 1016629 - c. Add define for ThreadStackHelper pseudostack support; r=snorp (67def0d2f)
- Bug 1016629 - d. Add and implement GetNativeStack method in ThreadStackHelper; r=snorp r=jseward (46c52f2be)
- Bug 1016629 - e. Implement platform-specific code for filling in context; r=snorp r=jseward (e6a66858b)
- Bug 1016629 - g. Avoid ASan flag when copying stack; r=snorp (0159628b5)
- Bug 1045176 - Unbreak build on non-SPS platforms after bug 1016629. (f1d60d838)
- Bug 1047123 - ThreadStackHelper should use UniquePtr<uint8_t[]>, not ScopedDeleteArray. r=jchen (0e4af313c)
- Bug 1049161 - Fix ThreadStackHelper thread handle permissions on Windows; r=snorp (c05172b1c)
- Bug 1050185 - Make ThreadStackHelper::FillThreadContext Valgrind-friendly. r=nchen (368725774)
- Bug 1050440 - Remove repeated js::RunScript frames in ThreadStackHelper (2a79600b3)
- Bug 1046841 - Fix more style violations in previously touched .cpp files in xpcom/. r=froydnj (02afe2493)
- Bug 1069694 - Remove or move around functions in OldDebugAPI. r=shu (177197302)
- Bug 1069694 - Remove OldDebugAPI from the browser. r=shu (b8c917d42)
- Bug 1100911 - For MacOS builds running on Valgrind, make ThreadStackHelper::GetStack be a no-op. r=nchen. (d99c02e16)
- Bug 1091758 - Report full paths for most chrome scripts; r=snorp (2b72e7878)
- Bug 1109291 - Include better paths for hanging chrome scripts in profile extensions directory; r=snorp r=bsmedberg (1997b9532)
- Bug 1113416 - Don't read stack labels inside hang monitor sighandler; r=nfroyd r=snorp (9688f6069)
- bug 1146027 - more final r=froydnj (7b0f295e5)
- Bug 1164090 - Check for Windows path separator in BHR file name; r=snorp (f014b4d78)
- Bug 1169034 - include <cstdlib> in ThreadStackHelper.cpp to declare correct overload for std::abs; r=jseward (874d4447e)
- Bug 1182996 - Fix and add missing namespace comments. rs=ehsan (054fc00b2)
- Bug 932865 - Collect thread hang stats in BackgroundHangMonitor; (ac80c8e9f)
- minor anticipated fixes to get it compiling (2bd701d15)
2020-02-01 08:07:15 +08:00

796 lines
19 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
#include "BroadcastChannel.h"
#include "BroadcastChannelChild.h"
#include "mozilla/dom/BroadcastChannelBinding.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/Preferences.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "nsIAppsService.h"
#include "nsIDocument.h"
#include "nsIScriptSecurityManager.h"
#include "nsServiceManagerUtils.h"
#include "nsISupportsPrimitives.h"
#ifdef XP_WIN
#undef PostMessage
#endif
namespace mozilla {
using namespace ipc;
namespace dom {
using namespace workers;
class BroadcastChannelMessage final
{
public:
NS_INLINE_DECL_REFCOUNTING(BroadcastChannelMessage)
JSAutoStructuredCloneBuffer mBuffer;
StructuredCloneClosure mClosure;
BroadcastChannelMessage()
{ }
private:
~BroadcastChannelMessage()
{ }
};
namespace {
void
GetOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin, ErrorResult& aRv)
{
MOZ_ASSERT(aPrincipal);
uint16_t appStatus = aPrincipal->GetAppStatus();
if (appStatus == nsIPrincipal::APP_STATUS_NOT_INSTALLED) {
nsAutoString tmp;
aRv = nsContentUtils::GetUTFOrigin(aPrincipal, tmp);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
aOrigin = tmp;
if (aOrigin.EqualsASCII("null")) {
nsCOMPtr<nsIURI> uri;
aRv = aPrincipal->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (NS_WARN_IF(!uri)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsAutoCString spec;
aRv = uri->GetSpec(spec);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
aOrigin = NS_ConvertUTF8toUTF16(spec);
}
return;
}
uint32_t appId = aPrincipal->GetAppId();
// If we are in "app code", use manifest URL as unique origin since
// multiple apps can share the same origin but not same broadcast messages.
nsresult rv;
nsCOMPtr<nsIAppsService> appsService =
do_GetService("@mozilla.org/AppsService;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
appsService->GetManifestURLByLocalId(appId, aOrigin);
}
nsIPrincipal*
GetPrincipalFromWorkerPrivate(WorkerPrivate* aWorkerPrivate)
{
nsIPrincipal* principal = aWorkerPrivate->GetPrincipal();
if (principal) {
return principal;
}
// Walk up to our containing page
WorkerPrivate* wp = aWorkerPrivate;
while (wp->GetParent()) {
wp = wp->GetParent();
}
return wp->GetPrincipal();
}
class InitializeRunnable final : public WorkerMainThreadRunnable
{
public:
InitializeRunnable(WorkerPrivate* aWorkerPrivate, nsAString& aOrigin,
PrincipalInfo& aPrincipalInfo, bool& aPrivateBrowsing,
ErrorResult& aRv)
: WorkerMainThreadRunnable(aWorkerPrivate)
, mWorkerPrivate(GetCurrentThreadWorkerPrivate())
, mOrigin(aOrigin)
, mPrincipalInfo(aPrincipalInfo)
, mPrivateBrowsing(aPrivateBrowsing)
, mRv(aRv)
{
MOZ_ASSERT(mWorkerPrivate);
}
bool MainThreadRun() override
{
MOZ_ASSERT(NS_IsMainThread());
nsIPrincipal* principal = GetPrincipalFromWorkerPrivate(mWorkerPrivate);
if (!principal) {
mRv.Throw(NS_ERROR_FAILURE);
return true;
}
bool isNullPrincipal;
mRv = principal->GetIsNullPrincipal(&isNullPrincipal);
if (NS_WARN_IF(mRv.Failed())) {
return true;
}
if (NS_WARN_IF(isNullPrincipal)) {
mRv.Throw(NS_ERROR_FAILURE);
return true;
}
mRv = PrincipalToPrincipalInfo(principal, &mPrincipalInfo);
if (NS_WARN_IF(mRv.Failed())) {
return true;
}
GetOrigin(principal, mOrigin, mRv);
if (NS_WARN_IF(mRv.Failed())) {
return true;
}
// Walk up to our containing page
WorkerPrivate* wp = mWorkerPrivate;
while (wp->GetParent()) {
wp = wp->GetParent();
}
// Window doesn't exist for some kind of workers (eg: SharedWorkers)
nsPIDOMWindow* window = wp->GetWindow();
if (!window) {
return true;
}
nsIDocument* doc = window->GetExtantDoc();
if (doc) {
mPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
// No bfcache when BroadcastChannel is used.
doc->DisallowBFCaching();
}
return true;
}
private:
WorkerPrivate* mWorkerPrivate;
nsAString& mOrigin;
PrincipalInfo& mPrincipalInfo;
bool& mPrivateBrowsing;
ErrorResult& mRv;
};
class BCPostMessageRunnable final : public nsICancelableRunnable
{
public:
NS_DECL_ISUPPORTS
BCPostMessageRunnable(BroadcastChannelChild* aActor,
BroadcastChannelMessage* aData)
: mActor(aActor)
, mData(aData)
{
MOZ_ASSERT(mActor);
}
NS_IMETHODIMP Run() override
{
MOZ_ASSERT(mActor);
if (mActor->IsActorDestroyed()) {
return NS_OK;
}
ClonedMessageData message;
SerializedStructuredCloneBuffer& buffer = message.data();
buffer.data = mData->mBuffer.data();
buffer.dataLength = mData->mBuffer.nbytes();
PBackgroundChild* backgroundManager = mActor->Manager();
MOZ_ASSERT(backgroundManager);
const nsTArray<nsRefPtr<File>>& blobs = mData->mClosure.mBlobs;
if (!blobs.IsEmpty()) {
message.blobsChild().SetCapacity(blobs.Length());
for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
PBlobChild* blobChild =
BackgroundChild::GetOrCreateActorForBlob(backgroundManager, blobs[i]);
MOZ_ASSERT(blobChild);
message.blobsChild().AppendElement(blobChild);
}
}
mActor->SendPostMessage(message);
return NS_OK;
}
NS_IMETHODIMP Cancel() override
{
mActor = nullptr;
return NS_OK;
}
private:
~BCPostMessageRunnable() {}
nsRefPtr<BroadcastChannelChild> mActor;
nsRefPtr<BroadcastChannelMessage> mData;
};
NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable)
class CloseRunnable final : public nsICancelableRunnable
{
public:
NS_DECL_ISUPPORTS
explicit CloseRunnable(BroadcastChannel* aBC)
: mBC(aBC)
{
MOZ_ASSERT(mBC);
}
NS_IMETHODIMP Run() override
{
mBC->Shutdown();
return NS_OK;
}
NS_IMETHODIMP Cancel() override
{
mBC = nullptr;
return NS_OK;
}
private:
~CloseRunnable() {}
nsRefPtr<BroadcastChannel> mBC;
};
NS_IMPL_ISUPPORTS(CloseRunnable, nsICancelableRunnable, nsIRunnable)
class TeardownRunnable final : public nsICancelableRunnable
{
public:
NS_DECL_ISUPPORTS
explicit TeardownRunnable(BroadcastChannelChild* aActor)
: mActor(aActor)
{
MOZ_ASSERT(mActor);
}
NS_IMETHODIMP Run() override
{
MOZ_ASSERT(mActor);
if (!mActor->IsActorDestroyed()) {
mActor->SendClose();
}
return NS_OK;
}
NS_IMETHODIMP Cancel() override
{
mActor = nullptr;
return NS_OK;
}
private:
~TeardownRunnable() {}
nsRefPtr<BroadcastChannelChild> mActor;
};
NS_IMPL_ISUPPORTS(TeardownRunnable, nsICancelableRunnable, nsIRunnable)
class BroadcastChannelFeature final : public workers::WorkerFeature
{
BroadcastChannel* mChannel;
public:
explicit BroadcastChannelFeature(BroadcastChannel* aChannel)
: mChannel(aChannel)
{
MOZ_COUNT_CTOR(BroadcastChannelFeature);
}
virtual bool Notify(JSContext* aCx, workers::Status aStatus) override
{
if (aStatus >= Closing) {
mChannel->Shutdown();
}
return true;
}
private:
~BroadcastChannelFeature()
{
MOZ_COUNT_DTOR(BroadcastChannelFeature);
}
};
class PrefEnabledRunnable final : public WorkerMainThreadRunnable
{
public:
explicit PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
: WorkerMainThreadRunnable(aWorkerPrivate)
, mEnabled(false)
{ }
bool MainThreadRun() override
{
AssertIsOnMainThread();
mEnabled = Preferences::GetBool("dom.broadcastChannel.enabled", false);
return true;
}
bool IsEnabled() const
{
return mEnabled;
}
private:
bool mEnabled;
};
} // namespace
/* static */ bool
BroadcastChannel::IsEnabled(JSContext* aCx, JSObject* aGlobal)
{
if (NS_IsMainThread()) {
return Preferences::GetBool("dom.broadcastChannel.enabled", false);
}
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsRefPtr<PrefEnabledRunnable> runnable =
new PrefEnabledRunnable(workerPrivate);
runnable->Dispatch(workerPrivate->GetJSContext());
return runnable->IsEnabled();
}
BroadcastChannel::BroadcastChannel(nsPIDOMWindow* aWindow,
const PrincipalInfo& aPrincipalInfo,
const nsAString& aOrigin,
const nsAString& aChannel,
bool aPrivateBrowsing)
: DOMEventTargetHelper(aWindow)
, mWorkerFeature(nullptr)
, mPrincipalInfo(new PrincipalInfo(aPrincipalInfo))
, mOrigin(aOrigin)
, mChannel(aChannel)
, mPrivateBrowsing(aPrivateBrowsing)
, mIsKeptAlive(false)
, mInnerID(0)
, mState(StateActive)
{
// Window can be null in workers
}
BroadcastChannel::~BroadcastChannel()
{
Shutdown();
MOZ_ASSERT(!mWorkerFeature);
}
JSObject*
BroadcastChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return BroadcastChannelBinding::Wrap(aCx, this, aGivenProto);
}
/* static */ already_AddRefed<BroadcastChannel>
BroadcastChannel::Constructor(const GlobalObject& aGlobal,
const nsAString& aChannel,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
// Window is null in workers.
nsAutoString origin;
PrincipalInfo principalInfo;
bool privateBrowsing = false;
WorkerPrivate* workerPrivate = nullptr;
if (NS_IsMainThread()) {
nsCOMPtr<nsIGlobalObject> incumbent = mozilla::dom::GetIncumbentGlobal();
if (!incumbent) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsIPrincipal* principal = incumbent->PrincipalOrNull();
if (!principal) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
bool isNullPrincipal;
aRv = principal->GetIsNullPrincipal(&isNullPrincipal);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (NS_WARN_IF(isNullPrincipal)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
GetOrigin(principal, origin, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
aRv = PrincipalToPrincipalInfo(principal, &principalInfo);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsIDocument* doc = window->GetExtantDoc();
if (doc) {
privateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
// No bfcache when BroadcastChannel is used.
doc->DisallowBFCaching();
}
} else {
JSContext* cx = aGlobal.Context();
workerPrivate = GetWorkerPrivateFromContext(cx);
MOZ_ASSERT(workerPrivate);
nsRefPtr<InitializeRunnable> runnable =
new InitializeRunnable(workerPrivate, origin, principalInfo,
privateBrowsing, aRv);
runnable->Dispatch(cx);
}
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<BroadcastChannel> bc =
new BroadcastChannel(window, principalInfo, origin, aChannel,
privateBrowsing);
// Register this component to PBackground.
PBackgroundChild* actor = BackgroundChild::GetForCurrentThread();
if (actor) {
bc->ActorCreated(actor);
} else {
BackgroundChild::GetOrCreateForCurrentThread(bc);
}
if (!workerPrivate) {
MOZ_ASSERT(window);
MOZ_ASSERT(window->IsInnerWindow());
bc->mInnerID = window->WindowID();
// Register as observer for inner-window-destroyed.
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(bc, "inner-window-destroyed", false);
}
} else {
bc->mWorkerFeature = new BroadcastChannelFeature(bc);
JSContext* cx = workerPrivate->GetJSContext();
if (NS_WARN_IF(!workerPrivate->AddFeature(cx, bc->mWorkerFeature))) {
NS_WARNING("Failed to register the BroadcastChannel worker feature.");
bc->mWorkerFeature = nullptr;
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
}
return bc.forget();
}
void
BroadcastChannel::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
ErrorResult& aRv)
{
if (mState != StateActive) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
PostMessageInternal(aCx, aMessage, aRv);
}
void
BroadcastChannel::PostMessageInternal(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
ErrorResult& aRv)
{
nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
if (!WriteStructuredClone(aCx, aMessage, data->mBuffer, data->mClosure)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
const nsTArray<nsRefPtr<File>>& blobs = data->mClosure.mBlobs;
for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
if (!blobs[i]->Impl()->MayBeClonedToOtherThreads()) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
}
PostMessageData(data);
}
void
BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData)
{
if (mActor) {
nsRefPtr<BCPostMessageRunnable> runnable =
new BCPostMessageRunnable(mActor, aData);
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch to the current thread!");
}
return;
}
mPendingMessages.AppendElement(aData);
}
void
BroadcastChannel::Close()
{
if (mState != StateActive) {
return;
}
if (mPendingMessages.IsEmpty()) {
// We cannot call Shutdown() immediatelly because we could have some
// postMessage runnable already dispatched. Instead, we change the state to
// StateClosed and we shutdown the actor asynchrounsly.
mState = StateClosed;
nsRefPtr<CloseRunnable> runnable = new CloseRunnable(this);
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch to the current thread!");
}
} else {
MOZ_ASSERT(!mActor);
mState = StateClosing;
}
}
void
BroadcastChannel::ActorFailed()
{
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
}
void
BroadcastChannel::ActorCreated(PBackgroundChild* aActor)
{
MOZ_ASSERT(aActor);
if (mState == StateClosed) {
return;
}
PBroadcastChannelChild* actor =
aActor->SendPBroadcastChannelConstructor(*mPrincipalInfo, mOrigin, mChannel,
mPrivateBrowsing);
mActor = static_cast<BroadcastChannelChild*>(actor);
MOZ_ASSERT(mActor);
mActor->SetParent(this);
// Flush pending messages.
for (uint32_t i = 0; i < mPendingMessages.Length(); ++i) {
PostMessageData(mPendingMessages[i]);
}
mPendingMessages.Clear();
if (mState == StateClosing) {
Shutdown();
}
}
void
BroadcastChannel::Shutdown()
{
mState = StateClosed;
if (mWorkerFeature) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), mWorkerFeature);
mWorkerFeature = nullptr;
}
if (mActor) {
mActor->SetParent(nullptr);
nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
NS_DispatchToCurrentThread(runnable);
mActor = nullptr;
}
// If shutdown() is called we have to release the reference if we still keep
// it.
if (mIsKeptAlive) {
mIsKeptAlive = false;
Release();
}
}
EventHandlerNonNull*
BroadcastChannel::GetOnmessage()
{
if (NS_IsMainThread()) {
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
}
return GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
}
void
BroadcastChannel::SetOnmessage(EventHandlerNonNull* aCallback)
{
if (NS_IsMainThread()) {
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
} else {
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
}
UpdateMustKeepAlive();
}
void
BroadcastChannel::AddEventListener(const nsAString& aType,
EventListener* aCallback,
bool aCapture,
const dom::Nullable<bool>& aWantsUntrusted,
ErrorResult& aRv)
{
DOMEventTargetHelper::AddEventListener(aType, aCallback, aCapture,
aWantsUntrusted, aRv);
if (aRv.Failed()) {
return;
}
UpdateMustKeepAlive();
}
void
BroadcastChannel::RemoveEventListener(const nsAString& aType,
EventListener* aCallback,
bool aCapture,
ErrorResult& aRv)
{
DOMEventTargetHelper::RemoveEventListener(aType, aCallback, aCapture, aRv);
if (aRv.Failed()) {
return;
}
UpdateMustKeepAlive();
}
void
BroadcastChannel::UpdateMustKeepAlive()
{
bool toKeepAlive = HasListenersFor(NS_LITERAL_STRING("message"));
if (toKeepAlive == mIsKeptAlive) {
return;
}
mIsKeptAlive = toKeepAlive;
if (toKeepAlive) {
AddRef();
} else {
Release();
}
}
NS_IMETHODIMP
BroadcastChannel::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!strcmp(aTopic, "inner-window-destroyed"));
// If the window is destroyed we have to release the reference that we are
// keeping.
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
uint64_t innerID;
nsresult rv = wrapper->GetData(&innerID);
NS_ENSURE_SUCCESS(rv, rv);
if (innerID == mInnerID) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, "inner-window-destroyed");
}
Shutdown();
}
return NS_OK;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(BroadcastChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BroadcastChannel,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BroadcastChannel,
DOMEventTargetHelper)
tmp->Shutdown();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BroadcastChannel)
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(BroadcastChannel, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BroadcastChannel, DOMEventTargetHelper)
} // namespace dom
} // namespace mozilla