diff options
Diffstat (limited to '')
-rw-r--r-- | dom/plugins/ipc/PluginModuleChild.h | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h new file mode 100644 index 0000000000..31d4eafb8f --- /dev/null +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -0,0 +1,345 @@ +/* -*- 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 <string> +#include <vector> + +#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 <glib.h> +#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<mozilla::PProfilerChild>&& 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<PPluginModuleChild>&& endpoint); + + mozilla::ipc::IPCResult RecvInitPluginFunctionBroker( + Endpoint<PFunctionBrokerChild>&& endpoint); + + PPluginInstanceChild* AllocPPluginInstanceChild( + const nsCString& aMimeType, const nsTArray<nsCString>& aNames, + const nsTArray<nsCString>& aValues); + + bool DeallocPPluginInstanceChild(PPluginInstanceChild* aActor); + + mozilla::ipc::IPCResult RecvPPluginInstanceConstructor( + PPluginInstanceChild* aActor, const nsCString& aMimeType, + nsTArray<nsCString>&& aNames, nsTArray<nsCString>&& 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<IPC::Channel> aChannel); + + bool InitForContent(Endpoint<PPluginModuleChild>&& aEndpoint); + + static bool CreateForContentProcess(Endpoint<PPluginModuleChild>&& 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<ChildProfilerController> 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<nsPtrHashKey<PluginInstanceChild>> 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<IncallFrame, 8> 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 |