Bug 1728955: part 3) Add logging to `nsBaseClipboard`. r=masayuki
[gecko.git] / dom / base / nsFrameMessageManager.h
blobfb6639701993c6181328973da5ec43ba18c10577
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/RootingAPI.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 UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
79 StructuredCloneData& aData);
81 void UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
82 StructuredCloneData& aData);
84 } // namespace ipc
85 } // namespace dom
86 } // namespace mozilla
88 struct nsMessageListenerInfo {
89 bool operator==(const nsMessageListenerInfo& aOther) const {
90 return &aOther == this;
93 // If mWeakListener is null then mStrongListener holds a MessageListener.
94 // If mWeakListener is non-null then mStrongListener contains null.
95 RefPtr<mozilla::dom::MessageListener> mStrongListener;
96 nsWeakPtr mWeakListener;
97 bool mListenWhenClosed;
100 class nsFrameMessageManager : public nsIMessageSender {
101 friend class mozilla::dom::MessageManagerReporter;
102 using StructuredCloneData = mozilla::dom::ipc::StructuredCloneData;
104 protected:
105 using MessageManagerFlags = mozilla::dom::ipc::MessageManagerFlags;
107 nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
108 MessageManagerFlags aFlags);
110 virtual ~nsFrameMessageManager();
112 public:
113 explicit nsFrameMessageManager(
114 mozilla::dom::ipc::MessageManagerCallback* aCallback)
115 : nsFrameMessageManager(aCallback, MessageManagerFlags::MM_NONE) {}
117 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
118 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsFrameMessageManager)
120 void MarkForCC();
122 // MessageListenerManager
123 void AddMessageListener(const nsAString& aMessageName,
124 mozilla::dom::MessageListener& aListener,
125 bool aListenWhenClosed, mozilla::ErrorResult& aError);
126 void RemoveMessageListener(const nsAString& aMessageName,
127 mozilla::dom::MessageListener& aListener,
128 mozilla::ErrorResult& aError);
129 void AddWeakMessageListener(const nsAString& aMessageName,
130 mozilla::dom::MessageListener& aListener,
131 mozilla::ErrorResult& aError);
132 void RemoveWeakMessageListener(const nsAString& aMessageName,
133 mozilla::dom::MessageListener& aListener,
134 mozilla::ErrorResult& aError);
136 // MessageSender
137 void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
138 JS::Handle<JS::Value> aObj,
139 JS::Handle<JS::Value> aTransfers,
140 mozilla::ErrorResult& aError) {
141 DispatchAsyncMessage(aCx, aMessageName, aObj, aTransfers, aError);
143 already_AddRefed<mozilla::dom::ProcessMessageManager>
144 GetProcessMessageManager(mozilla::ErrorResult& aError);
145 void GetRemoteType(nsACString& aRemoteType,
146 mozilla::ErrorResult& aError) const;
148 // SyncMessageSender
149 void SendSyncMessage(JSContext* aCx, const nsAString& aMessageName,
150 JS::Handle<JS::Value> aObj, nsTArray<JS::Value>& aResult,
151 mozilla::ErrorResult& aError);
153 // GlobalProcessScriptLoader
154 void GetInitialProcessData(JSContext* aCx,
155 JS::MutableHandle<JS::Value> aInitialProcessData,
156 mozilla::ErrorResult& aError);
158 mozilla::dom::ipc::WritableSharedMap* SharedData();
160 NS_DECL_NSIMESSAGESENDER
162 static mozilla::dom::ProcessMessageManager* NewProcessMessageManager(
163 bool aIsRemote);
165 void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
166 const nsAString& aMessage, bool aIsSync,
167 StructuredCloneData* aCloneData,
168 nsTArray<StructuredCloneData>* aRetVal,
169 mozilla::ErrorResult& aError) {
170 ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync,
171 aCloneData, aRetVal, aError);
174 void Disconnect(bool aRemoveFromParent = true);
175 void Close();
177 void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
179 mozilla::dom::ipc::MessageManagerCallback* GetCallback() { return mCallback; }
181 nsresult DispatchAsyncMessageInternal(JSContext* aCx,
182 const nsAString& aMessage,
183 StructuredCloneData& aData);
184 bool IsGlobal() { return mGlobal; }
185 bool IsBroadcaster() { return mIsBroadcaster; }
186 bool IsChrome() { return mChrome; }
188 // GetGlobalMessageManager creates the global message manager if it hasn't
189 // been yet.
190 static already_AddRefed<mozilla::dom::ChromeMessageBroadcaster>
191 GetGlobalMessageManager();
192 static mozilla::dom::ParentProcessMessageManager* GetParentProcessManager() {
193 return sParentProcessManager;
195 static mozilla::dom::ChildProcessMessageManager* GetChildProcessManager() {
196 return sChildProcessManager;
198 static void SetChildProcessManager(
199 mozilla::dom::ChildProcessMessageManager* aManager) {
200 sChildProcessManager = aManager;
203 static bool GetParamsForMessage(JSContext* aCx, const JS::Value& aValue,
204 const JS::Value& aTransfer,
205 StructuredCloneData& aData);
207 void SetInitialProcessData(JS::HandleValue aInitialData);
209 void LoadPendingScripts();
211 protected:
212 friend class MMListenerRemover;
214 virtual mozilla::dom::MessageBroadcaster* GetParentManager() {
215 return nullptr;
217 virtual void ClearParentManager(bool aRemove) {}
219 void DispatchAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
220 JS::Handle<JS::Value> aObj,
221 JS::Handle<JS::Value> aTransfers,
222 mozilla::ErrorResult& aError);
224 void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
225 bool aTargetClosed, const nsAString& aMessage,
226 bool aIsSync, StructuredCloneData* aCloneData,
227 nsTArray<StructuredCloneData>* aRetVal,
228 mozilla::ErrorResult& aError);
230 void LoadScript(const nsAString& aURL, bool aAllowDelayedLoad,
231 bool aRunInGlobalScope, mozilla::ErrorResult& aError);
232 void RemoveDelayedScript(const nsAString& aURL);
233 void GetDelayedScripts(JSContext* aCx, nsTArray<nsTArray<JS::Value>>& aList,
234 mozilla::ErrorResult& aError);
236 // We keep the message listeners as arrays in a hastable indexed by the
237 // message name. That gives us fast lookups in ReceiveMessage().
238 nsClassHashtable<nsStringHashKey,
239 nsAutoTObserverArray<nsMessageListenerInfo, 1>>
240 mListeners;
241 nsTArray<RefPtr<mozilla::dom::MessageListenerManager>> mChildManagers;
242 bool mChrome; // true if we're in the chrome process
243 bool mGlobal; // true if we're the global frame message manager
244 bool mIsProcessManager; // true if the message manager belongs to the process
245 // realm
246 bool mIsBroadcaster; // true if the message manager is a broadcaster
247 bool mOwnsCallback;
248 bool mHandlingMessage;
249 bool mClosed; // true if we can no longer send messages
250 bool mDisconnected;
251 mozilla::dom::ipc::MessageManagerCallback* mCallback;
252 mozilla::UniquePtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
253 nsTArray<nsString> mPendingScripts;
254 nsTArray<bool> mPendingScriptsGlobalStates;
255 JS::Heap<JS::Value> mInitialProcessData;
256 RefPtr<mozilla::dom::ipc::WritableSharedMap> mSharedData;
258 void LoadPendingScripts(nsFrameMessageManager* aManager,
259 nsFrameMessageManager* aChildMM);
261 public:
262 static mozilla::dom::ParentProcessMessageManager* sParentProcessManager;
263 static nsFrameMessageManager* sSameProcessParentManager;
264 static nsTArray<nsCOMPtr<nsIRunnable>>* sPendingSameProcessAsyncMessages;
266 private:
267 static mozilla::dom::ChildProcessMessageManager* sChildProcessManager;
270 /* A helper class for taking care of many details for async message sending
271 within a single process. Intended to be used like so:
273 class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public Runnable
275 NS_IMETHOD Run() {
276 ReceiveMessage(..., ...);
277 return NS_OK;
282 RefPtr<nsSameProcessAsyncMessageBase> ev = new MyAsyncMessage();
283 nsresult rv = ev->Init(...);
284 if (NS_SUCCEEDED(rv)) {
285 NS_DispatchToMainThread(ev);
288 class nsSameProcessAsyncMessageBase {
289 public:
290 using StructuredCloneData = mozilla::dom::ipc::StructuredCloneData;
292 nsSameProcessAsyncMessageBase();
293 nsresult Init(const nsAString& aMessage, StructuredCloneData& aData);
295 void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
296 nsFrameMessageManager* aManager);
298 private:
299 nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
301 nsString mMessage;
302 StructuredCloneData mData;
303 #ifdef DEBUG
304 bool mCalledInit;
305 #endif
308 class nsScriptCacheCleaner;
310 struct nsMessageManagerScriptHolder {
311 nsMessageManagerScriptHolder(JSContext* aCx, JSScript* aScript)
312 : mScript(aCx, aScript) {
313 MOZ_COUNT_CTOR(nsMessageManagerScriptHolder);
316 MOZ_COUNTED_DTOR(nsMessageManagerScriptHolder)
318 JS::PersistentRooted<JSScript*> mScript;
321 class nsMessageManagerScriptExecutor {
322 public:
323 static void PurgeCache();
324 static void Shutdown();
326 void MarkScopesForCC();
328 protected:
329 friend class nsMessageManagerScriptCx;
330 nsMessageManagerScriptExecutor() {
331 MOZ_COUNT_CTOR(nsMessageManagerScriptExecutor);
333 MOZ_COUNTED_DTOR(nsMessageManagerScriptExecutor)
335 void DidCreateScriptLoader();
336 void LoadScriptInternal(JS::Handle<JSObject*> aMessageManager,
337 const nsAString& aURL, bool aRunInUniqueScope);
338 void TryCacheLoadAndCompileScript(const nsAString& aURL,
339 bool aRunInUniqueScope, bool aShouldCache,
340 JS::Handle<JSObject*> aMessageManager,
341 JS::MutableHandle<JSScript*> aScriptp);
342 bool Init();
343 void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
344 void Unlink();
345 AutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
347 // Returns true if this is a process message manager. There should only be a
348 // single process message manager per session, so instances of this type will
349 // optimize their script loading to avoid unnecessary duplication.
350 virtual bool IsProcessScoped() const { return false; }
352 static nsTHashMap<nsStringHashKey, nsMessageManagerScriptHolder*>*
353 sCachedScripts;
354 static mozilla::StaticRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
357 class nsScriptCacheCleaner final : public nsIObserver {
358 ~nsScriptCacheCleaner() = default;
360 NS_DECL_ISUPPORTS
362 nsScriptCacheCleaner() {
363 nsCOMPtr<nsIObserverService> obsSvc =
364 mozilla::services::GetObserverService();
365 if (obsSvc) {
366 obsSvc->AddObserver(this, "message-manager-flush-caches", false);
367 obsSvc->AddObserver(this, "xpcom-shutdown", false);
371 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
372 const char16_t* aData) override {
373 if (strcmp("message-manager-flush-caches", aTopic) == 0) {
374 nsMessageManagerScriptExecutor::PurgeCache();
375 } else if (strcmp("xpcom-shutdown", aTopic) == 0) {
376 nsMessageManagerScriptExecutor::Shutdown();
378 return NS_OK;
382 #endif