content/base/src/nsFrameMessageManager.h

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef nsFrameMessageManager_h__
michael@0 8 #define nsFrameMessageManager_h__
michael@0 9
michael@0 10 #include "nsIMessageManager.h"
michael@0 11 #include "nsIObserver.h"
michael@0 12 #include "nsCOMPtr.h"
michael@0 13 #include "nsAutoPtr.h"
michael@0 14 #include "nsCOMArray.h"
michael@0 15 #include "nsTArray.h"
michael@0 16 #include "nsIAtom.h"
michael@0 17 #include "nsCycleCollectionParticipant.h"
michael@0 18 #include "nsTArray.h"
michael@0 19 #include "nsIPrincipal.h"
michael@0 20 #include "nsIXPConnect.h"
michael@0 21 #include "nsDataHashtable.h"
michael@0 22 #include "nsClassHashtable.h"
michael@0 23 #include "mozilla/Services.h"
michael@0 24 #include "nsIObserverService.h"
michael@0 25 #include "nsThreadUtils.h"
michael@0 26 #include "nsWeakPtr.h"
michael@0 27 #include "mozilla/Attributes.h"
michael@0 28 #include "js/RootingAPI.h"
michael@0 29 #include "nsTObserverArray.h"
michael@0 30 #include "mozilla/dom/StructuredCloneUtils.h"
michael@0 31
michael@0 32 namespace mozilla {
michael@0 33 namespace dom {
michael@0 34
michael@0 35 class ContentParent;
michael@0 36 class ContentChild;
michael@0 37 class ClonedMessageData;
michael@0 38 class MessageManagerReporter;
michael@0 39
michael@0 40 namespace ipc {
michael@0 41
michael@0 42 enum MessageManagerFlags {
michael@0 43 MM_CHILD = 0,
michael@0 44 MM_CHROME = 1,
michael@0 45 MM_GLOBAL = 2,
michael@0 46 MM_PROCESSMANAGER = 4,
michael@0 47 MM_BROADCASTER = 8,
michael@0 48 MM_OWNSCALLBACK = 16
michael@0 49 };
michael@0 50
michael@0 51 class MessageManagerCallback
michael@0 52 {
michael@0 53 public:
michael@0 54 virtual ~MessageManagerCallback() {}
michael@0 55
michael@0 56 virtual bool DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
michael@0 57 {
michael@0 58 return true;
michael@0 59 }
michael@0 60
michael@0 61 virtual bool DoSendBlockingMessage(JSContext* aCx,
michael@0 62 const nsAString& aMessage,
michael@0 63 const StructuredCloneData& aData,
michael@0 64 JS::Handle<JSObject*> aCpows,
michael@0 65 nsIPrincipal* aPrincipal,
michael@0 66 InfallibleTArray<nsString>* aJSONRetVal,
michael@0 67 bool aIsSync)
michael@0 68 {
michael@0 69 return true;
michael@0 70 }
michael@0 71
michael@0 72 virtual bool DoSendAsyncMessage(JSContext* aCx,
michael@0 73 const nsAString& aMessage,
michael@0 74 const StructuredCloneData& aData,
michael@0 75 JS::Handle<JSObject*> aCpows,
michael@0 76 nsIPrincipal* aPrincipal)
michael@0 77 {
michael@0 78 return true;
michael@0 79 }
michael@0 80
michael@0 81 virtual bool CheckPermission(const nsAString& aPermission)
michael@0 82 {
michael@0 83 return false;
michael@0 84 }
michael@0 85
michael@0 86 virtual bool CheckManifestURL(const nsAString& aManifestURL)
michael@0 87 {
michael@0 88 return false;
michael@0 89 }
michael@0 90
michael@0 91 virtual bool CheckAppHasPermission(const nsAString& aPermission)
michael@0 92 {
michael@0 93 return false;
michael@0 94 }
michael@0 95
michael@0 96 virtual bool CheckAppHasStatus(unsigned short aStatus)
michael@0 97 {
michael@0 98 return false;
michael@0 99 }
michael@0 100
michael@0 101 protected:
michael@0 102 bool BuildClonedMessageDataForParent(ContentParent* aParent,
michael@0 103 const StructuredCloneData& aData,
michael@0 104 ClonedMessageData& aClonedData);
michael@0 105 bool BuildClonedMessageDataForChild(ContentChild* aChild,
michael@0 106 const StructuredCloneData& aData,
michael@0 107 ClonedMessageData& aClonedData);
michael@0 108 };
michael@0 109
michael@0 110 StructuredCloneData UnpackClonedMessageDataForParent(const ClonedMessageData& aData);
michael@0 111 StructuredCloneData UnpackClonedMessageDataForChild(const ClonedMessageData& aData);
michael@0 112
michael@0 113 } // namespace ipc
michael@0 114 } // namespace dom
michael@0 115 } // namespace mozilla
michael@0 116
michael@0 117 class nsAXPCNativeCallContext;
michael@0 118
michael@0 119 struct nsMessageListenerInfo
michael@0 120 {
michael@0 121 bool operator==(const nsMessageListenerInfo& aOther) const
michael@0 122 {
michael@0 123 return &aOther == this;
michael@0 124 }
michael@0 125
michael@0 126 // Exactly one of mStrongListener and mWeakListener must be non-null.
michael@0 127 nsCOMPtr<nsIMessageListener> mStrongListener;
michael@0 128 nsWeakPtr mWeakListener;
michael@0 129 };
michael@0 130
michael@0 131 class CpowHolder
michael@0 132 {
michael@0 133 public:
michael@0 134 virtual bool ToObject(JSContext* cx, JS::MutableHandle<JSObject*> objp) = 0;
michael@0 135 };
michael@0 136
michael@0 137 class MOZ_STACK_CLASS SameProcessCpowHolder : public CpowHolder
michael@0 138 {
michael@0 139 public:
michael@0 140 SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject*> aObj)
michael@0 141 : mObj(aRuntime, aObj)
michael@0 142 {
michael@0 143 }
michael@0 144
michael@0 145 bool ToObject(JSContext* aCx, JS::MutableHandle<JSObject*> aObjp);
michael@0 146
michael@0 147 private:
michael@0 148 JS::Rooted<JSObject*> mObj;
michael@0 149 };
michael@0 150
michael@0 151 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
michael@0 152 public nsIMessageBroadcaster,
michael@0 153 public nsIFrameScriptLoader,
michael@0 154 public nsIProcessChecker
michael@0 155 {
michael@0 156 friend class mozilla::dom::MessageManagerReporter;
michael@0 157 typedef mozilla::dom::StructuredCloneData StructuredCloneData;
michael@0 158 public:
michael@0 159 nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
michael@0 160 nsFrameMessageManager* aParentManager,
michael@0 161 /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
michael@0 162 : mChrome(!!(aFlags & mozilla::dom::ipc::MM_CHROME)),
michael@0 163 mGlobal(!!(aFlags & mozilla::dom::ipc::MM_GLOBAL)),
michael@0 164 mIsProcessManager(!!(aFlags & mozilla::dom::ipc::MM_PROCESSMANAGER)),
michael@0 165 mIsBroadcaster(!!(aFlags & mozilla::dom::ipc::MM_BROADCASTER)),
michael@0 166 mOwnsCallback(!!(aFlags & mozilla::dom::ipc::MM_OWNSCALLBACK)),
michael@0 167 mHandlingMessage(false),
michael@0 168 mDisconnected(false),
michael@0 169 mCallback(aCallback),
michael@0 170 mParentManager(aParentManager)
michael@0 171 {
michael@0 172 NS_ASSERTION(mChrome || !aParentManager, "Should not set parent manager!");
michael@0 173 NS_ASSERTION(!mIsBroadcaster || !mCallback,
michael@0 174 "Broadcasters cannot have callbacks!");
michael@0 175 // This is a bit hackish. When parent manager is global, we want
michael@0 176 // to attach the window message manager to it immediately.
michael@0 177 // Is it just the frame message manager which waits until the
michael@0 178 // content process is running.
michael@0 179 if (mParentManager && (mCallback || IsWindowLevel())) {
michael@0 180 mParentManager->AddChildManager(this);
michael@0 181 }
michael@0 182 if (mOwnsCallback) {
michael@0 183 mOwnedCallback = aCallback;
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 ~nsFrameMessageManager()
michael@0 188 {
michael@0 189 for (int32_t i = mChildManagers.Count(); i > 0; --i) {
michael@0 190 static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
michael@0 191 Disconnect(false);
michael@0 192 }
michael@0 193 if (mIsProcessManager) {
michael@0 194 if (this == sParentProcessManager) {
michael@0 195 sParentProcessManager = nullptr;
michael@0 196 }
michael@0 197 if (this == sChildProcessManager) {
michael@0 198 sChildProcessManager = nullptr;
michael@0 199 delete sPendingSameProcessAsyncMessages;
michael@0 200 sPendingSameProcessAsyncMessages = nullptr;
michael@0 201 }
michael@0 202 if (this == sSameProcessParentManager) {
michael@0 203 sSameProcessParentManager = nullptr;
michael@0 204 }
michael@0 205 }
michael@0 206 }
michael@0 207
michael@0 208 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
michael@0 209 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameMessageManager,
michael@0 210 nsIContentFrameMessageManager)
michael@0 211 NS_DECL_NSIMESSAGELISTENERMANAGER
michael@0 212 NS_DECL_NSIMESSAGESENDER
michael@0 213 NS_DECL_NSIMESSAGEBROADCASTER
michael@0 214 NS_DECL_NSISYNCMESSAGESENDER
michael@0 215 NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
michael@0 216 NS_DECL_NSIFRAMESCRIPTLOADER
michael@0 217 NS_DECL_NSIPROCESSCHECKER
michael@0 218
michael@0 219 static nsFrameMessageManager*
michael@0 220 NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
michael@0 221
michael@0 222 nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
michael@0 223 bool aIsSync, const StructuredCloneData* aCloneData,
michael@0 224 CpowHolder* aCpows, nsIPrincipal* aPrincipal,
michael@0 225 InfallibleTArray<nsString>* aJSONRetVal);
michael@0 226
michael@0 227 void AddChildManager(nsFrameMessageManager* aManager);
michael@0 228 void RemoveChildManager(nsFrameMessageManager* aManager)
michael@0 229 {
michael@0 230 mChildManagers.RemoveObject(aManager);
michael@0 231 }
michael@0 232 void Disconnect(bool aRemoveFromParent = true);
michael@0 233
michael@0 234 void InitWithCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
michael@0 235 void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
michael@0 236 mozilla::dom::ipc::MessageManagerCallback* GetCallback()
michael@0 237 {
michael@0 238 return mCallback;
michael@0 239 }
michael@0 240
michael@0 241 nsresult DispatchAsyncMessage(const nsAString& aMessageName,
michael@0 242 const JS::Value& aJSON,
michael@0 243 const JS::Value& aObjects,
michael@0 244 nsIPrincipal* aPrincipal,
michael@0 245 JSContext* aCx,
michael@0 246 uint8_t aArgc);
michael@0 247 nsresult DispatchAsyncMessageInternal(JSContext* aCx,
michael@0 248 const nsAString& aMessage,
michael@0 249 const StructuredCloneData& aData,
michael@0 250 JS::Handle<JSObject*> aCpows,
michael@0 251 nsIPrincipal* aPrincipal);
michael@0 252 void RemoveFromParent();
michael@0 253 nsFrameMessageManager* GetParentManager() { return mParentManager; }
michael@0 254 void SetParentManager(nsFrameMessageManager* aParent)
michael@0 255 {
michael@0 256 NS_ASSERTION(!mParentManager, "We have parent manager already!");
michael@0 257 NS_ASSERTION(mChrome, "Should not set parent manager!");
michael@0 258 mParentManager = aParent;
michael@0 259 }
michael@0 260 bool IsGlobal() { return mGlobal; }
michael@0 261 bool IsWindowLevel() { return mParentManager && mParentManager->IsGlobal(); }
michael@0 262
michael@0 263 static nsFrameMessageManager* GetParentProcessManager()
michael@0 264 {
michael@0 265 return sParentProcessManager;
michael@0 266 }
michael@0 267 static nsFrameMessageManager* GetChildProcessManager()
michael@0 268 {
michael@0 269 return sChildProcessManager;
michael@0 270 }
michael@0 271 private:
michael@0 272 nsresult SendMessage(const nsAString& aMessageName,
michael@0 273 JS::Handle<JS::Value> aJSON,
michael@0 274 JS::Handle<JS::Value> aObjects,
michael@0 275 nsIPrincipal* aPrincipal,
michael@0 276 JSContext* aCx,
michael@0 277 uint8_t aArgc,
michael@0 278 JS::MutableHandle<JS::Value> aRetval,
michael@0 279 bool aIsSync);
michael@0 280 protected:
michael@0 281 friend class MMListenerRemover;
michael@0 282 // We keep the message listeners as arrays in a hastable indexed by the
michael@0 283 // message name. That gives us fast lookups in ReceiveMessage().
michael@0 284 nsClassHashtable<nsStringHashKey,
michael@0 285 nsAutoTObserverArray<nsMessageListenerInfo, 1>> mListeners;
michael@0 286 nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
michael@0 287 bool mChrome; // true if we're in the chrome process
michael@0 288 bool mGlobal; // true if we're the global frame message manager
michael@0 289 bool mIsProcessManager; // true if the message manager belongs to the process realm
michael@0 290 bool mIsBroadcaster; // true if the message manager is a broadcaster
michael@0 291 bool mOwnsCallback;
michael@0 292 bool mHandlingMessage;
michael@0 293 bool mDisconnected;
michael@0 294 mozilla::dom::ipc::MessageManagerCallback* mCallback;
michael@0 295 nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
michael@0 296 nsFrameMessageManager* mParentManager;
michael@0 297 nsTArray<nsString> mPendingScripts;
michael@0 298 nsTArray<bool> mPendingScriptsGlobalStates;
michael@0 299 public:
michael@0 300 static nsFrameMessageManager* sParentProcessManager;
michael@0 301 static nsFrameMessageManager* sChildProcessManager;
michael@0 302 static nsFrameMessageManager* sSameProcessParentManager;
michael@0 303 static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
michael@0 304 private:
michael@0 305 enum ProcessCheckerType {
michael@0 306 PROCESS_CHECKER_PERMISSION,
michael@0 307 PROCESS_CHECKER_MANIFEST_URL,
michael@0 308 ASSERT_APP_HAS_PERMISSION
michael@0 309 };
michael@0 310 nsresult AssertProcessInternal(ProcessCheckerType aType,
michael@0 311 const nsAString& aCapability,
michael@0 312 bool* aValid);
michael@0 313 };
michael@0 314
michael@0 315 /* A helper class for taking care of many details for async message sending
michael@0 316 within a single process. Intended to be used like so:
michael@0 317
michael@0 318 class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public nsRunnable
michael@0 319 {
michael@0 320 // Initialize nsSameProcessAsyncMessageBase...
michael@0 321
michael@0 322 NS_IMETHOD Run() {
michael@0 323 ReceiveMessage(..., ...);
michael@0 324 return NS_OK;
michael@0 325 }
michael@0 326 };
michael@0 327 */
michael@0 328 class nsSameProcessAsyncMessageBase
michael@0 329 {
michael@0 330 typedef mozilla::dom::StructuredCloneClosure StructuredCloneClosure;
michael@0 331
michael@0 332 public:
michael@0 333 typedef mozilla::dom::StructuredCloneData StructuredCloneData;
michael@0 334
michael@0 335 nsSameProcessAsyncMessageBase(JSContext* aCx,
michael@0 336 const nsAString& aMessage,
michael@0 337 const StructuredCloneData& aData,
michael@0 338 JS::Handle<JSObject*> aCpows,
michael@0 339 nsIPrincipal* aPrincipal);
michael@0 340
michael@0 341 void ReceiveMessage(nsISupports* aTarget, nsFrameMessageManager* aManager);
michael@0 342
michael@0 343 private:
michael@0 344 nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
michael@0 345
michael@0 346 JSRuntime* mRuntime;
michael@0 347 nsString mMessage;
michael@0 348 JSAutoStructuredCloneBuffer mData;
michael@0 349 StructuredCloneClosure mClosure;
michael@0 350 JS::PersistentRooted<JSObject*> mCpows;
michael@0 351 nsCOMPtr<nsIPrincipal> mPrincipal;
michael@0 352 };
michael@0 353
michael@0 354 class nsScriptCacheCleaner;
michael@0 355
michael@0 356 struct nsFrameScriptObjectExecutorHolder
michael@0 357 {
michael@0 358 nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript)
michael@0 359 : mScript(aCx, aScript), mFunction(aCx, nullptr)
michael@0 360 { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
michael@0 361
michael@0 362 nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSObject* aFunction)
michael@0 363 : mScript(aCx, nullptr), mFunction(aCx, aFunction)
michael@0 364 { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
michael@0 365
michael@0 366 ~nsFrameScriptObjectExecutorHolder()
michael@0 367 { MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder); }
michael@0 368
michael@0 369 bool WillRunInGlobalScope() { return mScript; }
michael@0 370
michael@0 371 JS::PersistentRooted<JSScript*> mScript;
michael@0 372 JS::PersistentRooted<JSObject*> mFunction;
michael@0 373 };
michael@0 374
michael@0 375 class nsFrameScriptObjectExecutorStackHolder;
michael@0 376
michael@0 377 class nsFrameScriptExecutor
michael@0 378 {
michael@0 379 public:
michael@0 380 static void Shutdown();
michael@0 381 already_AddRefed<nsIXPConnectJSObjectHolder> GetGlobal()
michael@0 382 {
michael@0 383 nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mGlobal;
michael@0 384 return ref.forget();
michael@0 385 }
michael@0 386 protected:
michael@0 387 friend class nsFrameScriptCx;
michael@0 388 nsFrameScriptExecutor()
michael@0 389 { MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
michael@0 390 ~nsFrameScriptExecutor()
michael@0 391 { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
michael@0 392 void DidCreateGlobal();
michael@0 393 void LoadFrameScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
michael@0 394 void TryCacheLoadAndCompileScript(const nsAString& aURL,
michael@0 395 bool aRunInGlobalScope,
michael@0 396 bool aShouldCache,
michael@0 397 JS::MutableHandle<JSScript*> aScriptp,
michael@0 398 JS::MutableHandle<JSObject*> aFunp);
michael@0 399 void TryCacheLoadAndCompileScript(const nsAString& aURL,
michael@0 400 bool aRunInGlobalScope);
michael@0 401 bool InitTabChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
michael@0 402 nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
michael@0 403 nsCOMPtr<nsIPrincipal> mPrincipal;
michael@0 404 static nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>* sCachedScripts;
michael@0 405 static nsScriptCacheCleaner* sScriptCacheCleaner;
michael@0 406 };
michael@0 407
michael@0 408 class nsScriptCacheCleaner MOZ_FINAL : public nsIObserver
michael@0 409 {
michael@0 410 NS_DECL_ISUPPORTS
michael@0 411
michael@0 412 nsScriptCacheCleaner()
michael@0 413 {
michael@0 414 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
michael@0 415 if (obsSvc)
michael@0 416 obsSvc->AddObserver(this, "xpcom-shutdown", false);
michael@0 417 }
michael@0 418
michael@0 419 NS_IMETHODIMP Observe(nsISupports *aSubject,
michael@0 420 const char *aTopic,
michael@0 421 const char16_t *aData)
michael@0 422 {
michael@0 423 nsFrameScriptExecutor::Shutdown();
michael@0 424 return NS_OK;
michael@0 425 }
michael@0 426 };
michael@0 427
michael@0 428 #endif

mercurial