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.)

     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"
    30 #include "mozilla/dom/StructuredCloneUtils.h"
    32 namespace mozilla {
    33 namespace dom {
    35 class ContentParent;
    36 class ContentChild;
    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
    49 };
    51 class MessageManagerCallback
    52 {
    53 public:
    54   virtual ~MessageManagerCallback() {}
    56   virtual bool DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
    57   {
    58     return true;
    59   }
    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)
    68   {
    69     return true;
    70   }
    72   virtual bool DoSendAsyncMessage(JSContext* aCx,
    73                                   const nsAString& aMessage,
    74                                   const StructuredCloneData& aData,
    75                                   JS::Handle<JSObject*> aCpows,
    76                                   nsIPrincipal* aPrincipal)
    77   {
    78     return true;
    79   }
    81   virtual bool CheckPermission(const nsAString& aPermission)
    82   {
    83     return false;
    84   }
    86   virtual bool CheckManifestURL(const nsAString& aManifestURL)
    87   {
    88     return false;
    89   }
    91   virtual bool CheckAppHasPermission(const nsAString& aPermission)
    92   {
    93     return false;
    94   }
    96   virtual bool CheckAppHasStatus(unsigned short aStatus)
    97   {
    98     return false;
    99   }
   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);
   108 };
   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
   120 {
   121   bool operator==(const nsMessageListenerInfo& aOther) const
   122   {
   123     return &aOther == this;
   124   }
   126   // Exactly one of mStrongListener and mWeakListener must be non-null.
   127   nsCOMPtr<nsIMessageListener> mStrongListener;
   128   nsWeakPtr mWeakListener;
   129 };
   131 class CpowHolder
   132 {
   133 public:
   134   virtual bool ToObject(JSContext* cx, JS::MutableHandle<JSObject*> objp) = 0;
   135 };
   137 class MOZ_STACK_CLASS SameProcessCpowHolder : public CpowHolder
   138 {
   139 public:
   140   SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject*> aObj)
   141     : mObj(aRuntime, aObj)
   142   {
   143   }
   145   bool ToObject(JSContext* aCx, JS::MutableHandle<JSObject*> aObjp);
   147 private:
   148   JS::Rooted<JSObject*> mObj;
   149 };
   151 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
   152                                         public nsIMessageBroadcaster,
   153                                         public nsIFrameScriptLoader,
   154                                         public nsIProcessChecker
   155 {
   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)
   171   {
   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);
   181     }
   182     if (mOwnsCallback) {
   183       mOwnedCallback = aCallback;
   184     }
   185   }
   187   ~nsFrameMessageManager()
   188   {
   189     for (int32_t i = mChildManagers.Count(); i > 0; --i) {
   190       static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
   191         Disconnect(false);
   192     }
   193     if (mIsProcessManager) {
   194       if (this == sParentProcessManager) {
   195         sParentProcessManager = nullptr;
   196       }
   197       if (this == sChildProcessManager) {
   198         sChildProcessManager = nullptr;
   199         delete sPendingSameProcessAsyncMessages;
   200         sPendingSameProcessAsyncMessages = nullptr;
   201       }
   202       if (this == sSameProcessParentManager) {
   203         sSameProcessParentManager = nullptr;
   204       }
   205     }
   206   }
   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   void RemoveChildManager(nsFrameMessageManager* aManager)
   229   {
   230     mChildManagers.RemoveObject(aManager);
   231   }
   232   void Disconnect(bool aRemoveFromParent = true);
   234   void InitWithCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
   235   void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
   236   mozilla::dom::ipc::MessageManagerCallback* GetCallback()
   237   {
   238     return mCallback;
   239   }
   241   nsresult DispatchAsyncMessage(const nsAString& aMessageName,
   242                                 const JS::Value& aJSON,
   243                                 const JS::Value& aObjects,
   244                                 nsIPrincipal* aPrincipal,
   245                                 JSContext* aCx,
   246                                 uint8_t aArgc);
   247   nsresult DispatchAsyncMessageInternal(JSContext* aCx,
   248                                         const nsAString& aMessage,
   249                                         const StructuredCloneData& aData,
   250                                         JS::Handle<JSObject*> aCpows,
   251                                         nsIPrincipal* aPrincipal);
   252   void RemoveFromParent();
   253   nsFrameMessageManager* GetParentManager() { return mParentManager; }
   254   void SetParentManager(nsFrameMessageManager* aParent)
   255   {
   256     NS_ASSERTION(!mParentManager, "We have parent manager already!");
   257     NS_ASSERTION(mChrome, "Should not set parent manager!");
   258     mParentManager = aParent;
   259   }
   260   bool IsGlobal() { return mGlobal; }
   261   bool IsWindowLevel() { return mParentManager && mParentManager->IsGlobal(); }
   263   static nsFrameMessageManager* GetParentProcessManager()
   264   {
   265     return sParentProcessManager;
   266   }
   267   static nsFrameMessageManager* GetChildProcessManager()
   268   {
   269     return sChildProcessManager;
   270   }
   271 private:
   272   nsresult SendMessage(const nsAString& aMessageName,
   273                        JS::Handle<JS::Value> aJSON,
   274                        JS::Handle<JS::Value> aObjects,
   275                        nsIPrincipal* aPrincipal,
   276                        JSContext* aCx,
   277                        uint8_t aArgc,
   278                        JS::MutableHandle<JS::Value> aRetval,
   279                        bool aIsSync);
   280 protected:
   281   friend class MMListenerRemover;
   282   // We keep the message listeners as arrays in a hastable indexed by the
   283   // message name. That gives us fast lookups in ReceiveMessage().
   284   nsClassHashtable<nsStringHashKey,
   285                    nsAutoTObserverArray<nsMessageListenerInfo, 1>> mListeners;
   286   nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
   287   bool mChrome;     // true if we're in the chrome process
   288   bool mGlobal;     // true if we're the global frame message manager
   289   bool mIsProcessManager; // true if the message manager belongs to the process realm
   290   bool mIsBroadcaster; // true if the message manager is a broadcaster
   291   bool mOwnsCallback;
   292   bool mHandlingMessage;
   293   bool mDisconnected;
   294   mozilla::dom::ipc::MessageManagerCallback* mCallback;
   295   nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
   296   nsFrameMessageManager* mParentManager;
   297   nsTArray<nsString> mPendingScripts;
   298   nsTArray<bool> mPendingScriptsGlobalStates;
   299 public:
   300   static nsFrameMessageManager* sParentProcessManager;
   301   static nsFrameMessageManager* sChildProcessManager;
   302   static nsFrameMessageManager* sSameProcessParentManager;
   303   static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
   304 private:
   305   enum ProcessCheckerType {
   306     PROCESS_CHECKER_PERMISSION,
   307     PROCESS_CHECKER_MANIFEST_URL,
   308     ASSERT_APP_HAS_PERMISSION
   309   };
   310   nsresult AssertProcessInternal(ProcessCheckerType aType,
   311                                  const nsAString& aCapability,
   312                                  bool* aValid);
   313 };
   315 /* A helper class for taking care of many details for async message sending
   316    within a single process.  Intended to be used like so:
   318    class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public nsRunnable
   319    {
   320      // Initialize nsSameProcessAsyncMessageBase...
   322      NS_IMETHOD Run() {
   323        ReceiveMessage(..., ...);
   324        return NS_OK;
   325      }
   326    };
   327  */
   328 class nsSameProcessAsyncMessageBase
   329 {
   330   typedef mozilla::dom::StructuredCloneClosure StructuredCloneClosure;
   332 public:
   333   typedef mozilla::dom::StructuredCloneData StructuredCloneData;
   335   nsSameProcessAsyncMessageBase(JSContext* aCx,
   336                                 const nsAString& aMessage,
   337                                 const StructuredCloneData& aData,
   338                                 JS::Handle<JSObject*> aCpows,
   339                                 nsIPrincipal* aPrincipal);
   341   void ReceiveMessage(nsISupports* aTarget, nsFrameMessageManager* aManager);
   343 private:
   344   nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
   346   JSRuntime* mRuntime;
   347   nsString mMessage;
   348   JSAutoStructuredCloneBuffer mData;
   349   StructuredCloneClosure mClosure;
   350   JS::PersistentRooted<JSObject*> mCpows;
   351   nsCOMPtr<nsIPrincipal> mPrincipal;
   352 };
   354 class nsScriptCacheCleaner;
   356 struct nsFrameScriptObjectExecutorHolder
   357 {
   358   nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript)
   359    : mScript(aCx, aScript), mFunction(aCx, nullptr)
   360   { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
   362   nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSObject* aFunction)
   363    : mScript(aCx, nullptr), mFunction(aCx, aFunction)
   364   { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
   366   ~nsFrameScriptObjectExecutorHolder()
   367   { MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder); }
   369   bool WillRunInGlobalScope() { return mScript; }
   371   JS::PersistentRooted<JSScript*> mScript;
   372   JS::PersistentRooted<JSObject*> mFunction;
   373 };
   375 class nsFrameScriptObjectExecutorStackHolder;
   377 class nsFrameScriptExecutor
   378 {
   379 public:
   380   static void Shutdown();
   381   already_AddRefed<nsIXPConnectJSObjectHolder> GetGlobal()
   382   {
   383     nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mGlobal;
   384     return ref.forget();
   385   }
   386 protected:
   387   friend class nsFrameScriptCx;
   388   nsFrameScriptExecutor()
   389   { MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
   390   ~nsFrameScriptExecutor()
   391   { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
   392   void DidCreateGlobal();
   393   void LoadFrameScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
   394   void TryCacheLoadAndCompileScript(const nsAString& aURL,
   395                                     bool aRunInGlobalScope,
   396                                     bool aShouldCache,
   397                                     JS::MutableHandle<JSScript*> aScriptp,
   398                                     JS::MutableHandle<JSObject*> aFunp);
   399   void TryCacheLoadAndCompileScript(const nsAString& aURL,
   400                                     bool aRunInGlobalScope);
   401   bool InitTabChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
   402   nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
   403   nsCOMPtr<nsIPrincipal> mPrincipal;
   404   static nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>* sCachedScripts;
   405   static nsScriptCacheCleaner* sScriptCacheCleaner;
   406 };
   408 class nsScriptCacheCleaner MOZ_FINAL : public nsIObserver
   409 {
   410   NS_DECL_ISUPPORTS
   412   nsScriptCacheCleaner()
   413   {
   414     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
   415     if (obsSvc)
   416       obsSvc->AddObserver(this, "xpcom-shutdown", false);
   417   }
   419   NS_IMETHODIMP Observe(nsISupports *aSubject,
   420                         const char *aTopic,
   421                         const char16_t *aData)
   422   {
   423     nsFrameScriptExecutor::Shutdown();
   424     return NS_OK;
   425   }
   426 };
   428 #endif

mercurial