1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/ipc/PluginModuleChild.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,455 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: sw=4 ts=4 et : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef dom_plugins_PluginModuleChild_h 1.11 +#define dom_plugins_PluginModuleChild_h 1 1.12 + 1.13 +#include "mozilla/Attributes.h" 1.14 + 1.15 +#include <string> 1.16 +#include <vector> 1.17 + 1.18 +#include "base/basictypes.h" 1.19 + 1.20 +#include "prlink.h" 1.21 + 1.22 +#include "npapi.h" 1.23 +#include "npfunctions.h" 1.24 + 1.25 +#include "nsAutoPtr.h" 1.26 +#include "nsDataHashtable.h" 1.27 +#include "nsTHashtable.h" 1.28 +#include "nsHashKeys.h" 1.29 + 1.30 +#ifdef MOZ_WIDGET_COCOA 1.31 +#include "PluginInterposeOSX.h" 1.32 +#endif 1.33 + 1.34 +#include "mozilla/plugins/PPluginModuleChild.h" 1.35 +#include "mozilla/plugins/PluginInstanceChild.h" 1.36 +#include "mozilla/plugins/PluginIdentifierChild.h" 1.37 +#include "mozilla/plugins/PluginMessageUtils.h" 1.38 + 1.39 +// NOTE: stolen from nsNPAPIPlugin.h 1.40 + 1.41 +#if defined(XP_WIN) 1.42 +#define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name) 1.43 +#else 1.44 +#define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name) 1.45 +#endif 1.46 + 1.47 +typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks); 1.48 +typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks); 1.49 +typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks); 1.50 +typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void); 1.51 + 1.52 +namespace mozilla { 1.53 +namespace dom { 1.54 +class PCrashReporterChild; 1.55 +} 1.56 + 1.57 +namespace plugins { 1.58 + 1.59 +#ifdef MOZ_WIDGET_QT 1.60 +class NestedLoopTimer; 1.61 +static const int kNestedLoopDetectorIntervalMs = 90; 1.62 +#endif 1.63 + 1.64 +class PluginScriptableObjectChild; 1.65 +class PluginInstanceChild; 1.66 + 1.67 +class PluginModuleChild : public PPluginModuleChild 1.68 +{ 1.69 + typedef mozilla::dom::PCrashReporterChild PCrashReporterChild; 1.70 +protected: 1.71 + virtual mozilla::ipc::RacyInterruptPolicy 1.72 + MediateInterruptRace(const Message& parent, const Message& child) MOZ_OVERRIDE 1.73 + { 1.74 + return MediateRace(parent, child); 1.75 + } 1.76 + 1.77 + virtual bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE; 1.78 + 1.79 + // Implement the PPluginModuleChild interface 1.80 + virtual bool AnswerNP_GetEntryPoints(NPError* rv) MOZ_OVERRIDE; 1.81 + virtual bool AnswerNP_Initialize(const uint32_t& aFlags, NPError* rv) MOZ_OVERRIDE; 1.82 + 1.83 + virtual PPluginIdentifierChild* 1.84 + AllocPPluginIdentifierChild(const nsCString& aString, 1.85 + const int32_t& aInt, 1.86 + const bool& aTemporary) MOZ_OVERRIDE; 1.87 + 1.88 + virtual bool 1.89 + RecvPPluginIdentifierConstructor(PPluginIdentifierChild* actor, 1.90 + const nsCString& aString, 1.91 + const int32_t& aInt, 1.92 + const bool& aTemporary) MOZ_OVERRIDE; 1.93 + 1.94 + virtual bool 1.95 + DeallocPPluginIdentifierChild(PPluginIdentifierChild* aActor) MOZ_OVERRIDE; 1.96 + 1.97 + virtual PPluginInstanceChild* 1.98 + AllocPPluginInstanceChild(const nsCString& aMimeType, 1.99 + const uint16_t& aMode, 1.100 + const InfallibleTArray<nsCString>& aNames, 1.101 + const InfallibleTArray<nsCString>& aValues, 1.102 + NPError* rv) MOZ_OVERRIDE; 1.103 + 1.104 + virtual bool 1.105 + DeallocPPluginInstanceChild(PPluginInstanceChild* aActor) MOZ_OVERRIDE; 1.106 + 1.107 + virtual bool 1.108 + AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor, 1.109 + const nsCString& aMimeType, 1.110 + const uint16_t& aMode, 1.111 + const InfallibleTArray<nsCString>& aNames, 1.112 + const InfallibleTArray<nsCString>& aValues, 1.113 + NPError* rv) MOZ_OVERRIDE; 1.114 + virtual bool 1.115 + AnswerNP_Shutdown(NPError *rv) MOZ_OVERRIDE; 1.116 + 1.117 + virtual bool 1.118 + AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify, 1.119 + bool *aClearSiteData, 1.120 + bool *aGetSitesWithData) MOZ_OVERRIDE; 1.121 + 1.122 + virtual bool 1.123 + AnswerNPP_ClearSiteData(const nsCString& aSite, 1.124 + const uint64_t& aFlags, 1.125 + const uint64_t& aMaxAge, 1.126 + NPError* aResult) MOZ_OVERRIDE; 1.127 + 1.128 + virtual bool 1.129 + AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult) MOZ_OVERRIDE; 1.130 + 1.131 + virtual bool 1.132 + RecvSetAudioSessionData(const nsID& aId, 1.133 + const nsString& aDisplayName, 1.134 + const nsString& aIconPath) MOZ_OVERRIDE; 1.135 + 1.136 + virtual bool 1.137 + RecvSetParentHangTimeout(const uint32_t& aSeconds) MOZ_OVERRIDE; 1.138 + 1.139 + virtual PCrashReporterChild* 1.140 + AllocPCrashReporterChild(mozilla::dom::NativeThreadId* id, 1.141 + uint32_t* processType) MOZ_OVERRIDE; 1.142 + virtual bool 1.143 + DeallocPCrashReporterChild(PCrashReporterChild* actor) MOZ_OVERRIDE; 1.144 + virtual bool 1.145 + AnswerPCrashReporterConstructor(PCrashReporterChild* actor, 1.146 + mozilla::dom::NativeThreadId* id, 1.147 + uint32_t* processType) MOZ_OVERRIDE; 1.148 + 1.149 + virtual void 1.150 + ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; 1.151 + 1.152 + MOZ_NORETURN void QuickExit(); 1.153 + 1.154 + virtual bool 1.155 + RecvProcessNativeEventsInInterruptCall() MOZ_OVERRIDE; 1.156 + 1.157 + virtual bool 1.158 + AnswerGeckoGetProfile(nsCString* aProfile) MOZ_OVERRIDE; 1.159 + 1.160 +public: 1.161 + PluginModuleChild(); 1.162 + virtual ~PluginModuleChild(); 1.163 + 1.164 + // aPluginFilename is UTF8, not native-charset! 1.165 + bool Init(const std::string& aPluginFilename, 1.166 + base::ProcessHandle aParentProcessHandle, 1.167 + MessageLoop* aIOLoop, 1.168 + IPC::Channel* aChannel); 1.169 + 1.170 + void CleanUp(); 1.171 + 1.172 + const char* GetUserAgent(); 1.173 + 1.174 + static const NPNetscapeFuncs sBrowserFuncs; 1.175 + 1.176 + static PluginModuleChild* current(); 1.177 + 1.178 + bool RegisterActorForNPObject(NPObject* aObject, 1.179 + PluginScriptableObjectChild* aActor); 1.180 + 1.181 + void UnregisterActorForNPObject(NPObject* aObject); 1.182 + 1.183 + PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject); 1.184 + 1.185 +#ifdef DEBUG 1.186 + bool NPObjectIsRegistered(NPObject* aObject); 1.187 +#endif 1.188 + 1.189 + bool AsyncDrawingAllowed() { return mAsyncDrawingAllowed; } 1.190 + 1.191 + /** 1.192 + * The child implementation of NPN_CreateObject. 1.193 + */ 1.194 + static NPObject* NPN_CreateObject(NPP aNPP, NPClass* aClass); 1.195 + /** 1.196 + * The child implementation of NPN_RetainObject. 1.197 + */ 1.198 + static NPObject* NPN_RetainObject(NPObject* aNPObj); 1.199 + /** 1.200 + * The child implementation of NPN_ReleaseObject. 1.201 + */ 1.202 + static void NPN_ReleaseObject(NPObject* aNPObj); 1.203 + 1.204 + /** 1.205 + * The child implementations of NPIdentifier-related functions. 1.206 + */ 1.207 + static NPIdentifier NPN_GetStringIdentifier(const NPUTF8* aName); 1.208 + static void NPN_GetStringIdentifiers(const NPUTF8** aNames, 1.209 + int32_t aNameCount, 1.210 + NPIdentifier* aIdentifiers); 1.211 + static NPIdentifier NPN_GetIntIdentifier(int32_t aIntId); 1.212 + static bool NPN_IdentifierIsString(NPIdentifier aIdentifier); 1.213 + static NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier aIdentifier); 1.214 + static int32_t NPN_IntFromIdentifier(NPIdentifier aIdentifier); 1.215 + 1.216 +#ifdef MOZ_WIDGET_COCOA 1.217 + void ProcessNativeEvents(); 1.218 + 1.219 + void PluginShowWindow(uint32_t window_id, bool modal, CGRect r) { 1.220 + SendPluginShowWindow(window_id, modal, r.origin.x, r.origin.y, r.size.width, r.size.height); 1.221 + } 1.222 + 1.223 + void PluginHideWindow(uint32_t window_id) { 1.224 + SendPluginHideWindow(window_id); 1.225 + } 1.226 + 1.227 + void SetCursor(NSCursorInfo& cursorInfo) { 1.228 + SendSetCursor(cursorInfo); 1.229 + } 1.230 + 1.231 + void ShowCursor(bool show) { 1.232 + SendShowCursor(show); 1.233 + } 1.234 + 1.235 + void PushCursor(NSCursorInfo& cursorInfo) { 1.236 + SendPushCursor(cursorInfo); 1.237 + } 1.238 + 1.239 + void PopCursor() { 1.240 + SendPopCursor(); 1.241 + } 1.242 + 1.243 + bool GetNativeCursorsSupported() { 1.244 + bool supported = false; 1.245 + SendGetNativeCursorsSupported(&supported); 1.246 + return supported; 1.247 + } 1.248 +#endif 1.249 + 1.250 + // Quirks mode support for various plugin mime types 1.251 + enum PluginQuirks { 1.252 + QUIRKS_NOT_INITIALIZED = 0, 1.253 + // Silverlight assumes it is transparent in windowless mode. This quirk 1.254 + // matches the logic in nsNPAPIPluginInstance::SetWindowless. 1.255 + QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT = 1 << 0, 1.256 + // Win32: Hook TrackPopupMenu api so that we can swap out parent 1.257 + // hwnds. The api will fail with parents not associated with our 1.258 + // child ui thread. See WinlessHandleEvent for details. 1.259 + QUIRK_WINLESS_TRACKPOPUP_HOOK = 1 << 1, 1.260 + // Win32: Throttle flash WM_USER+1 heart beat messages to prevent 1.261 + // flooding chromium's dispatch loop, which can cause ipc traffic 1.262 + // processing lag. 1.263 + QUIRK_FLASH_THROTTLE_WMUSER_EVENTS = 1 << 2, 1.264 + // Win32: Catch resets on our subclass by hooking SetWindowLong. 1.265 + QUIRK_FLASH_HOOK_SETLONGPTR = 1 << 3, 1.266 + // X11: Work around a bug in Flash up to 10.1 d51 at least, where 1.267 + // expose event top left coordinates within the plugin-rect and 1.268 + // not at the drawable origin are misinterpreted. 1.269 + QUIRK_FLASH_EXPOSE_COORD_TRANSLATION = 1 << 4, 1.270 + // Win32: Catch get window info calls on the browser and tweak the 1.271 + // results so mouse input works when flash is displaying it's settings 1.272 + // window. 1.273 + QUIRK_FLASH_HOOK_GETWINDOWINFO = 1 << 5, 1.274 + // Win: Addresses a flash bug with mouse capture and full screen 1.275 + // windows. 1.276 + QUIRK_FLASH_FIXUP_MOUSE_CAPTURE = 1 << 6, 1.277 + // Win: QuickTime steals focus on SetWindow calls even if it's hidden. 1.278 + // Avoid calling SetWindow in that case. 1.279 + QUIRK_QUICKTIME_AVOID_SETWINDOW = 1 << 7, 1.280 + // Win: Check to make sure the parent window has focus before calling 1.281 + // set focus on the child. Addresses a full screen dialog prompt 1.282 + // problem in Silverlight. 1.283 + QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT = 1 << 8, 1.284 + // Mac: Allow the plugin to use offline renderer mode. 1.285 + // Use this only if the plugin is certified the support the offline renderer. 1.286 + QUIRK_ALLOW_OFFLINE_RENDERER = 1 << 9, 1.287 + // Mac: Work around a Flash bug that can cause plugin process crashes 1.288 + // in CoreGraphics mode: The Flash plugin sometimes accesses the 1.289 + // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect) 1.290 + // outside of that call. See bug 804606. 1.291 + QUIRK_FLASH_AVOID_CGMODE_CRASHES = 1 << 10, 1.292 + }; 1.293 + 1.294 + int GetQuirks() { return mQuirks; } 1.295 + 1.296 +private: 1.297 + void AddQuirk(PluginQuirks quirk) { 1.298 + if (mQuirks == QUIRKS_NOT_INITIALIZED) 1.299 + mQuirks = 0; 1.300 + mQuirks |= quirk; 1.301 + } 1.302 + void InitQuirksModes(const nsCString& aMimeType); 1.303 + bool InitGraphics(); 1.304 + void DeinitGraphics(); 1.305 +#if defined(MOZ_WIDGET_GTK) 1.306 + static gboolean DetectNestedEventLoop(gpointer data); 1.307 + static gboolean ProcessBrowserEvents(gpointer data); 1.308 + 1.309 + virtual void EnteredCxxStack() MOZ_OVERRIDE; 1.310 + virtual void ExitedCxxStack() MOZ_OVERRIDE; 1.311 +#elif defined(MOZ_WIDGET_QT) 1.312 + 1.313 + virtual void EnteredCxxStack() MOZ_OVERRIDE; 1.314 + virtual void ExitedCxxStack() MOZ_OVERRIDE; 1.315 +#endif 1.316 + 1.317 + PRLibrary* mLibrary; 1.318 + nsCString mPluginFilename; // UTF8 1.319 + nsCString mUserAgent; 1.320 + int mQuirks; 1.321 + bool mAsyncDrawingAllowed; 1.322 + 1.323 + // we get this from the plugin 1.324 + NP_PLUGINSHUTDOWN mShutdownFunc; 1.325 +#if defined(OS_LINUX) || defined(OS_BSD) 1.326 + NP_PLUGINUNIXINIT mInitializeFunc; 1.327 +#elif defined(OS_WIN) || defined(OS_MACOSX) 1.328 + NP_PLUGININIT mInitializeFunc; 1.329 + NP_GETENTRYPOINTS mGetEntryPointsFunc; 1.330 +#endif 1.331 + 1.332 + NPPluginFuncs mFunctions; 1.333 + NPSavedData mSavedData; 1.334 + 1.335 +#if defined(MOZ_WIDGET_GTK) 1.336 + // If a plugin spins a nested glib event loop in response to a 1.337 + // synchronous IPC message from the browser, the loop might break 1.338 + // only after the browser responds to a request sent by the 1.339 + // plugin. This can happen if a plugin uses gtk's synchronous 1.340 + // copy/paste, for example. But because the browser is blocked on 1.341 + // a condvar, it can't respond to the request. This situation 1.342 + // isn't technically a deadlock, but the symptoms are basically 1.343 + // the same from the user's perspective. 1.344 + // 1.345 + // We take two steps to prevent this 1.346 + // 1.347 + // (1) Detect nested event loops spun by the plugin. This is 1.348 + // done by scheduling a glib timer event in the plugin 1.349 + // process whenever the browser might block on the plugin. 1.350 + // If the plugin indeed spins a nested loop, this timer event 1.351 + // will fire "soon" thereafter. 1.352 + // 1.353 + // (2) When a nested loop is detected, deschedule the 1.354 + // nested-loop-detection timer and in its place, schedule 1.355 + // another timer that periodically calls back into the 1.356 + // browser and spins a mini event loop. This mini event loop 1.357 + // processes a handful of pending native events. 1.358 + // 1.359 + // Because only timer (1) or (2) (or neither) may be active at any 1.360 + // point in time, we use the same member variable 1.361 + // |mNestedLoopTimerId| to refer to both. 1.362 + // 1.363 + // When the browser no longer might be blocked on a plugin's IPC 1.364 + // response, we deschedule whichever of (1) or (2) is active. 1.365 + guint mNestedLoopTimerId; 1.366 +# ifdef DEBUG 1.367 + // Depth of the stack of calls to g_main_context_dispatch before any 1.368 + // nested loops are run. This is 1 when IPC calls are dispatched from 1.369 + // g_main_context_iteration, or 0 when dispatched directly from 1.370 + // MessagePumpForUI. 1.371 + int mTopLoopDepth; 1.372 +# endif 1.373 +#elif defined (MOZ_WIDGET_QT) 1.374 + NestedLoopTimer *mNestedLoopTimerObject; 1.375 +#endif 1.376 + 1.377 + struct NPObjectData : public nsPtrHashKey<NPObject> 1.378 + { 1.379 + NPObjectData(const NPObject* key) 1.380 + : nsPtrHashKey<NPObject>(key) 1.381 + , instance(nullptr) 1.382 + , actor(nullptr) 1.383 + { } 1.384 + 1.385 + // never nullptr 1.386 + PluginInstanceChild* instance; 1.387 + 1.388 + // sometimes nullptr (no actor associated with an NPObject) 1.389 + PluginScriptableObjectChild* actor; 1.390 + }; 1.391 + /** 1.392 + * mObjectMap contains all the currently active NPObjects (from NPN_CreateObject until the 1.393 + * final release/dealloc, whether or not an actor is currently associated with the object. 1.394 + */ 1.395 + nsTHashtable<NPObjectData> mObjectMap; 1.396 + 1.397 + friend class PluginIdentifierChild; 1.398 + friend class PluginIdentifierChildString; 1.399 + friend class PluginIdentifierChildInt; 1.400 + nsDataHashtable<nsCStringHashKey, PluginIdentifierChildString*> mStringIdentifiers; 1.401 + nsDataHashtable<nsUint32HashKey, PluginIdentifierChildInt*> mIntIdentifiers; 1.402 + 1.403 +public: // called by PluginInstanceChild 1.404 + /** 1.405 + * Dealloc an NPObject after last-release or when the associated instance 1.406 + * is destroyed. This function will remove the object from mObjectMap. 1.407 + */ 1.408 + static void DeallocNPObject(NPObject* o); 1.409 + 1.410 + NPError NPP_Destroy(PluginInstanceChild* instance) { 1.411 + return mFunctions.destroy(instance->GetNPP(), 0); 1.412 + } 1.413 + 1.414 + /** 1.415 + * Fill PluginInstanceChild.mDeletingHash with all the remaining NPObjects 1.416 + * associated with that instance. 1.417 + */ 1.418 + void FindNPObjectsForInstance(PluginInstanceChild* instance); 1.419 + 1.420 +private: 1.421 + static PLDHashOperator CollectForInstance(NPObjectData* d, void* userArg); 1.422 + 1.423 +#if defined(OS_WIN) 1.424 + virtual void EnteredCall() MOZ_OVERRIDE; 1.425 + virtual void ExitedCall() MOZ_OVERRIDE; 1.426 + 1.427 + // Entered/ExitedCall notifications keep track of whether the plugin has 1.428 + // entered a nested event loop within this interrupt call. 1.429 + struct IncallFrame 1.430 + { 1.431 + IncallFrame() 1.432 + : _spinning(false) 1.433 + , _savedNestableTasksAllowed(false) 1.434 + { } 1.435 + 1.436 + bool _spinning; 1.437 + bool _savedNestableTasksAllowed; 1.438 + }; 1.439 + 1.440 + nsAutoTArray<IncallFrame, 8> mIncallPumpingStack; 1.441 + 1.442 + static LRESULT CALLBACK NestedInputEventHook(int code, 1.443 + WPARAM wParam, 1.444 + LPARAM lParam); 1.445 + static LRESULT CALLBACK CallWindowProcHook(int code, 1.446 + WPARAM wParam, 1.447 + LPARAM lParam); 1.448 + void SetEventHooks(); 1.449 + void ResetEventHooks(); 1.450 + HHOOK mNestedEventHook; 1.451 + HHOOK mGlobalCallWndProcHook; 1.452 +#endif 1.453 +}; 1.454 + 1.455 +} /* namespace plugins */ 1.456 +} /* namespace mozilla */ 1.457 + 1.458 +#endif // ifndef dom_plugins_PluginModuleChild_h