1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=4 et : 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 #ifndef dom_plugins_PluginModuleChild_h 8 #define dom_plugins_PluginModuleChild_h 1 9 10 #include "mozilla/Attributes.h" 11 12 #include <string> 13 #include <vector> 14 15 #include "base/basictypes.h" 16 17 #include "prlink.h" 18 19 #include "npapi.h" 20 #include "npfunctions.h" 21 22 #include "nsDataHashtable.h" 23 #include "nsTHashtable.h" 24 #include "nsHashKeys.h" 25 26 #ifdef MOZ_WIDGET_COCOA 27 # include "PluginInterposeOSX.h" 28 #endif 29 30 #include "mozilla/plugins/PPluginModuleChild.h" 31 #include "mozilla/plugins/PluginInstanceChild.h" 32 #include "mozilla/plugins/PluginMessageUtils.h" 33 #include "mozilla/plugins/PluginQuirks.h" 34 35 namespace mozilla { 36 37 class ChildProfilerController; 38 39 namespace plugins { 40 41 class PluginInstanceChild; 42 43 class PluginModuleChild : public PPluginModuleChild { 44 friend class PPluginModuleChild; 45 46 protected: MediateInterruptRace(const MessageInfo & parent,const MessageInfo & child)47 virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( 48 const MessageInfo& parent, const MessageInfo& child) override { 49 return MediateRace(parent, child); 50 } 51 52 virtual bool ShouldContinueFromReplyTimeout() override; 53 54 mozilla::ipc::IPCResult RecvSettingChanged(const PluginSettings& aSettings); 55 56 // Implement the PPluginModuleChild interface 57 mozilla::ipc::IPCResult RecvInitProfiler( 58 Endpoint<mozilla::PProfilerChild>&& aEndpoint); 59 mozilla::ipc::IPCResult RecvDisableFlashProtectedMode(); 60 mozilla::ipc::IPCResult AnswerNP_GetEntryPoints(NPError* rv); 61 mozilla::ipc::IPCResult AnswerNP_Initialize(const PluginSettings& aSettings, 62 NPError* rv); 63 mozilla::ipc::IPCResult AnswerSyncNPP_New(PPluginInstanceChild* aActor, 64 NPError* rv); 65 66 mozilla::ipc::IPCResult RecvInitPluginModuleChild( 67 Endpoint<PPluginModuleChild>&& endpoint); 68 69 mozilla::ipc::IPCResult RecvInitPluginFunctionBroker( 70 Endpoint<PFunctionBrokerChild>&& endpoint); 71 72 PPluginInstanceChild* AllocPPluginInstanceChild( 73 const nsCString& aMimeType, const nsTArray<nsCString>& aNames, 74 const nsTArray<nsCString>& aValues); 75 76 bool DeallocPPluginInstanceChild(PPluginInstanceChild* aActor); 77 78 mozilla::ipc::IPCResult RecvPPluginInstanceConstructor( 79 PPluginInstanceChild* aActor, const nsCString& aMimeType, 80 nsTArray<nsCString>&& aNames, nsTArray<nsCString>&& aValues) override; 81 mozilla::ipc::IPCResult AnswerNP_Shutdown(NPError* rv); 82 83 mozilla::ipc::IPCResult AnswerOptionalFunctionsSupported( 84 bool* aURLRedirectNotify, bool* aClearSiteData, bool* aGetSitesWithData); 85 86 mozilla::ipc::IPCResult RecvNPP_ClearSiteData(const nsCString& aSite, 87 const uint64_t& aFlags, 88 const uint64_t& aMaxAge, 89 const uint64_t& aCallbackId); 90 91 mozilla::ipc::IPCResult RecvNPP_GetSitesWithData(const uint64_t& aCallbackId); 92 93 mozilla::ipc::IPCResult RecvSetAudioSessionData(const nsID& aId, 94 const nsString& aDisplayName, 95 const nsString& aIconPath); 96 97 mozilla::ipc::IPCResult RecvSetParentHangTimeout(const uint32_t& aSeconds); 98 99 mozilla::ipc::IPCResult AnswerInitCrashReporter( 100 mozilla::dom::NativeThreadId* aId); 101 102 virtual void ActorDestroy(ActorDestroyReason why) override; 103 104 mozilla::ipc::IPCResult RecvProcessNativeEventsInInterruptCall(); 105 106 mozilla::ipc::IPCResult AnswerModuleSupportsAsyncRender(bool* aResult); 107 108 public: 109 explicit PluginModuleChild(bool aIsChrome); 110 virtual ~PluginModuleChild(); 111 112 void CommonInit(); 113 114 #if defined(OS_WIN) && defined(MOZ_SANDBOX) 115 // Path to the roaming Flash Player folder. This is used to restore some 116 // behavior blocked by the sandbox. 117 static void SetFlashRoamingPath(const std::wstring& aRoamingPath); 118 static std::wstring GetFlashRoamingPath(); 119 #endif 120 121 // aPluginFilename is UTF8, not native-charset! 122 bool InitForChrome(const std::string& aPluginFilename, 123 base::ProcessId aParentPid, MessageLoop* aIOLoop, 124 UniquePtr<IPC::Channel> aChannel); 125 126 bool InitForContent(Endpoint<PPluginModuleChild>&& aEndpoint); 127 128 static bool CreateForContentProcess(Endpoint<PPluginModuleChild>&& aEndpoint); 129 130 void CleanUp(); 131 132 NPError NP_Shutdown(); 133 134 const char* GetUserAgent(); 135 136 static const NPNetscapeFuncs sBrowserFuncs; 137 138 static PluginModuleChild* GetChrome(); 139 140 /** 141 * The child implementation of NPN_CreateObject. 142 */ 143 static NPObject* NPN_CreateObject(NPP aNPP, NPClass* aClass); 144 /** 145 * The child implementation of NPN_RetainObject. 146 */ 147 static NPObject* NPN_RetainObject(NPObject* aNPObj); 148 /** 149 * The child implementation of NPN_ReleaseObject. 150 */ 151 static void NPN_ReleaseObject(NPObject* aNPObj); 152 153 /** 154 * The child implementations of NPIdentifier-related functions. 155 */ 156 static NPIdentifier NPN_GetStringIdentifier(const NPUTF8* aName); 157 static void NPN_GetStringIdentifiers(const NPUTF8** aNames, 158 int32_t aNameCount, 159 NPIdentifier* aIdentifiers); 160 static NPIdentifier NPN_GetIntIdentifier(int32_t aIntId); 161 static bool NPN_IdentifierIsString(NPIdentifier aIdentifier); 162 static NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier aIdentifier); 163 static int32_t NPN_IntFromIdentifier(NPIdentifier aIdentifier); 164 165 #ifdef MOZ_WIDGET_COCOA 166 void ProcessNativeEvents(); 167 PluginShowWindow(uint32_t window_id,bool modal,CGRect r)168 void PluginShowWindow(uint32_t window_id, bool modal, CGRect r) { 169 SendPluginShowWindow(window_id, modal, r.origin.x, r.origin.y, r.size.width, 170 r.size.height); 171 } 172 PluginHideWindow(uint32_t window_id)173 void PluginHideWindow(uint32_t window_id) { SendPluginHideWindow(window_id); } 174 SetCursor(NSCursorInfo & cursorInfo)175 void SetCursor(NSCursorInfo& cursorInfo) { SendSetCursor(cursorInfo); } 176 ShowCursor(bool show)177 void ShowCursor(bool show) { SendShowCursor(show); } 178 PushCursor(NSCursorInfo & cursorInfo)179 void PushCursor(NSCursorInfo& cursorInfo) { SendPushCursor(cursorInfo); } 180 PopCursor()181 void PopCursor() { SendPopCursor(); } 182 GetNativeCursorsSupported()183 bool GetNativeCursorsSupported() { 184 return Settings().nativeCursorsSupported(); 185 } 186 #endif 187 GetQuirks()188 int GetQuirks() { return mQuirks; } 189 Settings()190 const PluginSettings& Settings() const { return mCachedSettings; } 191 192 NPError PluginRequiresAudioDeviceChanges(PluginInstanceChild* aInstance, 193 NPBool aShouldRegister); 194 mozilla::ipc::IPCResult RecvNPP_SetValue_NPNVaudioDeviceChangeDetails( 195 const NPAudioDeviceChangeDetailsIPC& detailsIPC); 196 mozilla::ipc::IPCResult RecvNPP_SetValue_NPNVaudioDeviceStateChanged( 197 const NPAudioDeviceStateChangedIPC& aDeviceStateIPC); 198 199 private: 200 NPError DoNP_Initialize(const PluginSettings& aSettings); AddQuirk(PluginQuirks quirk)201 void AddQuirk(PluginQuirks quirk) { 202 if (mQuirks == QUIRKS_NOT_INITIALIZED) mQuirks = 0; 203 mQuirks |= quirk; 204 } 205 void InitQuirksModes(const nsCString& aMimeType); 206 bool InitGraphics(); 207 void DeinitGraphics(); 208 209 #if defined(MOZ_WIDGET_GTK) 210 static gboolean DetectNestedEventLoop(gpointer data); 211 static gboolean ProcessBrowserEvents(gpointer data); 212 213 virtual void EnteredCxxStack() override; 214 virtual void ExitedCxxStack() override; 215 #endif 216 217 PRLibrary* mLibrary; 218 nsCString mPluginFilename; // UTF8 219 int mQuirks; 220 221 bool mIsChrome; 222 bool mHasShutdown; // true if NP_Shutdown has run 223 224 #ifdef MOZ_GECKO_PROFILER 225 RefPtr<ChildProfilerController> mProfilerController; 226 #endif 227 228 // we get this from the plugin 229 NP_PLUGINSHUTDOWN mShutdownFunc; 230 #if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) 231 NP_PLUGINUNIXINIT mInitializeFunc; 232 #elif defined(OS_WIN) || defined(OS_MACOSX) 233 NP_PLUGININIT mInitializeFunc; 234 NP_GETENTRYPOINTS mGetEntryPointsFunc; 235 #endif 236 237 NPPluginFuncs mFunctions; 238 239 PluginSettings mCachedSettings; 240 241 #if defined(MOZ_WIDGET_GTK) 242 // If a plugin spins a nested glib event loop in response to a 243 // synchronous IPC message from the browser, the loop might break 244 // only after the browser responds to a request sent by the 245 // plugin. This can happen if a plugin uses gtk's synchronous 246 // copy/paste, for example. But because the browser is blocked on 247 // a condvar, it can't respond to the request. This situation 248 // isn't technically a deadlock, but the symptoms are basically 249 // the same from the user's perspective. 250 // 251 // We take two steps to prevent this 252 // 253 // (1) Detect nested event loops spun by the plugin. This is 254 // done by scheduling a glib timer event in the plugin 255 // process whenever the browser might block on the plugin. 256 // If the plugin indeed spins a nested loop, this timer event 257 // will fire "soon" thereafter. 258 // 259 // (2) When a nested loop is detected, deschedule the 260 // nested-loop-detection timer and in its place, schedule 261 // another timer that periodically calls back into the 262 // browser and spins a mini event loop. This mini event loop 263 // processes a handful of pending native events. 264 // 265 // Because only timer (1) or (2) (or neither) may be active at any 266 // point in time, we use the same member variable 267 // |mNestedLoopTimerId| to refer to both. 268 // 269 // When the browser no longer might be blocked on a plugin's IPC 270 // response, we deschedule whichever of (1) or (2) is active. 271 guint mNestedLoopTimerId; 272 # ifdef DEBUG 273 // Depth of the stack of calls to g_main_context_dispatch before any 274 // nested loops are run. This is 1 when IPC calls are dispatched from 275 // g_main_context_iteration, or 0 when dispatched directly from 276 // MessagePumpForUI. 277 int mTopLoopDepth; 278 # endif 279 #endif 280 281 #if defined(XP_WIN) 282 typedef nsTHashtable<nsPtrHashKey<PluginInstanceChild>> PluginInstanceSet; 283 // Set of plugins that have registered to be notified when the audio device 284 // changes. 285 PluginInstanceSet mAudioNotificationSet; 286 #endif 287 288 public: // called by PluginInstanceChild 289 /** 290 * Dealloc an NPObject after last-release or when the associated instance 291 * is destroyed. This function will remove the object from mObjectMap. 292 */ 293 static void DeallocNPObject(NPObject* o); 294 NPP_Destroy(PluginInstanceChild * instance)295 NPError NPP_Destroy(PluginInstanceChild* instance) { 296 return mFunctions.destroy(instance->GetNPP(), 0); 297 } 298 299 #if defined(OS_MACOSX) && defined(MOZ_SANDBOX) 300 void EnableFlashSandbox(int aLevel, bool aShouldEnableLogging); 301 #endif 302 303 private: 304 #if defined(OS_MACOSX) && defined(MOZ_SANDBOX) 305 int mFlashSandboxLevel; 306 bool mEnableFlashSandboxLogging; 307 #endif 308 309 #if defined(OS_WIN) 310 virtual void EnteredCall() override; 311 virtual void ExitedCall() override; 312 313 // Entered/ExitedCall notifications keep track of whether the plugin has 314 // entered a nested event loop within this interrupt call. 315 struct IncallFrame { IncallFrameIncallFrame316 IncallFrame() : _spinning(false), _savedNestableTasksAllowed(false) {} 317 318 bool _spinning; 319 bool _savedNestableTasksAllowed; 320 }; 321 322 AutoTArray<IncallFrame, 8> mIncallPumpingStack; 323 324 static LRESULT CALLBACK NestedInputEventHook(int code, WPARAM wParam, 325 LPARAM lParam); 326 static LRESULT CALLBACK CallWindowProcHook(int code, WPARAM wParam, 327 LPARAM lParam); 328 void SetEventHooks(); 329 void ResetEventHooks(); 330 HHOOK mNestedEventHook; 331 HHOOK mGlobalCallWndProcHook; 332 333 public: 334 bool mAsyncRenderSupport; 335 #endif 336 }; 337 338 } /* namespace plugins */ 339 } /* namespace mozilla */ 340 341 #endif // ifndef dom_plugins_PluginModuleChild_h 342