InProcessBrowserChildMessageManager.cpp (9237B)
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/. */ 6 7 #include "InProcessBrowserChildMessageManager.h" 8 9 #include "mozilla/EventDispatcher.h" 10 #include "mozilla/HoldDropJSObjects.h" 11 #include "mozilla/dom/ChromeMessageSender.h" 12 #include "mozilla/dom/Document.h" 13 #include "mozilla/dom/JSActorService.h" 14 #include "mozilla/dom/MessageManagerBinding.h" 15 #include "mozilla/dom/SameProcessMessageQueue.h" 16 #include "mozilla/dom/ScriptLoader.h" 17 #include "mozilla/dom/WindowProxyHolder.h" 18 #include "nsComponentManagerUtils.h" 19 #include "nsContentUtils.h" 20 #include "nsDocShell.h" 21 #include "nsFrameLoader.h" 22 #include "nsFrameLoaderOwner.h" 23 #include "nsIInterfaceRequestorUtils.h" 24 #include "nsQueryObject.h" 25 #include "xpcpublic.h" 26 27 using namespace mozilla; 28 using namespace mozilla::dom; 29 using namespace mozilla::dom::ipc; 30 31 /* static */ 32 already_AddRefed<InProcessBrowserChildMessageManager> 33 InProcessBrowserChildMessageManager::Create(nsDocShell* aShell, 34 nsIContent* aOwner, 35 nsFrameMessageManager* aChrome) { 36 RefPtr<InProcessBrowserChildMessageManager> mm = 37 new InProcessBrowserChildMessageManager(aShell, aOwner, aChrome); 38 39 NS_ENSURE_TRUE(mm->Init(), nullptr); 40 41 if (XRE_IsParentProcess()) { 42 RefPtr<JSActorService> wasvc = JSActorService::GetSingleton(); 43 wasvc->RegisterChromeEventTarget(mm); 44 } 45 46 return mm.forget(); 47 } 48 49 bool InProcessBrowserChildMessageManager::DoSendBlockingMessage( 50 const nsAString& aMessage, StructuredCloneData& aData, 51 nsTArray<UniquePtr<StructuredCloneData>>* aRetVal) { 52 SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); 53 queue->Flush(); 54 55 if (mChromeMessageManager) { 56 RefPtr<nsFrameMessageManager> mm = mChromeMessageManager; 57 RefPtr<nsFrameLoader> fl = GetFrameLoader(); 58 mm->ReceiveMessage(mOwner, fl, aMessage, true, &aData, aRetVal, 59 IgnoreErrors()); 60 } 61 return true; 62 } 63 64 class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase, 65 public SameProcessMessageQueue::Runnable { 66 public: 67 explicit nsAsyncMessageToParent( 68 InProcessBrowserChildMessageManager* aBrowserChild) 69 : mBrowserChild(aBrowserChild) {} 70 71 virtual nsresult HandleMessage() override { 72 RefPtr<nsFrameLoader> fl = mBrowserChild->GetFrameLoader(); 73 ReceiveMessage(mBrowserChild->mOwner, fl, 74 mBrowserChild->mChromeMessageManager); 75 return NS_OK; 76 } 77 RefPtr<InProcessBrowserChildMessageManager> mBrowserChild; 78 }; 79 80 nsresult InProcessBrowserChildMessageManager::DoSendAsyncMessage( 81 const nsAString& aMessage, StructuredCloneData& aData) { 82 SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); 83 RefPtr<nsAsyncMessageToParent> ev = new nsAsyncMessageToParent(this); 84 85 nsresult rv = ev->Init(aMessage, aData); 86 if (NS_FAILED(rv)) { 87 return rv; 88 } 89 90 queue->Push(ev); 91 return NS_OK; 92 } 93 94 InProcessBrowserChildMessageManager::InProcessBrowserChildMessageManager( 95 nsDocShell* aShell, nsIContent* aOwner, nsFrameMessageManager* aChrome) 96 : ContentFrameMessageManager(new nsFrameMessageManager(this)), 97 mDocShell(aShell), 98 mLoadingScript(false), 99 mPreventEventsEscaping(false), 100 mOwner(aOwner), 101 mChromeMessageManager(aChrome) { 102 mozilla::HoldJSObjects(this); 103 } 104 105 InProcessBrowserChildMessageManager::~InProcessBrowserChildMessageManager() { 106 if (XRE_IsParentProcess()) { 107 JSActorService::UnregisterChromeEventTarget(this); 108 } 109 110 mozilla::DropJSObjects(this); 111 } 112 113 // This method isn't automatically forwarded safely because it's notxpcom, so 114 // the IDL binding doesn't know what value to return. 115 void InProcessBrowserChildMessageManager::MarkForCC() { 116 MarkScopesForCC(); 117 MessageManagerGlobal::MarkForCC(); 118 } 119 120 NS_IMPL_CYCLE_COLLECTION_CLASS(InProcessBrowserChildMessageManager) 121 122 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED( 123 InProcessBrowserChildMessageManager, DOMEventTargetHelper) 124 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager) 125 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell) 126 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 127 128 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED( 129 InProcessBrowserChildMessageManager, DOMEventTargetHelper) 130 tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure); 131 NS_IMPL_CYCLE_COLLECTION_TRACE_END 132 133 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED( 134 InProcessBrowserChildMessageManager, DOMEventTargetHelper) 135 if (XRE_IsParentProcess()) { 136 JSActorService::UnregisterChromeEventTarget(tmp); 137 } 138 139 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager) 140 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell) 141 tmp->nsMessageManagerScriptExecutor::Unlink(); 142 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE 143 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 144 145 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InProcessBrowserChildMessageManager) 146 NS_INTERFACE_MAP_ENTRY(nsIMessageSender) 147 NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager) 148 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager) 149 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 150 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 151 152 NS_IMPL_ADDREF_INHERITED(InProcessBrowserChildMessageManager, 153 DOMEventTargetHelper) 154 NS_IMPL_RELEASE_INHERITED(InProcessBrowserChildMessageManager, 155 DOMEventTargetHelper) 156 157 JSObject* InProcessBrowserChildMessageManager::WrapObject( 158 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 159 return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto); 160 } 161 162 void InProcessBrowserChildMessageManager::CacheFrameLoader( 163 nsFrameLoader* aFrameLoader) { 164 mFrameLoader = aFrameLoader; 165 } 166 167 Nullable<WindowProxyHolder> InProcessBrowserChildMessageManager::GetContent( 168 ErrorResult& aError) { 169 if (!mDocShell) { 170 return nullptr; 171 } 172 return WindowProxyHolder(mDocShell->GetBrowsingContext()); 173 } 174 175 already_AddRefed<nsIEventTarget> 176 InProcessBrowserChildMessageManager::GetTabEventTarget() { 177 nsCOMPtr<nsIEventTarget> target = GetMainThreadSerialEventTarget(); 178 return target.forget(); 179 } 180 181 void InProcessBrowserChildMessageManager::FireUnloadEvent() { 182 // We're called from Document::MaybeInitializeFinalizeFrameLoaders, so it 183 // should be safe to run script. 184 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); 185 186 // Don't let the unload event propagate to chrome event handlers. 187 mPreventEventsEscaping = true; 188 DOMEventTargetHelper::DispatchTrustedEvent(u"unload"_ns); 189 190 // Allow events fired during docshell destruction (pagehide, unload) to 191 // propagate to the <browser> element since chrome code depends on this. 192 mPreventEventsEscaping = false; 193 } 194 195 void InProcessBrowserChildMessageManager::DisconnectEventListeners() { 196 if (mDocShell) { 197 if (nsCOMPtr<nsPIDOMWindowOuter> win = mDocShell->GetWindow()) { 198 win->SetChromeEventHandler(win->GetChromeEventHandler()); 199 } 200 } 201 if (mListenerManager) { 202 mListenerManager->Disconnect(); 203 } 204 205 mDocShell = nullptr; 206 } 207 208 void InProcessBrowserChildMessageManager::Disconnect() { 209 mChromeMessageManager = nullptr; 210 mOwner = nullptr; 211 if (mMessageManager) { 212 static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect(); 213 mMessageManager = nullptr; 214 } 215 } 216 217 NS_IMETHODIMP_(nsIContent*) 218 InProcessBrowserChildMessageManager::GetOwnerContent() { return mOwner; } 219 220 void InProcessBrowserChildMessageManager::GetEventTargetParent( 221 EventChainPreVisitor& aVisitor) { 222 aVisitor.mForceContentDispatch = true; 223 aVisitor.mCanHandle = true; 224 225 if (mPreventEventsEscaping) { 226 aVisitor.SetParentTarget(nullptr, false); 227 return; 228 } 229 230 aVisitor.SetParentTarget(mOwner, false); 231 } 232 233 class nsAsyncScriptLoad : public Runnable { 234 public: 235 nsAsyncScriptLoad(InProcessBrowserChildMessageManager* aBrowserChild, 236 const nsAString& aURL, bool aRunInGlobalScope) 237 : mozilla::Runnable("nsAsyncScriptLoad"), 238 mBrowserChild(aBrowserChild), 239 mURL(aURL), 240 mRunInGlobalScope(aRunInGlobalScope) {} 241 242 NS_IMETHOD Run() override { 243 mBrowserChild->LoadFrameScript(mURL, mRunInGlobalScope); 244 return NS_OK; 245 } 246 RefPtr<InProcessBrowserChildMessageManager> mBrowserChild; 247 nsString mURL; 248 bool mRunInGlobalScope; 249 }; 250 251 void InProcessBrowserChildMessageManager::LoadFrameScript( 252 const nsAString& aURL, bool aRunInGlobalScope) { 253 if (!nsContentUtils::IsSafeToRunScript()) { 254 nsContentUtils::AddScriptRunner( 255 new nsAsyncScriptLoad(this, aURL, aRunInGlobalScope)); 256 return; 257 } 258 bool tmp = mLoadingScript; 259 mLoadingScript = true; 260 JS::Rooted<JSObject*> mm(mozilla::dom::RootingCx(), GetOrCreateWrapper()); 261 LoadScriptInternal(mm, aURL, !aRunInGlobalScope); 262 mLoadingScript = tmp; 263 } 264 265 already_AddRefed<nsFrameLoader> 266 InProcessBrowserChildMessageManager::GetFrameLoader() { 267 RefPtr<nsFrameLoaderOwner> owner = do_QueryObject(mOwner); 268 RefPtr<nsFrameLoader> fl = owner ? owner->GetFrameLoader() : nullptr; 269 if (!fl) { 270 fl = mFrameLoader; 271 } 272 return fl.forget(); 273 }