/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: sw=2 ts=4 et : * 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 dom_plugins_PluginModuleChild_h #define dom_plugins_PluginModuleChild_h 1 #include "mozilla/Attributes.h" #include #include #include "base/basictypes.h" #include "prlink.h" #include "npapi.h" #include "npfunctions.h" #include "nsDataHashtable.h" #include "nsTHashtable.h" #include "nsHashKeys.h" #ifdef MOZ_WIDGET_COCOA # include "PluginInterposeOSX.h" #endif #include "mozilla/plugins/PPluginModuleChild.h" #include "mozilla/plugins/PluginInstanceChild.h" #include "mozilla/plugins/PluginMessageUtils.h" #include "mozilla/plugins/PluginQuirks.h" #if defined(MOZ_WIDGET_GTK) # include #endif namespace mozilla { class ChildProfilerController; namespace plugins { class PluginInstanceChild; class PluginModuleChild : public PPluginModuleChild { friend class PPluginModuleChild; protected: virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( const MessageInfo& parent, const MessageInfo& child) override { return MediateRace(parent, child); } virtual bool ShouldContinueFromReplyTimeout() override; mozilla::ipc::IPCResult RecvSettingChanged(const PluginSettings& aSettings); // Implement the PPluginModuleChild interface mozilla::ipc::IPCResult RecvInitProfiler( Endpoint&& aEndpoint); mozilla::ipc::IPCResult RecvDisableFlashProtectedMode(); mozilla::ipc::IPCResult AnswerNP_GetEntryPoints(NPError* rv); mozilla::ipc::IPCResult AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv); mozilla::ipc::IPCResult AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv); mozilla::ipc::IPCResult RecvInitPluginModuleChild( Endpoint&& endpoint); mozilla::ipc::IPCResult RecvInitPluginFunctionBroker( Endpoint&& endpoint); PPluginInstanceChild* AllocPPluginInstanceChild( const nsCString& aMimeType, const nsTArray& aNames, const nsTArray& aValues); bool DeallocPPluginInstanceChild(PPluginInstanceChild* aActor); mozilla::ipc::IPCResult RecvPPluginInstanceConstructor( PPluginInstanceChild* aActor, const nsCString& aMimeType, nsTArray&& aNames, nsTArray&& aValues) override; mozilla::ipc::IPCResult AnswerNP_Shutdown(NPError* rv); mozilla::ipc::IPCResult AnswerOptionalFunctionsSupported( bool* aURLRedirectNotify, bool* aClearSiteData, bool* aGetSitesWithData); mozilla::ipc::IPCResult RecvNPP_ClearSiteData(const nsCString& aSite, const uint64_t& aFlags, const uint64_t& aMaxAge, const uint64_t& aCallbackId); mozilla::ipc::IPCResult RecvNPP_GetSitesWithData(const uint64_t& aCallbackId); mozilla::ipc::IPCResult RecvSetAudioSessionData(const nsID& aId, const nsString& aDisplayName, const nsString& aIconPath); mozilla::ipc::IPCResult RecvSetParentHangTimeout(const uint32_t& aSeconds); mozilla::ipc::IPCResult AnswerInitCrashReporter( mozilla::dom::NativeThreadId* aId); virtual void ActorDestroy(ActorDestroyReason why) override; mozilla::ipc::IPCResult RecvProcessNativeEventsInInterruptCall(); mozilla::ipc::IPCResult AnswerModuleSupportsAsyncRender(bool* aResult); public: explicit PluginModuleChild(bool aIsChrome); virtual ~PluginModuleChild(); void CommonInit(); #if defined(OS_WIN) && defined(MOZ_SANDBOX) // Path to the roaming Flash Player folder. This is used to restore some // behavior blocked by the sandbox. static void SetFlashRoamingPath(const std::wstring& aRoamingPath); static std::wstring GetFlashRoamingPath(); #endif // aPluginFilename is UTF8, not native-charset! bool InitForChrome(const std::string& aPluginFilename, base::ProcessId aParentPid, MessageLoop* aIOLoop, UniquePtr aChannel); bool InitForContent(Endpoint&& aEndpoint); static bool CreateForContentProcess(Endpoint&& aEndpoint); void CleanUp(); NPError NP_Shutdown(); const char* GetUserAgent(); static const NPNetscapeFuncs sBrowserFuncs; static PluginModuleChild* GetChrome(); /** * The child implementation of NPN_CreateObject. */ static NPObject* NPN_CreateObject(NPP aNPP, NPClass* aClass); /** * The child implementation of NPN_RetainObject. */ static NPObject* NPN_RetainObject(NPObject* aNPObj); /** * The child implementation of NPN_ReleaseObject. */ static void NPN_ReleaseObject(NPObject* aNPObj); /** * The child implementations of NPIdentifier-related functions. */ static NPIdentifier NPN_GetStringIdentifier(const NPUTF8* aName); static void NPN_GetStringIdentifiers(const NPUTF8** aNames, int32_t aNameCount, NPIdentifier* aIdentifiers); static NPIdentifier NPN_GetIntIdentifier(int32_t aIntId); static bool NPN_IdentifierIsString(NPIdentifier aIdentifier); static NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier aIdentifier); static int32_t NPN_IntFromIdentifier(NPIdentifier aIdentifier); #ifdef MOZ_WIDGET_COCOA void ProcessNativeEvents(); void PluginShowWindow(uint32_t window_id, bool modal, CGRect r) { SendPluginShowWindow(window_id, modal, r.origin.x, r.origin.y, r.size.width, r.size.height); } void PluginHideWindow(uint32_t window_id) { SendPluginHideWindow(window_id); } void SetCursor(NSCursorInfo& cursorInfo) { SendSetCursor(cursorInfo); } void ShowCursor(bool show) { SendShowCursor(show); } void PushCursor(NSCursorInfo& cursorInfo) { SendPushCursor(cursorInfo); } void PopCursor() { SendPopCursor(); } bool GetNativeCursorsSupported() { return Settings().nativeCursorsSupported(); } #endif int GetQuirks() { return mQuirks; } const PluginSettings& Settings() const { return mCachedSettings; } NPError PluginRequiresAudioDeviceChanges(PluginInstanceChild* aInstance, NPBool aShouldRegister); mozilla::ipc::IPCResult RecvNPP_SetValue_NPNVaudioDeviceChangeDetails( const NPAudioDeviceChangeDetailsIPC& detailsIPC); mozilla::ipc::IPCResult RecvNPP_SetValue_NPNVaudioDeviceStateChanged( const NPAudioDeviceStateChangedIPC& aDeviceStateIPC); private: NPError DoNP_Initialize(const PluginSettings& aSettings); void AddQuirk(PluginQuirks quirk) { if (mQuirks == QUIRKS_NOT_INITIALIZED) mQuirks = 0; mQuirks |= quirk; } void InitQuirksModes(const nsCString& aMimeType); bool InitGraphics(); void DeinitGraphics(); #if defined(MOZ_WIDGET_GTK) static gboolean DetectNestedEventLoop(gpointer data); static gboolean ProcessBrowserEvents(gpointer data); virtual void EnteredCxxStack() override; virtual void ExitedCxxStack() override; #endif PRLibrary* mLibrary; nsCString mPluginFilename; // UTF8 int mQuirks; bool mIsChrome; bool mHasShutdown; // true if NP_Shutdown has run #ifdef MOZ_GECKO_PROFILER RefPtr mProfilerController; #endif // we get this from the plugin NP_PLUGINSHUTDOWN mShutdownFunc; #if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) NP_PLUGINUNIXINIT mInitializeFunc; #elif defined(OS_WIN) || defined(OS_MACOSX) NP_PLUGININIT mInitializeFunc; NP_GETENTRYPOINTS mGetEntryPointsFunc; #endif NPPluginFuncs mFunctions; PluginSettings mCachedSettings; #if defined(MOZ_WIDGET_GTK) // If a plugin spins a nested glib event loop in response to a // synchronous IPC message from the browser, the loop might break // only after the browser responds to a request sent by the // plugin. This can happen if a plugin uses gtk's synchronous // copy/paste, for example. But because the browser is blocked on // a condvar, it can't respond to the request. This situation // isn't technically a deadlock, but the symptoms are basically // the same from the user's perspective. // // We take two steps to prevent this // // (1) Detect nested event loops spun by the plugin. This is // done by scheduling a glib timer event in the plugin // process whenever the browser might block on the plugin. // If the plugin indeed spins a nested loop, this timer event // will fire "soon" thereafter. // // (2) When a nested loop is detected, deschedule the // nested-loop-detection timer and in its place, schedule // another timer that periodically calls back into the // browser and spins a mini event loop. This mini event loop // processes a handful of pending native events. // // Because only timer (1) or (2) (or neither) may be active at any // point in time, we use the same member variable // |mNestedLoopTimerId| to refer to both. // // When the browser no longer might be blocked on a plugin's IPC // response, we deschedule whichever of (1) or (2) is active. guint mNestedLoopTimerId; # ifdef DEBUG // Depth of the stack of calls to g_main_context_dispatch before any // nested loops are run. This is 1 when IPC calls are dispatched from // g_main_context_iteration, or 0 when dispatched directly from // MessagePumpForUI. int mTopLoopDepth; # endif #endif #if defined(XP_WIN) typedef nsTHashtable> PluginInstanceSet; // Set of plugins that have registered to be notified when the audio device // changes. PluginInstanceSet mAudioNotificationSet; #endif public: // called by PluginInstanceChild /** * Dealloc an NPObject after last-release or when the associated instance * is destroyed. This function will remove the object from mObjectMap. */ static void DeallocNPObject(NPObject* o); NPError NPP_Destroy(PluginInstanceChild* instance) { return mFunctions.destroy(instance->GetNPP(), 0); } #if defined(OS_MACOSX) && defined(MOZ_SANDBOX) void EnableFlashSandbox(int aLevel, bool aShouldEnableLogging); #endif private: #if defined(OS_MACOSX) && defined(MOZ_SANDBOX) int mFlashSandboxLevel; bool mEnableFlashSandboxLogging; #endif #if defined(OS_WIN) virtual void EnteredCall() override; virtual void ExitedCall() override; // Entered/ExitedCall notifications keep track of whether the plugin has // entered a nested event loop within this interrupt call. struct IncallFrame { IncallFrame() : _spinning(false), _savedNestableTasksAllowed(false) {} bool _spinning; bool _savedNestableTasksAllowed; }; AutoTArray mIncallPumpingStack; static LRESULT CALLBACK NestedInputEventHook(int code, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK CallWindowProcHook(int code, WPARAM wParam, LPARAM lParam); void SetEventHooks(); void ResetEventHooks(); HHOOK mNestedEventHook; HHOOK mGlobalCallWndProcHook; public: bool mAsyncRenderSupport; #endif }; } /* namespace plugins */ } /* namespace mozilla */ #endif // ifndef dom_plugins_PluginModuleChild_h