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 "nsIMessageManager.h"
11 #include "nsIObserver.h"
13 #include "nsAutoPtr.h"
14 #include "nsCOMArray.h"
17 #include "nsCycleCollectionParticipant.h"
19 #include "nsIPrincipal.h"
20 #include "nsIXPConnect.h"
21 #include "nsDataHashtable.h"
22 #include "nsClassHashtable.h"
23 #include "mozilla/Services.h"
24 #include "nsIObserverService.h"
25 #include "nsThreadUtils.h"
26 #include "nsWeakPtr.h"
27 #include "mozilla/Attributes.h"
28 #include "js/RootingAPI.h"
29 #include "nsTObserverArray.h"
36 struct StructuredCloneData
;
37 class ClonedMessageData
;
38 class MessageManagerReporter
;
42 enum MessageManagerFlags
{
46 MM_PROCESSMANAGER
= 4,
51 class MessageManagerCallback
54 virtual ~MessageManagerCallback() {}
56 virtual bool DoLoadFrameScript(const nsAString
& aURL
, bool aRunInGlobalScope
)
61 virtual bool DoSendBlockingMessage(JSContext
* aCx
,
62 const nsAString
& aMessage
,
63 const StructuredCloneData
& aData
,
64 JS::Handle
<JSObject
*> aCpows
,
65 nsIPrincipal
* aPrincipal
,
66 InfallibleTArray
<nsString
>* aJSONRetVal
,
72 virtual bool DoSendAsyncMessage(JSContext
* aCx
,
73 const nsAString
& aMessage
,
74 const StructuredCloneData
& aData
,
75 JS::Handle
<JSObject
*> aCpows
,
76 nsIPrincipal
* aPrincipal
)
81 virtual bool CheckPermission(const nsAString
& aPermission
)
86 virtual bool CheckManifestURL(const nsAString
& aManifestURL
)
91 virtual bool CheckAppHasPermission(const nsAString
& aPermission
)
96 virtual bool CheckAppHasStatus(unsigned short aStatus
)
102 bool BuildClonedMessageDataForParent(ContentParent
* aParent
,
103 const StructuredCloneData
& aData
,
104 ClonedMessageData
& aClonedData
);
105 bool BuildClonedMessageDataForChild(ContentChild
* aChild
,
106 const StructuredCloneData
& aData
,
107 ClonedMessageData
& aClonedData
);
110 StructuredCloneData
UnpackClonedMessageDataForParent(const ClonedMessageData
& aData
);
111 StructuredCloneData
UnpackClonedMessageDataForChild(const ClonedMessageData
& aData
);
115 } // namespace mozilla
117 class nsAXPCNativeCallContext
;
119 struct nsMessageListenerInfo
121 bool operator==(const nsMessageListenerInfo
& aOther
) const
123 return &aOther
== this;
126 // Exactly one of mStrongListener and mWeakListener must be non-null.
127 nsCOMPtr
<nsIMessageListener
> mStrongListener
;
128 nsWeakPtr mWeakListener
;
134 virtual bool ToObject(JSContext
* cx
, JS::MutableHandle
<JSObject
*> objp
) = 0;
137 class MOZ_STACK_CLASS SameProcessCpowHolder
: public CpowHolder
140 SameProcessCpowHolder(JSRuntime
*aRuntime
, JS::Handle
<JSObject
*> aObj
)
141 : mObj(aRuntime
, aObj
)
145 bool ToObject(JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aObjp
);
148 JS::Rooted
<JSObject
*> mObj
;
151 class nsFrameMessageManager MOZ_FINAL
: public nsIContentFrameMessageManager
,
152 public nsIMessageBroadcaster
,
153 public nsIFrameScriptLoader
,
154 public nsIProcessChecker
156 friend class mozilla::dom::MessageManagerReporter
;
157 typedef mozilla::dom::StructuredCloneData StructuredCloneData
;
159 nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback
* aCallback
,
160 nsFrameMessageManager
* aParentManager
,
161 /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags
)
162 : mChrome(!!(aFlags
& mozilla::dom::ipc::MM_CHROME
)),
163 mGlobal(!!(aFlags
& mozilla::dom::ipc::MM_GLOBAL
)),
164 mIsProcessManager(!!(aFlags
& mozilla::dom::ipc::MM_PROCESSMANAGER
)),
165 mIsBroadcaster(!!(aFlags
& mozilla::dom::ipc::MM_BROADCASTER
)),
166 mOwnsCallback(!!(aFlags
& mozilla::dom::ipc::MM_OWNSCALLBACK
)),
167 mHandlingMessage(false),
168 mDisconnected(false),
169 mCallback(aCallback
),
170 mParentManager(aParentManager
)
172 NS_ASSERTION(mChrome
|| !aParentManager
, "Should not set parent manager!");
173 NS_ASSERTION(!mIsBroadcaster
|| !mCallback
,
174 "Broadcasters cannot have callbacks!");
175 // This is a bit hackish. When parent manager is global, we want
176 // to attach the window message manager to it immediately.
177 // Is it just the frame message manager which waits until the
178 // content process is running.
179 if (mParentManager
&& (mCallback
|| IsWindowLevel())) {
180 mParentManager
->AddChildManager(this);
183 mOwnedCallback
= aCallback
;
187 ~nsFrameMessageManager()
189 for (int32_t i
= mChildManagers
.Count(); i
> 0; --i
) {
190 static_cast<nsFrameMessageManager
*>(mChildManagers
[i
- 1])->
193 if (mIsProcessManager
) {
194 if (this == sParentProcessManager
) {
195 sParentProcessManager
= nullptr;
197 if (this == sChildProcessManager
) {
198 sChildProcessManager
= nullptr;
199 delete sPendingSameProcessAsyncMessages
;
200 sPendingSameProcessAsyncMessages
= nullptr;
202 if (this == sSameProcessParentManager
) {
203 sSameProcessParentManager
= nullptr;
208 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
209 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameMessageManager
,
210 nsIContentFrameMessageManager
)
211 NS_DECL_NSIMESSAGELISTENERMANAGER
212 NS_DECL_NSIMESSAGESENDER
213 NS_DECL_NSIMESSAGEBROADCASTER
214 NS_DECL_NSISYNCMESSAGESENDER
215 NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
216 NS_DECL_NSIFRAMESCRIPTLOADER
217 NS_DECL_NSIPROCESSCHECKER
219 static nsFrameMessageManager
*
220 NewProcessMessageManager(mozilla::dom::ContentParent
* aProcess
);
222 nsresult
ReceiveMessage(nsISupports
* aTarget
, const nsAString
& aMessage
,
223 bool aIsSync
, const StructuredCloneData
* aCloneData
,
224 CpowHolder
* aCpows
, nsIPrincipal
* aPrincipal
,
225 InfallibleTArray
<nsString
>* aJSONRetVal
);
227 void AddChildManager(nsFrameMessageManager
* aManager
,
228 bool aLoadScripts
= true);
229 void RemoveChildManager(nsFrameMessageManager
* aManager
)
231 mChildManagers
.RemoveObject(aManager
);
233 void Disconnect(bool aRemoveFromParent
= true);
235 void SetCallback(mozilla::dom::ipc::MessageManagerCallback
* aCallback
,
236 bool aLoadScripts
= true);
237 mozilla::dom::ipc::MessageManagerCallback
* GetCallback()
242 nsresult
DispatchAsyncMessage(const nsAString
& aMessageName
,
243 const JS::Value
& aJSON
,
244 const JS::Value
& aObjects
,
245 nsIPrincipal
* aPrincipal
,
248 nsresult
DispatchAsyncMessageInternal(JSContext
* aCx
,
249 const nsAString
& aMessage
,
250 const StructuredCloneData
& aData
,
251 JS::Handle
<JSObject
*> aCpows
,
252 nsIPrincipal
* aPrincipal
);
253 void RemoveFromParent();
254 nsFrameMessageManager
* GetParentManager() { return mParentManager
; }
255 void SetParentManager(nsFrameMessageManager
* aParent
)
257 NS_ASSERTION(!mParentManager
, "We have parent manager already!");
258 NS_ASSERTION(mChrome
, "Should not set parent manager!");
259 mParentManager
= aParent
;
261 bool IsGlobal() { return mGlobal
; }
262 bool IsWindowLevel() { return mParentManager
&& mParentManager
->IsGlobal(); }
264 static nsFrameMessageManager
* GetParentProcessManager()
266 return sParentProcessManager
;
268 static nsFrameMessageManager
* GetChildProcessManager()
270 return sChildProcessManager
;
273 nsresult
SendMessage(const nsAString
& aMessageName
,
274 const JS::Value
& aJSON
,
275 const JS::Value
& aObjects
,
276 nsIPrincipal
* aPrincipal
,
282 friend class MMListenerRemover
;
283 // We keep the message listeners as arrays in a hastable indexed by the
284 // message name. That gives us fast lookups in ReceiveMessage().
285 nsClassHashtable
<nsStringHashKey
,
286 nsAutoTObserverArray
<nsMessageListenerInfo
, 1>> mListeners
;
287 nsCOMArray
<nsIContentFrameMessageManager
> mChildManagers
;
288 bool mChrome
; // true if we're in the chrome process
289 bool mGlobal
; // true if we're the global frame message manager
290 bool mIsProcessManager
; // true if the message manager belongs to the process realm
291 bool mIsBroadcaster
; // true if the message manager is a broadcaster
293 bool mHandlingMessage
;
295 mozilla::dom::ipc::MessageManagerCallback
* mCallback
;
296 nsAutoPtr
<mozilla::dom::ipc::MessageManagerCallback
> mOwnedCallback
;
297 nsFrameMessageManager
* mParentManager
;
298 nsTArray
<nsString
> mPendingScripts
;
299 nsTArray
<bool> mPendingScriptsGlobalStates
;
301 static nsFrameMessageManager
* sParentProcessManager
;
302 static nsFrameMessageManager
* sChildProcessManager
;
303 static nsFrameMessageManager
* sSameProcessParentManager
;
304 static nsTArray
<nsCOMPtr
<nsIRunnable
> >* sPendingSameProcessAsyncMessages
;
306 enum ProcessCheckerType
{
307 PROCESS_CHECKER_PERMISSION
,
308 PROCESS_CHECKER_MANIFEST_URL
,
309 ASSERT_APP_HAS_PERMISSION
311 nsresult
AssertProcessInternal(ProcessCheckerType aType
,
312 const nsAString
& aCapability
,
316 class nsScriptCacheCleaner
;
318 struct nsFrameScriptObjectExecutorHolder
320 nsFrameScriptObjectExecutorHolder(JSScript
* aScript
) : mScript(aScript
), mFunction(nullptr)
321 { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder
); }
322 nsFrameScriptObjectExecutorHolder(JSObject
* aFunction
) : mScript(nullptr), mFunction(aFunction
)
323 { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder
); }
324 ~nsFrameScriptObjectExecutorHolder()
325 { MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder
); }
327 bool WillRunInGlobalScope() { return mScript
; }
329 // We use JS_AddNamed{Script,Object}Root to root these fields explicitly, so
330 // no need for Heap<T>.
335 class nsFrameScriptObjectExecutorStackHolder
;
337 class nsFrameScriptExecutor
340 static void Shutdown();
341 already_AddRefed
<nsIXPConnectJSObjectHolder
> GetGlobal()
343 nsCOMPtr
<nsIXPConnectJSObjectHolder
> ref
= mGlobal
;
347 friend class nsFrameScriptCx
;
348 nsFrameScriptExecutor()
349 { MOZ_COUNT_CTOR(nsFrameScriptExecutor
); }
350 ~nsFrameScriptExecutor()
351 { MOZ_COUNT_DTOR(nsFrameScriptExecutor
); }
352 void DidCreateGlobal();
353 void LoadFrameScriptInternal(const nsAString
& aURL
, bool aRunInGlobalScope
);
354 void TryCacheLoadAndCompileScript(const nsAString
& aURL
,
355 bool aRunInGlobalScope
,
357 JS::MutableHandle
<JSScript
*> aScriptp
,
358 JS::MutableHandle
<JSObject
*> aFunp
);
359 void TryCacheLoadAndCompileScript(const nsAString
& aURL
,
360 bool aRunInGlobalScope
);
361 bool InitTabChildGlobalInternal(nsISupports
* aScope
, const nsACString
& aID
);
362 nsCOMPtr
<nsIXPConnectJSObjectHolder
> mGlobal
;
363 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
364 static nsDataHashtable
<nsStringHashKey
, nsFrameScriptObjectExecutorHolder
*>* sCachedScripts
;
365 static nsScriptCacheCleaner
* sScriptCacheCleaner
;
368 class nsScriptCacheCleaner MOZ_FINAL
: public nsIObserver
372 nsScriptCacheCleaner()
374 nsCOMPtr
<nsIObserverService
> obsSvc
= mozilla::services::GetObserverService();
376 obsSvc
->AddObserver(this, "xpcom-shutdown", false);
379 NS_IMETHODIMP
Observe(nsISupports
*aSubject
,
381 const PRUnichar
*aData
)
383 nsFrameScriptExecutor::Shutdown();