Line data Source code
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/. */
6 :
7 : #ifndef nsFrameMessageManager_h__
8 : #define nsFrameMessageManager_h__
9 :
10 : #include "nsIMessageManager.h"
11 : #include "nsIObserver.h"
12 : #include "nsCOMPtr.h"
13 : #include "nsAutoPtr.h"
14 : #include "nsCOMArray.h"
15 : #include "nsTArray.h"
16 : #include "nsIAtom.h"
17 : #include "nsCycleCollectionParticipant.h"
18 : #include "nsTArray.h"
19 : #include "nsIPrincipal.h"
20 : #include "nsIXPConnect.h"
21 : #include "nsDataHashtable.h"
22 : #include "nsClassHashtable.h"
23 : #include "mozilla/Services.h"
24 : #include "mozilla/StaticPtr.h"
25 : #include "nsIObserverService.h"
26 : #include "nsThreadUtils.h"
27 : #include "nsWeakPtr.h"
28 : #include "mozilla/Attributes.h"
29 : #include "js/RootingAPI.h"
30 : #include "nsTObserverArray.h"
31 : #include "mozilla/dom/SameProcessMessageQueue.h"
32 : #include "mozilla/dom/ipc/StructuredCloneData.h"
33 : #include "mozilla/jsipc/CpowHolder.h"
34 :
35 : class nsIFrameLoader;
36 :
37 : namespace mozilla {
38 : namespace dom {
39 :
40 : class nsIContentParent;
41 : class nsIContentChild;
42 : class ClonedMessageData;
43 : class MessageManagerReporter;
44 :
45 : namespace ipc {
46 :
47 : // Note: we round the time we spend to the nearest millisecond. So a min value
48 : // of 1 ms actually captures from 500us and above.
49 : static const uint32_t kMinTelemetrySyncMessageManagerLatencyMs = 1;
50 :
51 : enum MessageManagerFlags {
52 : MM_CHILD = 0,
53 : MM_CHROME = 1,
54 : MM_GLOBAL = 2,
55 : MM_PROCESSMANAGER = 4,
56 : MM_BROADCASTER = 8,
57 : MM_OWNSCALLBACK = 16
58 : };
59 :
60 15 : class MessageManagerCallback
61 : {
62 : public:
63 0 : virtual ~MessageManagerCallback() {}
64 :
65 0 : virtual bool DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
66 : {
67 0 : return true;
68 : }
69 :
70 0 : virtual bool DoSendBlockingMessage(JSContext* aCx,
71 : const nsAString& aMessage,
72 : StructuredCloneData& aData,
73 : JS::Handle<JSObject*> aCpows,
74 : nsIPrincipal* aPrincipal,
75 : nsTArray<StructuredCloneData>* aRetVal,
76 : bool aIsSync)
77 : {
78 0 : return true;
79 : }
80 :
81 0 : virtual nsresult DoSendAsyncMessage(JSContext* aCx,
82 : const nsAString& aMessage,
83 : StructuredCloneData& aData,
84 : JS::Handle<JSObject*> aCpows,
85 : nsIPrincipal* aPrincipal)
86 : {
87 0 : return NS_OK;
88 : }
89 :
90 0 : virtual nsIMessageSender* GetProcessMessageManager() const
91 : {
92 0 : return nullptr;
93 : }
94 :
95 : protected:
96 : bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
97 : StructuredCloneData& aData,
98 : ClonedMessageData& aClonedData);
99 : bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
100 : StructuredCloneData& aData,
101 : ClonedMessageData& aClonedData);
102 : };
103 :
104 : void UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
105 : StructuredCloneData& aData);
106 :
107 : void UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
108 : StructuredCloneData& aData);
109 :
110 : } // namespace ipc
111 : } // namespace dom
112 : } // namespace mozilla
113 :
114 398 : struct nsMessageListenerInfo
115 : {
116 0 : bool operator==(const nsMessageListenerInfo& aOther) const
117 : {
118 0 : return &aOther == this;
119 : }
120 :
121 : // Exactly one of mStrongListener and mWeakListener must be non-null.
122 : nsCOMPtr<nsIMessageListener> mStrongListener;
123 : nsWeakPtr mWeakListener;
124 : bool mListenWhenClosed;
125 : };
126 :
127 :
128 5 : class MOZ_STACK_CLASS SameProcessCpowHolder : public mozilla::jsipc::CpowHolder
129 : {
130 : public:
131 5 : SameProcessCpowHolder(JS::RootingContext* aRootingCx, JS::Handle<JSObject*> aObj)
132 5 : : mObj(aRootingCx, aObj)
133 : {
134 5 : }
135 :
136 : virtual bool ToObject(JSContext* aCx, JS::MutableHandle<JSObject*> aObjp)
137 : override;
138 :
139 : private:
140 : JS::Rooted<JSObject*> mObj;
141 : };
142 :
143 : class nsFrameMessageManager final : public nsIContentFrameMessageManager,
144 : public nsIMessageBroadcaster,
145 : public nsIFrameScriptLoader,
146 : public nsIGlobalProcessScriptLoader
147 : {
148 : friend class mozilla::dom::MessageManagerReporter;
149 : typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
150 : public:
151 : nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
152 : nsFrameMessageManager* aParentManager,
153 : /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags);
154 :
155 : private:
156 : ~nsFrameMessageManager();
157 :
158 : public:
159 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
160 1513 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFrameMessageManager,
161 : nsIContentFrameMessageManager)
162 : NS_DECL_NSIMESSAGELISTENERMANAGER
163 : NS_DECL_NSIMESSAGESENDER
164 : NS_DECL_NSIMESSAGEBROADCASTER
165 : NS_DECL_NSISYNCMESSAGESENDER
166 : NS_DECL_NSIMESSAGEMANAGERGLOBAL
167 : NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
168 : NS_DECL_NSIFRAMESCRIPTLOADER
169 : NS_DECL_NSIPROCESSSCRIPTLOADER
170 : NS_DECL_NSIGLOBALPROCESSSCRIPTLOADER
171 :
172 : static nsFrameMessageManager*
173 : NewProcessMessageManager(bool aIsRemote);
174 :
175 : nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
176 : const nsAString& aMessage,
177 : bool aIsSync, StructuredCloneData* aCloneData,
178 : mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
179 : nsTArray<StructuredCloneData>* aRetVal);
180 :
181 : void AddChildManager(nsFrameMessageManager* aManager);
182 1 : void RemoveChildManager(nsFrameMessageManager* aManager)
183 : {
184 1 : mChildManagers.RemoveObject(aManager);
185 1 : }
186 : void Disconnect(bool aRemoveFromParent = true);
187 : void Close();
188 :
189 : void InitWithCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
190 : void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
191 :
192 2 : mozilla::dom::ipc::MessageManagerCallback* GetCallback()
193 : {
194 2 : return mCallback;
195 : }
196 :
197 : nsresult DispatchAsyncMessage(const nsAString& aMessageName,
198 : const JS::Value& aJSON,
199 : const JS::Value& aObjects,
200 : nsIPrincipal* aPrincipal,
201 : const JS::Value& aTransfers,
202 : JSContext* aCx,
203 : uint8_t aArgc);
204 :
205 : nsresult DispatchAsyncMessageInternal(JSContext* aCx,
206 : const nsAString& aMessage,
207 : StructuredCloneData& aData,
208 : JS::Handle<JSObject*> aCpows,
209 : nsIPrincipal* aPrincipal);
210 : void RemoveFromParent();
211 : nsFrameMessageManager* GetParentManager() { return mParentManager; }
212 : void SetParentManager(nsFrameMessageManager* aParent)
213 : {
214 : NS_ASSERTION(!mParentManager, "We have parent manager already!");
215 : NS_ASSERTION(mChrome, "Should not set parent manager!");
216 : mParentManager = aParent;
217 : }
218 0 : bool IsGlobal() { return mGlobal; }
219 15 : bool IsBroadcaster() { return mIsBroadcaster; }
220 :
221 : static nsFrameMessageManager* GetParentProcessManager()
222 : {
223 : return sParentProcessManager;
224 : }
225 10 : static nsFrameMessageManager* GetChildProcessManager()
226 : {
227 10 : return sChildProcessManager;
228 : }
229 3 : static void SetChildProcessManager(nsFrameMessageManager* aManager)
230 : {
231 3 : sChildProcessManager = aManager;
232 3 : }
233 :
234 : void SetInitialProcessData(JS::HandleValue aInitialData);
235 :
236 : void LoadPendingScripts();
237 :
238 : private:
239 : nsresult SendMessage(const nsAString& aMessageName,
240 : JS::Handle<JS::Value> aJSON,
241 : JS::Handle<JS::Value> aObjects,
242 : nsIPrincipal* aPrincipal,
243 : JSContext* aCx,
244 : uint8_t aArgc,
245 : JS::MutableHandle<JS::Value> aRetval,
246 : bool aIsSync);
247 :
248 : nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
249 : bool aTargetClosed, const nsAString& aMessage,
250 : bool aIsSync, StructuredCloneData* aCloneData,
251 : mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
252 : nsTArray<StructuredCloneData>* aRetVal);
253 :
254 : NS_IMETHOD LoadScript(const nsAString& aURL,
255 : bool aAllowDelayedLoad,
256 : bool aRunInGlobalScope);
257 : NS_IMETHOD RemoveDelayedScript(const nsAString& aURL);
258 : NS_IMETHOD GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList);
259 :
260 : protected:
261 : friend class MMListenerRemover;
262 : // We keep the message listeners as arrays in a hastable indexed by the
263 : // message name. That gives us fast lookups in ReceiveMessage().
264 : nsClassHashtable<nsStringHashKey,
265 : nsAutoTObserverArray<nsMessageListenerInfo, 1>> mListeners;
266 : nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
267 : bool mChrome; // true if we're in the chrome process
268 : bool mGlobal; // true if we're the global frame message manager
269 : bool mIsProcessManager; // true if the message manager belongs to the process realm
270 : bool mIsBroadcaster; // true if the message manager is a broadcaster
271 : bool mOwnsCallback;
272 : bool mHandlingMessage;
273 : bool mClosed; // true if we can no longer send messages
274 : bool mDisconnected;
275 : mozilla::dom::ipc::MessageManagerCallback* mCallback;
276 : nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
277 : RefPtr<nsFrameMessageManager> mParentManager;
278 : nsTArray<nsString> mPendingScripts;
279 : nsTArray<bool> mPendingScriptsGlobalStates;
280 : JS::Heap<JS::Value> mInitialProcessData;
281 :
282 : void LoadPendingScripts(nsFrameMessageManager* aManager,
283 : nsFrameMessageManager* aChildMM);
284 : public:
285 : static nsFrameMessageManager* sParentProcessManager;
286 : static nsFrameMessageManager* sSameProcessParentManager;
287 : static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
288 : private:
289 : static nsFrameMessageManager* sChildProcessManager;
290 : enum ProcessCheckerType {
291 : PROCESS_CHECKER_PERMISSION,
292 : PROCESS_CHECKER_MANIFEST_URL,
293 : ASSERT_APP_HAS_PERMISSION
294 : };
295 : nsresult AssertProcessInternal(ProcessCheckerType aType,
296 : const nsAString& aCapability,
297 : bool* aValid);
298 : };
299 :
300 : /* A helper class for taking care of many details for async message sending
301 : within a single process. Intended to be used like so:
302 :
303 : class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public Runnable
304 : {
305 : NS_IMETHOD Run() override {
306 : ReceiveMessage(..., ...);
307 : return NS_OK;
308 : }
309 : };
310 :
311 :
312 : RefPtr<nsSameProcessAsyncMessageBase> ev = new MyAsyncMessage();
313 : nsresult rv = ev->Init(...);
314 : if (NS_SUCCEEDED(rv)) {
315 : NS_DispatchToMainThread(ev);
316 : }
317 : */
318 5 : class nsSameProcessAsyncMessageBase
319 : {
320 : public:
321 : typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
322 :
323 : nsSameProcessAsyncMessageBase(JS::RootingContext* aRootingCx,
324 : JS::Handle<JSObject*> aCpows);
325 : nsresult Init(const nsAString& aMessage,
326 : StructuredCloneData& aData,
327 : nsIPrincipal* aPrincipal);
328 :
329 : void ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
330 : nsFrameMessageManager* aManager);
331 : private:
332 : nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
333 :
334 : nsString mMessage;
335 : StructuredCloneData mData;
336 : JS::PersistentRooted<JSObject*> mCpows;
337 : nsCOMPtr<nsIPrincipal> mPrincipal;
338 : #ifdef DEBUG
339 : bool mCalledInit;
340 : #endif
341 : };
342 :
343 : class nsScriptCacheCleaner;
344 :
345 : struct nsMessageManagerScriptHolder
346 : {
347 39 : nsMessageManagerScriptHolder(JSContext* aCx,
348 : JSScript* aScript,
349 : bool aRunInGlobalScope)
350 39 : : mScript(aCx, aScript), mRunInGlobalScope(aRunInGlobalScope)
351 39 : { MOZ_COUNT_CTOR(nsMessageManagerScriptHolder); }
352 :
353 0 : ~nsMessageManagerScriptHolder()
354 0 : { MOZ_COUNT_DTOR(nsMessageManagerScriptHolder); }
355 :
356 0 : bool WillRunInGlobalScope() { return mRunInGlobalScope; }
357 :
358 : JS::PersistentRooted<JSScript*> mScript;
359 : bool mRunInGlobalScope;
360 : };
361 :
362 : class nsMessageManagerScriptExecutor
363 : {
364 : public:
365 : static void PurgeCache();
366 : static void Shutdown();
367 2078 : JSObject* GetGlobal()
368 : {
369 2078 : return mGlobal;
370 : }
371 :
372 : void MarkScopesForCC();
373 : protected:
374 : friend class nsMessageManagerScriptCx;
375 5 : nsMessageManagerScriptExecutor() { MOZ_COUNT_CTOR(nsMessageManagerScriptExecutor); }
376 0 : ~nsMessageManagerScriptExecutor() { MOZ_COUNT_DTOR(nsMessageManagerScriptExecutor); }
377 :
378 : void DidCreateGlobal();
379 : void LoadScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
380 : void TryCacheLoadAndCompileScript(const nsAString& aURL,
381 : bool aRunInGlobalScope,
382 : bool aShouldCache,
383 : JS::MutableHandle<JSScript*> aScriptp);
384 : void TryCacheLoadAndCompileScript(const nsAString& aURL,
385 : bool aRunInGlobalScope);
386 : bool InitChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
387 : void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
388 : void Unlink();
389 : JS::TenuredHeap<JSObject*> mGlobal;
390 : nsCOMPtr<nsIPrincipal> mPrincipal;
391 : AutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
392 :
393 : static nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>* sCachedScripts;
394 : static mozilla::StaticRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
395 : };
396 :
397 : class nsScriptCacheCleaner final : public nsIObserver
398 : {
399 0 : ~nsScriptCacheCleaner() {}
400 :
401 : NS_DECL_ISUPPORTS
402 :
403 3 : nsScriptCacheCleaner()
404 3 : {
405 6 : nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
406 3 : if (obsSvc) {
407 3 : obsSvc->AddObserver(this, "message-manager-flush-caches", false);
408 3 : obsSvc->AddObserver(this, "xpcom-shutdown", false);
409 : }
410 3 : }
411 :
412 0 : NS_IMETHOD Observe(nsISupports *aSubject,
413 : const char *aTopic,
414 : const char16_t *aData) override
415 : {
416 0 : if (strcmp("message-manager-flush-caches", aTopic) == 0) {
417 0 : nsMessageManagerScriptExecutor::PurgeCache();
418 0 : } else if (strcmp("xpcom-shutdown", aTopic) == 0) {
419 0 : nsMessageManagerScriptExecutor::Shutdown();
420 : }
421 0 : return NS_OK;
422 : }
423 : };
424 :
425 : #endif
|