Bug 1839316: part 5) Guard the "fetchpriority" attribute behind a pref. r=kershaw...
[gecko.git] / docshell / base / BrowsingContextGroup.h
blobfb1f2e528c32adca52fc7ef724958ecd7cd69af2
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 #ifndef mozilla_dom_BrowsingContextGroup_h
8 #define mozilla_dom_BrowsingContextGroup_h
10 #include "mozilla/dom/BrowsingContext.h"
11 #include "mozilla/FunctionRef.h"
12 #include "nsRefPtrHashtable.h"
13 #include "nsHashKeys.h"
14 #include "nsTArray.h"
15 #include "nsTHashSet.h"
16 #include "nsWrapperCache.h"
17 #include "nsXULAppAPI.h"
19 namespace mozilla {
20 class ThrottledEventQueue;
22 namespace dom {
24 // Amount of time allowed between alert/prompt/confirm before enabling
25 // the stop dialog checkbox.
26 #define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec
28 class BrowsingContext;
29 class WindowContext;
30 class ContentParent;
31 class DocGroup;
33 // A BrowsingContextGroup represents the Unit of Related Browsing Contexts in
34 // the standard.
36 // A BrowsingContext may not hold references to other BrowsingContext objects
37 // which are not in the same BrowsingContextGroup.
38 class BrowsingContextGroup final : public nsWrapperCache {
39 public:
40 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContextGroup)
41 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(BrowsingContextGroup)
43 // Interact with the list of synced contexts. This controls the lifecycle of
44 // the BrowsingContextGroup and contexts loaded within them.
45 void Register(nsISupports* aContext);
46 void Unregister(nsISupports* aContext);
48 // Control which processes will be used to host documents loaded in this
49 // BrowsingContextGroup. There should only ever be one host process per remote
50 // type.
52 // A new host process will be subscribed to the BrowsingContextGroup unless it
53 // is still launching, in which case it will subscribe itself when it is done
54 // launching.
55 void EnsureHostProcess(ContentParent* aProcess);
57 // A removed host process will no longer be used to host documents loaded in
58 // this BrowsingContextGroup.
59 void RemoveHostProcess(ContentParent* aProcess);
61 // Synchronize the current BrowsingContextGroup state down to the given
62 // content process, and continue updating it.
64 // You rarely need to call this directly, as it's automatically called by
65 // |EnsureHostProcess| as needed.
66 void Subscribe(ContentParent* aProcess);
68 // Stop synchronizing the current BrowsingContextGroup state down to a given
69 // content process. The content process must no longer be a host process.
70 void Unsubscribe(ContentParent* aProcess);
72 // Look up the process which should be used to host documents with this
73 // RemoteType. This will be a non-dead process associated with this
74 // BrowsingContextGroup, if possible.
75 ContentParent* GetHostProcess(const nsACString& aRemoteType);
77 // When a BrowsingContext is being discarded, we may want to keep the
78 // corresponding BrowsingContextGroup alive until the other process
79 // acknowledges that the BrowsingContext has been discarded. A `KeepAlive`
80 // will be added to the `BrowsingContextGroup`, delaying destruction.
81 void AddKeepAlive();
82 void RemoveKeepAlive();
84 // A `KeepAlivePtr` will hold both a strong reference to the
85 // `BrowsingContextGroup` and holds a `KeepAlive`. When the pointer is
86 // dropped, it will release both the strong reference and the keepalive.
87 struct KeepAliveDeleter {
88 void operator()(BrowsingContextGroup* aPtr) {
89 if (RefPtr<BrowsingContextGroup> ptr = already_AddRefed(aPtr)) {
90 ptr->RemoveKeepAlive();
94 using KeepAlivePtr = UniquePtr<BrowsingContextGroup, KeepAliveDeleter>;
95 KeepAlivePtr MakeKeepAlivePtr();
97 // Call when we want to check if we should suspend or resume all top level
98 // contexts.
99 void UpdateToplevelsSuspendedIfNeeded();
101 // Get a reference to the list of toplevel contexts in this
102 // BrowsingContextGroup.
103 nsTArray<RefPtr<BrowsingContext>>& Toplevels() { return mToplevels; }
104 void GetToplevels(nsTArray<RefPtr<BrowsingContext>>& aToplevels) {
105 aToplevels.AppendElements(mToplevels);
108 uint64_t Id() { return mId; }
110 nsISupports* GetParentObject() const;
111 JSObject* WrapObject(JSContext* aCx,
112 JS::Handle<JSObject*> aGivenProto) override;
114 // Get or create a BrowsingContextGroup with the given ID.
115 static already_AddRefed<BrowsingContextGroup> GetOrCreate(uint64_t aId);
116 static already_AddRefed<BrowsingContextGroup> GetExisting(uint64_t aId);
117 static already_AddRefed<BrowsingContextGroup> Create(
118 bool aPotentiallyCrossOriginIsolated = false);
119 static already_AddRefed<BrowsingContextGroup> Select(
120 WindowContext* aParent, BrowsingContext* aOpener);
122 // Like `Create` but only generates and reserves a new ID without actually
123 // creating the BrowsingContextGroup object.
124 static uint64_t CreateId(bool aPotentiallyCrossOriginIsolated = false);
126 // For each 'ContentParent', except for 'aExcludedParent',
127 // associated with this group call 'aCallback'.
128 template <typename Func>
129 void EachOtherParent(ContentParent* aExcludedParent, Func&& aCallback) {
130 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
131 for (const auto& key : mSubscribers) {
132 if (key != aExcludedParent) {
133 aCallback(key);
138 // For each 'ContentParent' associated with
139 // this group call 'aCallback'.
140 template <typename Func>
141 void EachParent(Func&& aCallback) {
142 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
143 for (const auto& key : mSubscribers) {
144 aCallback(key);
148 nsresult QueuePostMessageEvent(already_AddRefed<nsIRunnable>&& aRunnable);
150 void FlushPostMessageEvents();
152 // Increase or decrease the suspension level in InputTaskManager
153 void UpdateInputTaskManagerIfNeeded(bool aIsActive);
155 static BrowsingContextGroup* GetChromeGroup();
157 void GetDocGroups(nsTArray<DocGroup*>& aDocGroups);
159 // Called by Document when a Document needs to be added to a DocGroup.
160 already_AddRefed<DocGroup> AddDocument(const nsACString& aKey,
161 Document* aDocument);
163 // Called by Document when a Document needs to be removed from a DocGroup.
164 // aDocGroup should be from aDocument. This is done to avoid the assert
165 // in GetDocGroup() which can crash when called during unlinking.
166 void RemoveDocument(Document* aDocument, DocGroup* aDocGroup);
168 mozilla::ThrottledEventQueue* GetTimerEventQueue() const {
169 return mTimerEventQueue;
172 mozilla::ThrottledEventQueue* GetWorkerEventQueue() const {
173 return mWorkerEventQueue;
176 void SetAreDialogsEnabled(bool aAreDialogsEnabled) {
177 mAreDialogsEnabled = aAreDialogsEnabled;
180 bool GetAreDialogsEnabled() { return mAreDialogsEnabled; }
182 bool GetDialogAbuseCount() { return mDialogAbuseCount; }
184 // For tests only.
185 void ResetDialogAbuseState();
187 bool DialogsAreBeingAbused();
189 TimeStamp GetLastDialogQuitTime() { return mLastDialogQuitTime; }
191 void SetLastDialogQuitTime(TimeStamp aLastDialogQuitTime) {
192 mLastDialogQuitTime = aLastDialogQuitTime;
195 // Whether all toplevel documents loaded in this group are allowed to be
196 // Cross-Origin Isolated.
198 // This does not reflect the actual value of `crossOriginIsolated`, as that
199 // also requires that the document is loaded within a `webCOOP+COEP` content
200 // process.
201 bool IsPotentiallyCrossOriginIsolated();
203 static void GetAllGroups(nsTArray<RefPtr<BrowsingContextGroup>>& aGroups);
205 void IncInputEventSuspensionLevel();
206 void DecInputEventSuspensionLevel();
208 void ChildDestroy();
210 private:
211 friend class CanonicalBrowsingContext;
213 explicit BrowsingContextGroup(uint64_t aId);
214 ~BrowsingContextGroup();
216 void MaybeDestroy();
217 void Destroy();
219 bool ShouldSuspendAllTopLevelContexts() const;
221 bool HasActiveBC();
222 void DecInputTaskManagerSuspensionLevel();
223 void IncInputTaskManagerSuspensionLevel();
225 uint64_t mId;
227 uint32_t mKeepAliveCount = 0;
229 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
230 bool mDestroyed = false;
231 #endif
233 // A BrowsingContextGroup contains a series of {Browsing,Window}Context
234 // objects. They are addressed using a hashtable to avoid linear lookup when
235 // adding or removing elements from the set.
237 // FIXME: This list is only required over a counter to keep nested
238 // non-discarded contexts within discarded contexts alive. It should be
239 // removed in the future.
240 // FIXME: Consider introducing a better common base than `nsISupports`?
241 nsTHashSet<nsRefPtrHashKey<nsISupports>> mContexts;
243 // The set of toplevel browsing contexts in the current BrowsingContextGroup.
244 nsTArray<RefPtr<BrowsingContext>> mToplevels;
246 // Whether or not all toplevels in this group should be suspended
247 bool mToplevelsSuspended = false;
249 // DocGroups are thread-safe, and not able to be cycle collected,
250 // but we still keep strong pointers. When all Documents are removed
251 // from DocGroup (by the BrowsingContextGroup), the DocGroup is
252 // removed from here.
253 nsRefPtrHashtable<nsCStringHashKey, DocGroup> mDocGroups;
255 // The content process which will host documents in this BrowsingContextGroup
256 // which need to be loaded with a given remote type.
258 // A non-launching host process must also be a subscriber, though a launching
259 // host process may not yet be subscribed, and a subscriber need not be a host
260 // process.
261 nsRefPtrHashtable<nsCStringHashKey, ContentParent> mHosts;
263 nsTHashSet<nsRefPtrHashKey<ContentParent>> mSubscribers;
265 // A queue to store postMessage events during page load, the queue will be
266 // flushed once the page is loaded
267 RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
269 RefPtr<mozilla::ThrottledEventQueue> mTimerEventQueue;
270 RefPtr<mozilla::ThrottledEventQueue> mWorkerEventQueue;
272 // A counter to keep track of the input event suspension level of this BCG
274 // We use BrowsingContextGroup to emulate process isolation in Fission, so
275 // documents within the same the same BCG will behave like they share
276 // the same input task queue.
277 uint32_t mInputEventSuspensionLevel = 0;
278 // Whether this BCG has increased the suspension level in InputTaskManager
279 bool mHasIncreasedInputTaskManagerSuspensionLevel = false;
281 // This flag keeps track of whether dialogs are
282 // currently enabled for windows of this group.
283 // It's OK to have these local to each process only because even if
284 // frames from two/three different sites (and thus, processes) coordinate a
285 // dialog abuse attack, they would only the double/triple number of dialogs,
286 // as it is still limited per-site.
287 bool mAreDialogsEnabled = true;
289 // This counts the number of windows that have been opened in rapid succession
290 // (i.e. within dom.successive_dialog_time_limit of each other). It is reset
291 // to 0 once a dialog is opened after dom.successive_dialog_time_limit seconds
292 // have elapsed without any other dialogs.
293 // See comment for mAreDialogsEnabled as to why it's ok to have this local to
294 // each process.
295 uint32_t mDialogAbuseCount = 0;
297 // This holds the time when the last modal dialog was shown. If more than
298 // MAX_DIALOG_LIMIT dialogs are shown within the time span defined by
299 // dom.successive_dialog_time_limit, we show a checkbox or confirmation prompt
300 // to allow disabling of further dialogs from windows in this BC group.
301 TimeStamp mLastDialogQuitTime;
303 } // namespace dom
304 } // namespace mozilla
306 inline void ImplCycleCollectionUnlink(
307 mozilla::dom::BrowsingContextGroup::KeepAlivePtr& aField) {
308 aField = nullptr;
311 inline void ImplCycleCollectionTraverse(
312 nsCycleCollectionTraversalCallback& aCallback,
313 mozilla::dom::BrowsingContextGroup::KeepAlivePtr& aField, const char* aName,
314 uint32_t aFlags = 0) {
315 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
318 #endif // !defined(mozilla_dom_BrowsingContextGroup_h)