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