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 "WindowDestroyedEvent.h"
11 #include "js/Wrapper.h"
12 #include "nsIPrincipal.h"
13 #include "nsISupportsPrimitives.h"
14 #include "nsIAppStartup.h"
15 #include "nsJSPrincipals.h"
17 #include "nsContentUtils.h"
18 #include "nsGlobalWindowInner.h"
19 #include "nsGlobalWindowOuter.h"
20 #include "xpcpublic.h"
21 #include "mozilla/AppShutdown.h"
22 #include "mozilla/BasePrincipal.h"
23 #include "mozilla/Components.h"
24 #include "mozilla/ProfilerLabels.h"
25 #include "nsFocusManager.h"
29 struct BrowserCompartmentMatcher
: public js::CompartmentFilter
{
30 bool match(JS::Compartment
* aC
) const override
{
31 return !xpc::MightBeWebContentCompartment(aC
);
35 WindowDestroyedEvent::WindowDestroyedEvent(nsGlobalWindowInner
* aWindow
,
36 uint64_t aID
, const char* aTopic
)
37 : mozilla::Runnable("WindowDestroyedEvent"),
39 mPhase(Phase::Destroying
),
41 mIsInnerWindow(true) {
42 mWindow
= do_GetWeakReference(aWindow
);
45 WindowDestroyedEvent::WindowDestroyedEvent(nsGlobalWindowOuter
* aWindow
,
46 uint64_t aID
, const char* aTopic
)
47 : mozilla::Runnable("WindowDestroyedEvent"),
49 mPhase(Phase::Destroying
),
51 mIsInnerWindow(false) {
52 mWindow
= do_GetWeakReference(aWindow
);
56 WindowDestroyedEvent::Run() {
57 AUTO_PROFILER_LABEL("WindowDestroyedEvent::Run", OTHER
);
59 nsCOMPtr
<nsPIDOMWindowOuter
> nukedOuter
;
61 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
62 if (!observerService
) {
66 nsCOMPtr
<nsISupportsPRUint64
> wrapper
=
67 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID
);
69 wrapper
->SetData(mID
);
70 observerService
->NotifyObservers(wrapper
, mTopic
.get(), nullptr);
74 case Phase::Destroying
: {
75 bool skipNukeCrossCompartment
= false;
77 skipNukeCrossCompartment
=
78 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
);
81 if (!skipNukeCrossCompartment
) {
82 // The compartment nuking phase might be too expensive, so do that
83 // part off of idle dispatch.
85 // For the compartment nuking phase, we dispatch either an
86 // inner-window-nuked or an outer-window-nuked notification.
87 // This will allow tests to wait for compartment nuking to happen.
88 if (mTopic
.EqualsLiteral("inner-window-destroyed")) {
89 mTopic
.AssignLiteral("inner-window-nuked");
90 } else if (mTopic
.EqualsLiteral("outer-window-destroyed")) {
91 mTopic
.AssignLiteral("outer-window-nuked");
93 mPhase
= Phase::Nuking
;
95 nsCOMPtr
<nsIRunnable
> copy(this);
96 NS_DispatchToCurrentThreadQueue(copy
.forget(), 1000,
97 EventQueuePriority::Idle
);
101 case Phase::Nuking
: {
102 nsCOMPtr
<nsISupports
> window
= do_QueryReferent(mWindow
);
104 nsGlobalWindowInner
* currentInner
;
105 if (mIsInnerWindow
) {
106 currentInner
= nsGlobalWindowInner::FromSupports(window
);
108 nsGlobalWindowOuter
* outer
=
109 nsGlobalWindowOuter::FromSupports(window
);
111 nsGlobalWindowInner::Cast(outer
->GetCurrentInnerWindow());
114 NS_ENSURE_TRUE(currentInner
, NS_OK
);
116 dom::AutoJSAPI jsapi
;
118 JSContext
* cx
= jsapi
.cx();
119 JS::Rooted
<JSObject
*> obj(cx
, currentInner
->GetGlobalJSObject());
120 if (obj
&& !js::IsSystemRealm(js::GetNonCCWObjectRealm(obj
))) {
121 JS::Realm
* realm
= js::GetNonCCWObjectRealm(obj
);
123 xpc::NukeJSStackFrames(realm
);
125 nsCOMPtr
<nsIPrincipal
> pc
=
126 nsJSPrincipals::get(JS::GetRealmPrincipals(realm
));
128 if (BasePrincipal::Cast(pc
)->AddonPolicy()) {
129 // We want to nuke all references to the add-on realm.
130 xpc::NukeAllWrappersForRealm(cx
, realm
,
132 ? js::DontNukeWindowReferences
133 : js::NukeWindowReferences
);
135 // We only want to nuke wrappers for the chrome->content case
136 js::NukeCrossCompartmentWrappers(
137 cx
, BrowserCompartmentMatcher(), realm
,
138 mIsInnerWindow
? js::DontNukeWindowReferences
139 : js::NukeWindowReferences
,
140 js::NukeIncomingReferences
);
148 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
150 fm
->WasNuked(nukedOuter
);
157 } // namespace mozilla