Backed out changeset 58dbd2146e24 (bug 944961) for bustage.
[gecko.git] / content / base / src / nsFrameMessageManager.h
blobc091e90d7b8a86ba0d5bfcba36d4e3037562c2a2
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"
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 "nsIObserverService.h"
25 #include "nsThreadUtils.h"
26 #include "nsWeakPtr.h"
27 #include "mozilla/Attributes.h"
28 #include "js/RootingAPI.h"
29 #include "nsTObserverArray.h"
31 namespace mozilla {
32 namespace dom {
34 class ContentParent;
35 class ContentChild;
36 struct StructuredCloneData;
37 class ClonedMessageData;
38 class MessageManagerReporter;
40 namespace ipc {
42 enum MessageManagerFlags {
43 MM_CHILD = 0,
44 MM_CHROME = 1,
45 MM_GLOBAL = 2,
46 MM_PROCESSMANAGER = 4,
47 MM_BROADCASTER = 8,
48 MM_OWNSCALLBACK = 16
51 class MessageManagerCallback
53 public:
54 virtual ~MessageManagerCallback() {}
56 virtual bool DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
58 return true;
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,
67 bool aIsSync)
69 return true;
72 virtual bool DoSendAsyncMessage(JSContext* aCx,
73 const nsAString& aMessage,
74 const StructuredCloneData& aData,
75 JS::Handle<JSObject*> aCpows,
76 nsIPrincipal* aPrincipal)
78 return true;
81 virtual bool CheckPermission(const nsAString& aPermission)
83 return false;
86 virtual bool CheckManifestURL(const nsAString& aManifestURL)
88 return false;
91 virtual bool CheckAppHasPermission(const nsAString& aPermission)
93 return false;
96 virtual bool CheckAppHasStatus(unsigned short aStatus)
98 return false;
101 protected:
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);
113 } // namespace ipc
114 } // namespace dom
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;
131 class CpowHolder
133 public:
134 virtual bool ToObject(JSContext* cx, JS::MutableHandle<JSObject*> objp) = 0;
137 class MOZ_STACK_CLASS SameProcessCpowHolder : public CpowHolder
139 public:
140 SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject*> aObj)
141 : mObj(aRuntime, aObj)
145 bool ToObject(JSContext* aCx, JS::MutableHandle<JSObject*> aObjp);
147 private:
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;
158 public:
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);
182 if (mOwnsCallback) {
183 mOwnedCallback = aCallback;
187 ~nsFrameMessageManager()
189 for (int32_t i = mChildManagers.Count(); i > 0; --i) {
190 static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
191 Disconnect(false);
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()
239 return mCallback;
242 nsresult DispatchAsyncMessage(const nsAString& aMessageName,
243 const JS::Value& aJSON,
244 const JS::Value& aObjects,
245 nsIPrincipal* aPrincipal,
246 JSContext* aCx,
247 uint8_t aArgc);
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;
272 private:
273 nsresult SendMessage(const nsAString& aMessageName,
274 const JS::Value& aJSON,
275 const JS::Value& aObjects,
276 nsIPrincipal* aPrincipal,
277 JSContext* aCx,
278 uint8_t aArgc,
279 JS::Value* aRetval,
280 bool aIsSync);
281 protected:
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
292 bool mOwnsCallback;
293 bool mHandlingMessage;
294 bool mDisconnected;
295 mozilla::dom::ipc::MessageManagerCallback* mCallback;
296 nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
297 nsFrameMessageManager* mParentManager;
298 nsTArray<nsString> mPendingScripts;
299 nsTArray<bool> mPendingScriptsGlobalStates;
300 public:
301 static nsFrameMessageManager* sParentProcessManager;
302 static nsFrameMessageManager* sChildProcessManager;
303 static nsFrameMessageManager* sSameProcessParentManager;
304 static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
305 private:
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,
313 bool* aValid);
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>.
331 JSScript* mScript;
332 JSObject* mFunction;
335 class nsFrameScriptObjectExecutorStackHolder;
337 class nsFrameScriptExecutor
339 public:
340 static void Shutdown();
341 already_AddRefed<nsIXPConnectJSObjectHolder> GetGlobal()
343 nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mGlobal;
344 return ref.forget();
346 protected:
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,
356 bool aShouldCache,
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
370 NS_DECL_ISUPPORTS
372 nsScriptCacheCleaner()
374 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
375 if (obsSvc)
376 obsSvc->AddObserver(this, "xpcom-shutdown", false);
379 NS_IMETHODIMP Observe(nsISupports *aSubject,
380 const char *aTopic,
381 const PRUnichar *aData)
383 nsFrameScriptExecutor::Shutdown();
384 return NS_OK;
388 #endif