no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / base / nsFrameMessageManager.h
blob3bcecf9c9d3a22fb15fc541bd298efa3e79fe72f
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 nsFrameMessageManager_h__
8 #define nsFrameMessageManager_h__
10 #include <cstdint>
11 #include <string.h>
12 #include <utility>
13 #include "ErrorList.h"
14 #include "js/experimental/JSStencil.h"
15 #include "js/TypeDecls.h"
16 #include "js/Value.h"
17 #include "mozilla/AlreadyAddRefed.h"
18 #include "mozilla/Assertions.h"
19 #include "mozilla/RefPtr.h"
20 #include "mozilla/Services.h"
21 #include "mozilla/StaticPtr.h"
22 #include "mozilla/TypedEnumBits.h"
23 #include "mozilla/UniquePtr.h"
24 #include "mozilla/dom/ipc/StructuredCloneData.h"
25 #include "nsCOMPtr.h"
26 #include "nsClassHashtable.h"
27 #include "nsCycleCollectionParticipant.h"
28 #include "nsTHashMap.h"
29 #include "nsHashKeys.h"
30 #include "nsIMessageManager.h"
31 #include "nsIObserver.h"
32 #include "nsIObserverService.h"
33 #include "nsISupports.h"
34 #include "nsIWeakReferenceUtils.h"
35 #include "nsStringFwd.h"
36 #include "nsTArray.h"
37 #include "nsTObserverArray.h"
38 #include "nscore.h"
40 class nsFrameLoader;
41 class nsIRunnable;
43 namespace mozilla {
45 class ErrorResult;
47 namespace dom {
49 class ChildProcessMessageManager;
50 class ChromeMessageBroadcaster;
51 class ClonedMessageData;
52 class MessageBroadcaster;
53 class MessageListener;
54 class MessageListenerManager;
55 class MessageManagerReporter;
56 class ParentProcessMessageManager;
57 class ProcessMessageManager;
59 namespace ipc {
61 class MessageManagerCallback;
62 class WritableSharedMap;
64 // Note: we round the time we spend to the nearest millisecond. So a min value
65 // of 1 ms actually captures from 500us and above.
66 static const uint32_t kMinTelemetrySyncMessageManagerLatencyMs = 1;
68 enum class MessageManagerFlags {
69 MM_NONE = 0,
70 MM_CHROME = 1,
71 MM_GLOBAL = 2,
72 MM_PROCESSMANAGER = 4,
73 MM_BROADCASTER = 8,
74 MM_OWNSCALLBACK = 16
76 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MessageManagerFlags);
78 void UnpackClonedMessageData(const ClonedMessageData& aClonedData,
79 StructuredCloneData& aData);
81 } // namespace ipc
82 } // namespace dom
83 } // namespace mozilla
85 struct nsMessageListenerInfo {
86 bool operator==(const nsMessageListenerInfo& aOther) const {
87 return &aOther == this;
90 // If mWeakListener is null then mStrongListener holds a MessageListener.
91 // If mWeakListener is non-null then mStrongListener contains null.
92 RefPtr<mozilla::dom::MessageListener> mStrongListener;
93 nsWeakPtr mWeakListener;
94 bool mListenWhenClosed;
97 class nsFrameMessageManager : public nsIMessageSender {
98 friend class mozilla::dom::MessageManagerReporter;
99 using StructuredCloneData = mozilla::dom::ipc::StructuredCloneData;
101 protected:
102 using MessageManagerFlags = mozilla::dom::ipc::MessageManagerFlags;
104 nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
105 MessageManagerFlags aFlags);
107 virtual ~nsFrameMessageManager();
109 public:
110 explicit nsFrameMessageManager(
111 mozilla::dom::ipc::MessageManagerCallback* aCallback)
112 : nsFrameMessageManager(aCallback, MessageManagerFlags::MM_NONE) {}
114 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
115 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsFrameMessageManager)
117 void MarkForCC();
119 // MessageListenerManager
120 void AddMessageListener(const nsAString& aMessageName,
121 mozilla::dom::MessageListener& aListener,
122 bool aListenWhenClosed, mozilla::ErrorResult& aError);
123 void RemoveMessageListener(const nsAString& aMessageName,
124 mozilla::dom::MessageListener& aListener,
125 mozilla::ErrorResult& aError);
126 void AddWeakMessageListener(const nsAString& aMessageName,
127 mozilla::dom::MessageListener& aListener,
128 mozilla::ErrorResult& aError);
129 void RemoveWeakMessageListener(const nsAString& aMessageName,
130 mozilla::dom::MessageListener& aListener,
131 mozilla::ErrorResult& aError);
133 // MessageSender
134 void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
135 JS::Handle<JS::Value> aObj,
136 JS::Handle<JS::Value> aTransfers,
137 mozilla::ErrorResult& aError) {
138 DispatchAsyncMessage(aCx, aMessageName, aObj, aTransfers, aError);
140 already_AddRefed<mozilla::dom::ProcessMessageManager>
141 GetProcessMessageManager(mozilla::ErrorResult& aError);
142 void GetRemoteType(nsACString& aRemoteType,
143 mozilla::ErrorResult& aError) const;
145 // SyncMessageSender
146 void SendSyncMessage(JSContext* aCx, const nsAString& aMessageName,
147 JS::Handle<JS::Value> aObj, nsTArray<JS::Value>& aResult,
148 mozilla::ErrorResult& aError);
150 // GlobalProcessScriptLoader
151 void GetInitialProcessData(JSContext* aCx,
152 JS::MutableHandle<JS::Value> aInitialProcessData,
153 mozilla::ErrorResult& aError);
155 mozilla::dom::ipc::WritableSharedMap* SharedData();
157 NS_DECL_NSIMESSAGESENDER
159 static mozilla::dom::ProcessMessageManager* NewProcessMessageManager(
160 bool aIsRemote);
162 void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
163 const nsAString& aMessage, bool aIsSync,
164 StructuredCloneData* aCloneData,
165 nsTArray<StructuredCloneData>* aRetVal,
166 mozilla::ErrorResult& aError) {
167 ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync,
168 aCloneData, aRetVal, aError);
171 void Disconnect(bool aRemoveFromParent = true);
172 void Close();
174 void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
176 mozilla::dom::ipc::MessageManagerCallback* GetCallback() { return mCallback; }
178 nsresult DispatchAsyncMessageInternal(JSContext* aCx,
179 const nsAString& aMessage,
180 StructuredCloneData& aData);
181 bool IsGlobal() { return mGlobal; }
182 bool IsBroadcaster() { return mIsBroadcaster; }
183 bool IsChrome() { return mChrome; }
185 // GetGlobalMessageManager creates the global message manager if it hasn't
186 // been yet.
187 static already_AddRefed<mozilla::dom::ChromeMessageBroadcaster>
188 GetGlobalMessageManager();
189 static mozilla::dom::ParentProcessMessageManager* GetParentProcessManager() {
190 return sParentProcessManager;
192 static mozilla::dom::ChildProcessMessageManager* GetChildProcessManager() {
193 return sChildProcessManager;
195 static void SetChildProcessManager(
196 mozilla::dom::ChildProcessMessageManager* aManager) {
197 sChildProcessManager = aManager;
200 static bool GetParamsForMessage(JSContext* aCx, const JS::Value& aValue,
201 const JS::Value& aTransfer,
202 StructuredCloneData& aData);
204 void SetInitialProcessData(JS::Handle<JS::Value> aInitialData);
206 void LoadPendingScripts();
208 protected:
209 friend class MMListenerRemover;
211 virtual mozilla::dom::MessageBroadcaster* GetParentManager() {
212 return nullptr;
214 virtual void ClearParentManager(bool aRemove) {}
216 void DispatchAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
217 JS::Handle<JS::Value> aObj,
218 JS::Handle<JS::Value> aTransfers,
219 mozilla::ErrorResult& aError);
221 void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
222 bool aTargetClosed, const nsAString& aMessage,
223 bool aIsSync, StructuredCloneData* aCloneData,
224 nsTArray<StructuredCloneData>* aRetVal,
225 mozilla::ErrorResult& aError);
227 void LoadScript(const nsAString& aURL, bool aAllowDelayedLoad,
228 bool aRunInGlobalScope, mozilla::ErrorResult& aError);
229 void RemoveDelayedScript(const nsAString& aURL);
230 void GetDelayedScripts(JSContext* aCx, nsTArray<nsTArray<JS::Value>>& aList,
231 mozilla::ErrorResult& aError);
233 // We keep the message listeners as arrays in a hastable indexed by the
234 // message name. That gives us fast lookups in ReceiveMessage().
235 nsClassHashtable<nsStringHashKey,
236 nsAutoTObserverArray<nsMessageListenerInfo, 1>>
237 mListeners;
238 nsTArray<RefPtr<mozilla::dom::MessageListenerManager>> mChildManagers;
239 bool mChrome; // true if we're in the chrome process
240 bool mGlobal; // true if we're the global frame message manager
241 bool mIsProcessManager; // true if the message manager belongs to the process
242 // realm
243 bool mIsBroadcaster; // true if the message manager is a broadcaster
244 bool mOwnsCallback;
245 bool mHandlingMessage;
246 bool mClosed; // true if we can no longer send messages
247 bool mDisconnected;
248 mozilla::dom::ipc::MessageManagerCallback* mCallback;
249 mozilla::UniquePtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
250 nsTArray<nsString> mPendingScripts;
251 nsTArray<bool> mPendingScriptsGlobalStates;
252 JS::Heap<JS::Value> mInitialProcessData;
253 RefPtr<mozilla::dom::ipc::WritableSharedMap> mSharedData;
255 void LoadPendingScripts(nsFrameMessageManager* aManager,
256 nsFrameMessageManager* aChildMM);
258 public:
259 static mozilla::dom::ParentProcessMessageManager* sParentProcessManager;
260 static nsFrameMessageManager* sSameProcessParentManager;
261 static nsTArray<nsCOMPtr<nsIRunnable>>* sPendingSameProcessAsyncMessages;
263 private:
264 static mozilla::dom::ChildProcessMessageManager* sChildProcessManager;
267 /* A helper class for taking care of many details for async message sending
268 within a single process. Intended to be used like so:
270 class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public Runnable
272 NS_IMETHOD Run() {
273 ReceiveMessage(..., ...);
274 return NS_OK;
279 RefPtr<nsSameProcessAsyncMessageBase> ev = new MyAsyncMessage();
280 nsresult rv = ev->Init(...);
281 if (NS_SUCCEEDED(rv)) {
282 NS_DispatchToMainThread(ev);
285 class nsSameProcessAsyncMessageBase {
286 public:
287 using StructuredCloneData = mozilla::dom::ipc::StructuredCloneData;
289 nsSameProcessAsyncMessageBase();
290 nsresult Init(const nsAString& aMessage, StructuredCloneData& aData);
292 void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
293 nsFrameMessageManager* aManager);
295 private:
296 nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
298 nsString mMessage;
299 StructuredCloneData mData;
300 #ifdef DEBUG
301 bool mCalledInit;
302 #endif
305 class nsScriptCacheCleaner;
307 struct nsMessageManagerScriptHolder {
308 explicit nsMessageManagerScriptHolder(JS::Stencil* aStencil)
309 : mStencil(aStencil) {
310 MOZ_COUNT_CTOR(nsMessageManagerScriptHolder);
313 MOZ_COUNTED_DTOR(nsMessageManagerScriptHolder)
315 RefPtr<JS::Stencil> mStencil;
318 class nsMessageManagerScriptExecutor {
319 public:
320 static void PurgeCache();
321 static void Shutdown();
323 void MarkScopesForCC();
325 protected:
326 friend class nsMessageManagerScriptCx;
327 nsMessageManagerScriptExecutor() {
328 MOZ_COUNT_CTOR(nsMessageManagerScriptExecutor);
330 MOZ_COUNTED_DTOR(nsMessageManagerScriptExecutor)
332 void DidCreateScriptLoader();
333 void LoadScriptInternal(JS::Handle<JSObject*> aMessageManager,
334 const nsAString& aURL, bool aRunInUniqueScope);
335 already_AddRefed<JS::Stencil> TryCacheLoadAndCompileScript(
336 const nsAString& aURL, bool aRunInUniqueScope,
337 JS::Handle<JSObject*> aMessageManager);
338 bool Init();
339 void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
340 void Unlink();
341 AutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
343 // Returns true if this is a process message manager. There should only be a
344 // single process message manager per session, so instances of this type will
345 // optimize their script loading to avoid unnecessary duplication.
346 virtual bool IsProcessScoped() const { return false; }
348 static nsTHashMap<nsStringHashKey, nsMessageManagerScriptHolder*>*
349 sCachedScripts;
350 static mozilla::StaticRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
353 class nsScriptCacheCleaner final : public nsIObserver {
354 ~nsScriptCacheCleaner() = default;
356 NS_DECL_ISUPPORTS
358 nsScriptCacheCleaner() {
359 nsCOMPtr<nsIObserverService> obsSvc =
360 mozilla::services::GetObserverService();
361 if (obsSvc) {
362 obsSvc->AddObserver(this, "xpcom-shutdown", false);
366 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
367 const char16_t* aData) override {
368 if (strcmp("xpcom-shutdown", aTopic) == 0) {
369 nsMessageManagerScriptExecutor::Shutdown();
371 return NS_OK;
375 #endif