summaryrefslogtreecommitdiffstats
path: root/dom/base/nsFrameMessageManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsFrameMessageManager.h')
-rw-r--r--dom/base/nsFrameMessageManager.h450
1 files changed, 450 insertions, 0 deletions
diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h
new file mode 100644
index 000000000..077389a49
--- /dev/null
+++ b/dom/base/nsFrameMessageManager.h
@@ -0,0 +1,450 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsFrameMessageManager_h__
+#define nsFrameMessageManager_h__
+
+#include "nsIMessageManager.h"
+#include "nsIObserver.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+#include "nsTArray.h"
+#include "nsIAtom.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsTArray.h"
+#include "nsIPrincipal.h"
+#include "nsIXPConnect.h"
+#include "nsDataHashtable.h"
+#include "nsClassHashtable.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIObserverService.h"
+#include "nsThreadUtils.h"
+#include "nsWeakPtr.h"
+#include "mozilla/Attributes.h"
+#include "js/RootingAPI.h"
+#include "nsTObserverArray.h"
+#include "mozilla/dom/SameProcessMessageQueue.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
+#include "mozilla/jsipc/CpowHolder.h"
+
+class nsIFrameLoader;
+
+namespace mozilla {
+namespace dom {
+
+class nsIContentParent;
+class nsIContentChild;
+class ClonedMessageData;
+class MessageManagerReporter;
+
+namespace ipc {
+
+enum MessageManagerFlags {
+ MM_CHILD = 0,
+ MM_CHROME = 1,
+ MM_GLOBAL = 2,
+ MM_PROCESSMANAGER = 4,
+ MM_BROADCASTER = 8,
+ MM_OWNSCALLBACK = 16
+};
+
+class MessageManagerCallback
+{
+public:
+ virtual ~MessageManagerCallback() {}
+
+ virtual bool DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
+ {
+ return true;
+ }
+
+ virtual bool DoSendBlockingMessage(JSContext* aCx,
+ const nsAString& aMessage,
+ StructuredCloneData& aData,
+ JS::Handle<JSObject*> aCpows,
+ nsIPrincipal* aPrincipal,
+ nsTArray<StructuredCloneData>* aRetVal,
+ bool aIsSync)
+ {
+ return true;
+ }
+
+ virtual nsresult DoSendAsyncMessage(JSContext* aCx,
+ const nsAString& aMessage,
+ StructuredCloneData& aData,
+ JS::Handle<JSObject*> aCpows,
+ nsIPrincipal* aPrincipal)
+ {
+ return NS_OK;
+ }
+
+ virtual bool CheckPermission(const nsAString& aPermission)
+ {
+ return false;
+ }
+
+ virtual bool CheckManifestURL(const nsAString& aManifestURL)
+ {
+ return false;
+ }
+
+ virtual bool CheckAppHasPermission(const nsAString& aPermission)
+ {
+ return false;
+ }
+
+ virtual bool CheckAppHasStatus(unsigned short aStatus)
+ {
+ return false;
+ }
+
+ virtual bool KillChild()
+ {
+ // By default, does nothing.
+ return false;
+ }
+
+ virtual nsIMessageSender* GetProcessMessageManager() const
+ {
+ return nullptr;
+ }
+
+protected:
+ bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
+ StructuredCloneData& aData,
+ ClonedMessageData& aClonedData);
+ bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
+ StructuredCloneData& aData,
+ ClonedMessageData& aClonedData);
+};
+
+void UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
+ StructuredCloneData& aData);
+
+void UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
+ StructuredCloneData& aData);
+
+} // namespace ipc
+} // namespace dom
+} // namespace mozilla
+
+struct nsMessageListenerInfo
+{
+ bool operator==(const nsMessageListenerInfo& aOther) const
+ {
+ return &aOther == this;
+ }
+
+ // Exactly one of mStrongListener and mWeakListener must be non-null.
+ nsCOMPtr<nsIMessageListener> mStrongListener;
+ nsWeakPtr mWeakListener;
+ bool mListenWhenClosed;
+};
+
+
+class MOZ_STACK_CLASS SameProcessCpowHolder : public mozilla::jsipc::CpowHolder
+{
+public:
+ SameProcessCpowHolder(JS::RootingContext* aRootingCx, JS::Handle<JSObject*> aObj)
+ : mObj(aRootingCx, aObj)
+ {
+ }
+
+ virtual bool ToObject(JSContext* aCx, JS::MutableHandle<JSObject*> aObjp)
+ override;
+
+private:
+ JS::Rooted<JSObject*> mObj;
+};
+
+class nsFrameMessageManager final : public nsIContentFrameMessageManager,
+ public nsIMessageBroadcaster,
+ public nsIFrameScriptLoader,
+ public nsIGlobalProcessScriptLoader,
+ public nsIProcessChecker
+{
+ friend class mozilla::dom::MessageManagerReporter;
+ typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
+public:
+ nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
+ nsFrameMessageManager* aParentManager,
+ /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags);
+
+private:
+ ~nsFrameMessageManager();
+
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFrameMessageManager,
+ nsIContentFrameMessageManager)
+ NS_DECL_NSIMESSAGELISTENERMANAGER
+ NS_DECL_NSIMESSAGESENDER
+ NS_DECL_NSIMESSAGEBROADCASTER
+ NS_DECL_NSISYNCMESSAGESENDER
+ NS_DECL_NSIMESSAGEMANAGERGLOBAL
+ NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
+ NS_DECL_NSIFRAMESCRIPTLOADER
+ NS_DECL_NSIPROCESSSCRIPTLOADER
+ NS_DECL_NSIGLOBALPROCESSSCRIPTLOADER
+ NS_DECL_NSIPROCESSCHECKER
+
+ static nsFrameMessageManager*
+ NewProcessMessageManager(bool aIsRemote);
+
+ nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
+ const nsAString& aMessage,
+ bool aIsSync, StructuredCloneData* aCloneData,
+ mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
+ nsTArray<StructuredCloneData>* aRetVal);
+
+ void AddChildManager(nsFrameMessageManager* aManager);
+ void RemoveChildManager(nsFrameMessageManager* aManager)
+ {
+ mChildManagers.RemoveObject(aManager);
+ }
+ void Disconnect(bool aRemoveFromParent = true);
+ void Close();
+
+ void InitWithCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
+ void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
+
+ mozilla::dom::ipc::MessageManagerCallback* GetCallback()
+ {
+ return mCallback;
+ }
+
+ nsresult DispatchAsyncMessage(const nsAString& aMessageName,
+ const JS::Value& aJSON,
+ const JS::Value& aObjects,
+ nsIPrincipal* aPrincipal,
+ const JS::Value& aTransfers,
+ JSContext* aCx,
+ uint8_t aArgc);
+
+ nsresult DispatchAsyncMessageInternal(JSContext* aCx,
+ const nsAString& aMessage,
+ StructuredCloneData& aData,
+ JS::Handle<JSObject*> aCpows,
+ nsIPrincipal* aPrincipal);
+ void RemoveFromParent();
+ nsFrameMessageManager* GetParentManager() { return mParentManager; }
+ void SetParentManager(nsFrameMessageManager* aParent)
+ {
+ NS_ASSERTION(!mParentManager, "We have parent manager already!");
+ NS_ASSERTION(mChrome, "Should not set parent manager!");
+ mParentManager = aParent;
+ }
+ bool IsGlobal() { return mGlobal; }
+ bool IsBroadcaster() { return mIsBroadcaster; }
+
+ static nsFrameMessageManager* GetParentProcessManager()
+ {
+ return sParentProcessManager;
+ }
+ static nsFrameMessageManager* GetChildProcessManager()
+ {
+ return sChildProcessManager;
+ }
+ static void SetChildProcessManager(nsFrameMessageManager* aManager)
+ {
+ sChildProcessManager = aManager;
+ }
+
+ void SetInitialProcessData(JS::HandleValue aInitialData);
+
+ void LoadPendingScripts();
+
+private:
+ nsresult SendMessage(const nsAString& aMessageName,
+ JS::Handle<JS::Value> aJSON,
+ JS::Handle<JS::Value> aObjects,
+ nsIPrincipal* aPrincipal,
+ JSContext* aCx,
+ uint8_t aArgc,
+ JS::MutableHandle<JS::Value> aRetval,
+ bool aIsSync);
+
+ nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
+ bool aTargetClosed, const nsAString& aMessage,
+ bool aIsSync, StructuredCloneData* aCloneData,
+ mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
+ nsTArray<StructuredCloneData>* aRetVal);
+
+ NS_IMETHOD LoadScript(const nsAString& aURL,
+ bool aAllowDelayedLoad,
+ bool aRunInGlobalScope);
+ NS_IMETHOD RemoveDelayedScript(const nsAString& aURL);
+ NS_IMETHOD GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList);
+
+protected:
+ friend class MMListenerRemover;
+ // We keep the message listeners as arrays in a hastable indexed by the
+ // message name. That gives us fast lookups in ReceiveMessage().
+ nsClassHashtable<nsStringHashKey,
+ nsAutoTObserverArray<nsMessageListenerInfo, 1>> mListeners;
+ nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
+ bool mChrome; // true if we're in the chrome process
+ bool mGlobal; // true if we're the global frame message manager
+ bool mIsProcessManager; // true if the message manager belongs to the process realm
+ bool mIsBroadcaster; // true if the message manager is a broadcaster
+ bool mOwnsCallback;
+ bool mHandlingMessage;
+ bool mClosed; // true if we can no longer send messages
+ bool mDisconnected;
+ mozilla::dom::ipc::MessageManagerCallback* mCallback;
+ nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
+ RefPtr<nsFrameMessageManager> mParentManager;
+ nsTArray<nsString> mPendingScripts;
+ nsTArray<bool> mPendingScriptsGlobalStates;
+ JS::Heap<JS::Value> mInitialProcessData;
+
+ void LoadPendingScripts(nsFrameMessageManager* aManager,
+ nsFrameMessageManager* aChildMM);
+public:
+ static nsFrameMessageManager* sParentProcessManager;
+ static nsFrameMessageManager* sSameProcessParentManager;
+ static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
+private:
+ static nsFrameMessageManager* sChildProcessManager;
+ enum ProcessCheckerType {
+ PROCESS_CHECKER_PERMISSION,
+ PROCESS_CHECKER_MANIFEST_URL,
+ ASSERT_APP_HAS_PERMISSION
+ };
+ nsresult AssertProcessInternal(ProcessCheckerType aType,
+ const nsAString& aCapability,
+ bool* aValid);
+};
+
+/* A helper class for taking care of many details for async message sending
+ within a single process. Intended to be used like so:
+
+ class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public Runnable
+ {
+ NS_IMETHOD Run() override {
+ ReceiveMessage(..., ...);
+ return NS_OK;
+ }
+ };
+
+
+ RefPtr<nsSameProcessAsyncMessageBase> ev = new MyAsyncMessage();
+ nsresult rv = ev->Init(...);
+ if (NS_SUCCEEDED(rv)) {
+ NS_DispatchToMainThread(ev);
+ }
+*/
+class nsSameProcessAsyncMessageBase
+{
+public:
+ typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
+
+ nsSameProcessAsyncMessageBase(JS::RootingContext* aRootingCx,
+ JS::Handle<JSObject*> aCpows);
+ nsresult Init(const nsAString& aMessage,
+ StructuredCloneData& aData,
+ nsIPrincipal* aPrincipal);
+
+ void ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
+ nsFrameMessageManager* aManager);
+private:
+ nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
+
+ JS::RootingContext* mRootingCx;
+ nsString mMessage;
+ StructuredCloneData mData;
+ JS::PersistentRooted<JSObject*> mCpows;
+ nsCOMPtr<nsIPrincipal> mPrincipal;
+#ifdef DEBUG
+ bool mCalledInit;
+#endif
+};
+
+class nsScriptCacheCleaner;
+
+struct nsMessageManagerScriptHolder
+{
+ nsMessageManagerScriptHolder(JSContext* aCx,
+ JSScript* aScript,
+ bool aRunInGlobalScope)
+ : mScript(aCx, aScript), mRunInGlobalScope(aRunInGlobalScope)
+ { MOZ_COUNT_CTOR(nsMessageManagerScriptHolder); }
+
+ ~nsMessageManagerScriptHolder()
+ { MOZ_COUNT_DTOR(nsMessageManagerScriptHolder); }
+
+ bool WillRunInGlobalScope() { return mRunInGlobalScope; }
+
+ JS::PersistentRooted<JSScript*> mScript;
+ bool mRunInGlobalScope;
+};
+
+class nsMessageManagerScriptExecutor
+{
+public:
+ static void PurgeCache();
+ static void Shutdown();
+ already_AddRefed<nsIXPConnectJSObjectHolder> GetGlobal()
+ {
+ nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mGlobal;
+ return ref.forget();
+ }
+
+ void MarkScopesForCC();
+protected:
+ friend class nsMessageManagerScriptCx;
+ nsMessageManagerScriptExecutor() { MOZ_COUNT_CTOR(nsMessageManagerScriptExecutor); }
+ ~nsMessageManagerScriptExecutor() { MOZ_COUNT_DTOR(nsMessageManagerScriptExecutor); }
+
+ void DidCreateGlobal();
+ void LoadScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
+ void TryCacheLoadAndCompileScript(const nsAString& aURL,
+ bool aRunInGlobalScope,
+ bool aShouldCache,
+ JS::MutableHandle<JSScript*> aScriptp);
+ void TryCacheLoadAndCompileScript(const nsAString& aURL,
+ bool aRunInGlobalScope);
+ bool InitChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
+ void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
+ nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
+ nsCOMPtr<nsIPrincipal> mPrincipal;
+ AutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
+
+ static nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>* sCachedScripts;
+ static mozilla::StaticRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
+};
+
+class nsScriptCacheCleaner final : public nsIObserver
+{
+ ~nsScriptCacheCleaner() {}
+
+ NS_DECL_ISUPPORTS
+
+ nsScriptCacheCleaner()
+ {
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ if (obsSvc) {
+ obsSvc->AddObserver(this, "message-manager-flush-caches", false);
+ obsSvc->AddObserver(this, "xpcom-shutdown", false);
+ }
+ }
+
+ NS_IMETHOD Observe(nsISupports *aSubject,
+ const char *aTopic,
+ const char16_t *aData) override
+ {
+ if (strcmp("message-manager-flush-caches", aTopic) == 0) {
+ nsMessageManagerScriptExecutor::PurgeCache();
+ } else if (strcmp("xpcom-shutdown", aTopic) == 0) {
+ nsMessageManagerScriptExecutor::Shutdown();
+ }
+ return NS_OK;
+ }
+};
+
+#endif