dom/plugins/ipc/PluginModuleChild.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:bb093ce6c320
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 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 "nsAutoPtr.h"
23 #include "nsDataHashtable.h"
24 #include "nsTHashtable.h"
25 #include "nsHashKeys.h"
26
27 #ifdef MOZ_WIDGET_COCOA
28 #include "PluginInterposeOSX.h"
29 #endif
30
31 #include "mozilla/plugins/PPluginModuleChild.h"
32 #include "mozilla/plugins/PluginInstanceChild.h"
33 #include "mozilla/plugins/PluginIdentifierChild.h"
34 #include "mozilla/plugins/PluginMessageUtils.h"
35
36 // NOTE: stolen from nsNPAPIPlugin.h
37
38 #if defined(XP_WIN)
39 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
40 #else
41 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
42 #endif
43
44 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
45 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
46 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks);
47 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
48
49 namespace mozilla {
50 namespace dom {
51 class PCrashReporterChild;
52 }
53
54 namespace plugins {
55
56 #ifdef MOZ_WIDGET_QT
57 class NestedLoopTimer;
58 static const int kNestedLoopDetectorIntervalMs = 90;
59 #endif
60
61 class PluginScriptableObjectChild;
62 class PluginInstanceChild;
63
64 class PluginModuleChild : public PPluginModuleChild
65 {
66 typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
67 protected:
68 virtual mozilla::ipc::RacyInterruptPolicy
69 MediateInterruptRace(const Message& parent, const Message& child) MOZ_OVERRIDE
70 {
71 return MediateRace(parent, child);
72 }
73
74 virtual bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
75
76 // Implement the PPluginModuleChild interface
77 virtual bool AnswerNP_GetEntryPoints(NPError* rv) MOZ_OVERRIDE;
78 virtual bool AnswerNP_Initialize(const uint32_t& aFlags, NPError* rv) MOZ_OVERRIDE;
79
80 virtual PPluginIdentifierChild*
81 AllocPPluginIdentifierChild(const nsCString& aString,
82 const int32_t& aInt,
83 const bool& aTemporary) MOZ_OVERRIDE;
84
85 virtual bool
86 RecvPPluginIdentifierConstructor(PPluginIdentifierChild* actor,
87 const nsCString& aString,
88 const int32_t& aInt,
89 const bool& aTemporary) MOZ_OVERRIDE;
90
91 virtual bool
92 DeallocPPluginIdentifierChild(PPluginIdentifierChild* aActor) MOZ_OVERRIDE;
93
94 virtual PPluginInstanceChild*
95 AllocPPluginInstanceChild(const nsCString& aMimeType,
96 const uint16_t& aMode,
97 const InfallibleTArray<nsCString>& aNames,
98 const InfallibleTArray<nsCString>& aValues,
99 NPError* rv) MOZ_OVERRIDE;
100
101 virtual bool
102 DeallocPPluginInstanceChild(PPluginInstanceChild* aActor) MOZ_OVERRIDE;
103
104 virtual bool
105 AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
106 const nsCString& aMimeType,
107 const uint16_t& aMode,
108 const InfallibleTArray<nsCString>& aNames,
109 const InfallibleTArray<nsCString>& aValues,
110 NPError* rv) MOZ_OVERRIDE;
111 virtual bool
112 AnswerNP_Shutdown(NPError *rv) MOZ_OVERRIDE;
113
114 virtual bool
115 AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
116 bool *aClearSiteData,
117 bool *aGetSitesWithData) MOZ_OVERRIDE;
118
119 virtual bool
120 AnswerNPP_ClearSiteData(const nsCString& aSite,
121 const uint64_t& aFlags,
122 const uint64_t& aMaxAge,
123 NPError* aResult) MOZ_OVERRIDE;
124
125 virtual bool
126 AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult) MOZ_OVERRIDE;
127
128 virtual bool
129 RecvSetAudioSessionData(const nsID& aId,
130 const nsString& aDisplayName,
131 const nsString& aIconPath) MOZ_OVERRIDE;
132
133 virtual bool
134 RecvSetParentHangTimeout(const uint32_t& aSeconds) MOZ_OVERRIDE;
135
136 virtual PCrashReporterChild*
137 AllocPCrashReporterChild(mozilla::dom::NativeThreadId* id,
138 uint32_t* processType) MOZ_OVERRIDE;
139 virtual bool
140 DeallocPCrashReporterChild(PCrashReporterChild* actor) MOZ_OVERRIDE;
141 virtual bool
142 AnswerPCrashReporterConstructor(PCrashReporterChild* actor,
143 mozilla::dom::NativeThreadId* id,
144 uint32_t* processType) MOZ_OVERRIDE;
145
146 virtual void
147 ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
148
149 MOZ_NORETURN void QuickExit();
150
151 virtual bool
152 RecvProcessNativeEventsInInterruptCall() MOZ_OVERRIDE;
153
154 virtual bool
155 AnswerGeckoGetProfile(nsCString* aProfile) MOZ_OVERRIDE;
156
157 public:
158 PluginModuleChild();
159 virtual ~PluginModuleChild();
160
161 // aPluginFilename is UTF8, not native-charset!
162 bool Init(const std::string& aPluginFilename,
163 base::ProcessHandle aParentProcessHandle,
164 MessageLoop* aIOLoop,
165 IPC::Channel* aChannel);
166
167 void CleanUp();
168
169 const char* GetUserAgent();
170
171 static const NPNetscapeFuncs sBrowserFuncs;
172
173 static PluginModuleChild* current();
174
175 bool RegisterActorForNPObject(NPObject* aObject,
176 PluginScriptableObjectChild* aActor);
177
178 void UnregisterActorForNPObject(NPObject* aObject);
179
180 PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
181
182 #ifdef DEBUG
183 bool NPObjectIsRegistered(NPObject* aObject);
184 #endif
185
186 bool AsyncDrawingAllowed() { return mAsyncDrawingAllowed; }
187
188 /**
189 * The child implementation of NPN_CreateObject.
190 */
191 static NPObject* NPN_CreateObject(NPP aNPP, NPClass* aClass);
192 /**
193 * The child implementation of NPN_RetainObject.
194 */
195 static NPObject* NPN_RetainObject(NPObject* aNPObj);
196 /**
197 * The child implementation of NPN_ReleaseObject.
198 */
199 static void NPN_ReleaseObject(NPObject* aNPObj);
200
201 /**
202 * The child implementations of NPIdentifier-related functions.
203 */
204 static NPIdentifier NPN_GetStringIdentifier(const NPUTF8* aName);
205 static void NPN_GetStringIdentifiers(const NPUTF8** aNames,
206 int32_t aNameCount,
207 NPIdentifier* aIdentifiers);
208 static NPIdentifier NPN_GetIntIdentifier(int32_t aIntId);
209 static bool NPN_IdentifierIsString(NPIdentifier aIdentifier);
210 static NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier aIdentifier);
211 static int32_t NPN_IntFromIdentifier(NPIdentifier aIdentifier);
212
213 #ifdef MOZ_WIDGET_COCOA
214 void ProcessNativeEvents();
215
216 void PluginShowWindow(uint32_t window_id, bool modal, CGRect r) {
217 SendPluginShowWindow(window_id, modal, r.origin.x, r.origin.y, r.size.width, r.size.height);
218 }
219
220 void PluginHideWindow(uint32_t window_id) {
221 SendPluginHideWindow(window_id);
222 }
223
224 void SetCursor(NSCursorInfo& cursorInfo) {
225 SendSetCursor(cursorInfo);
226 }
227
228 void ShowCursor(bool show) {
229 SendShowCursor(show);
230 }
231
232 void PushCursor(NSCursorInfo& cursorInfo) {
233 SendPushCursor(cursorInfo);
234 }
235
236 void PopCursor() {
237 SendPopCursor();
238 }
239
240 bool GetNativeCursorsSupported() {
241 bool supported = false;
242 SendGetNativeCursorsSupported(&supported);
243 return supported;
244 }
245 #endif
246
247 // Quirks mode support for various plugin mime types
248 enum PluginQuirks {
249 QUIRKS_NOT_INITIALIZED = 0,
250 // Silverlight assumes it is transparent in windowless mode. This quirk
251 // matches the logic in nsNPAPIPluginInstance::SetWindowless.
252 QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT = 1 << 0,
253 // Win32: Hook TrackPopupMenu api so that we can swap out parent
254 // hwnds. The api will fail with parents not associated with our
255 // child ui thread. See WinlessHandleEvent for details.
256 QUIRK_WINLESS_TRACKPOPUP_HOOK = 1 << 1,
257 // Win32: Throttle flash WM_USER+1 heart beat messages to prevent
258 // flooding chromium's dispatch loop, which can cause ipc traffic
259 // processing lag.
260 QUIRK_FLASH_THROTTLE_WMUSER_EVENTS = 1 << 2,
261 // Win32: Catch resets on our subclass by hooking SetWindowLong.
262 QUIRK_FLASH_HOOK_SETLONGPTR = 1 << 3,
263 // X11: Work around a bug in Flash up to 10.1 d51 at least, where
264 // expose event top left coordinates within the plugin-rect and
265 // not at the drawable origin are misinterpreted.
266 QUIRK_FLASH_EXPOSE_COORD_TRANSLATION = 1 << 4,
267 // Win32: Catch get window info calls on the browser and tweak the
268 // results so mouse input works when flash is displaying it's settings
269 // window.
270 QUIRK_FLASH_HOOK_GETWINDOWINFO = 1 << 5,
271 // Win: Addresses a flash bug with mouse capture and full screen
272 // windows.
273 QUIRK_FLASH_FIXUP_MOUSE_CAPTURE = 1 << 6,
274 // Win: QuickTime steals focus on SetWindow calls even if it's hidden.
275 // Avoid calling SetWindow in that case.
276 QUIRK_QUICKTIME_AVOID_SETWINDOW = 1 << 7,
277 // Win: Check to make sure the parent window has focus before calling
278 // set focus on the child. Addresses a full screen dialog prompt
279 // problem in Silverlight.
280 QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT = 1 << 8,
281 // Mac: Allow the plugin to use offline renderer mode.
282 // Use this only if the plugin is certified the support the offline renderer.
283 QUIRK_ALLOW_OFFLINE_RENDERER = 1 << 9,
284 // Mac: Work around a Flash bug that can cause plugin process crashes
285 // in CoreGraphics mode: The Flash plugin sometimes accesses the
286 // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect)
287 // outside of that call. See bug 804606.
288 QUIRK_FLASH_AVOID_CGMODE_CRASHES = 1 << 10,
289 };
290
291 int GetQuirks() { return mQuirks; }
292
293 private:
294 void AddQuirk(PluginQuirks quirk) {
295 if (mQuirks == QUIRKS_NOT_INITIALIZED)
296 mQuirks = 0;
297 mQuirks |= quirk;
298 }
299 void InitQuirksModes(const nsCString& aMimeType);
300 bool InitGraphics();
301 void DeinitGraphics();
302 #if defined(MOZ_WIDGET_GTK)
303 static gboolean DetectNestedEventLoop(gpointer data);
304 static gboolean ProcessBrowserEvents(gpointer data);
305
306 virtual void EnteredCxxStack() MOZ_OVERRIDE;
307 virtual void ExitedCxxStack() MOZ_OVERRIDE;
308 #elif defined(MOZ_WIDGET_QT)
309
310 virtual void EnteredCxxStack() MOZ_OVERRIDE;
311 virtual void ExitedCxxStack() MOZ_OVERRIDE;
312 #endif
313
314 PRLibrary* mLibrary;
315 nsCString mPluginFilename; // UTF8
316 nsCString mUserAgent;
317 int mQuirks;
318 bool mAsyncDrawingAllowed;
319
320 // we get this from the plugin
321 NP_PLUGINSHUTDOWN mShutdownFunc;
322 #if defined(OS_LINUX) || defined(OS_BSD)
323 NP_PLUGINUNIXINIT mInitializeFunc;
324 #elif defined(OS_WIN) || defined(OS_MACOSX)
325 NP_PLUGININIT mInitializeFunc;
326 NP_GETENTRYPOINTS mGetEntryPointsFunc;
327 #endif
328
329 NPPluginFuncs mFunctions;
330 NPSavedData mSavedData;
331
332 #if defined(MOZ_WIDGET_GTK)
333 // If a plugin spins a nested glib event loop in response to a
334 // synchronous IPC message from the browser, the loop might break
335 // only after the browser responds to a request sent by the
336 // plugin. This can happen if a plugin uses gtk's synchronous
337 // copy/paste, for example. But because the browser is blocked on
338 // a condvar, it can't respond to the request. This situation
339 // isn't technically a deadlock, but the symptoms are basically
340 // the same from the user's perspective.
341 //
342 // We take two steps to prevent this
343 //
344 // (1) Detect nested event loops spun by the plugin. This is
345 // done by scheduling a glib timer event in the plugin
346 // process whenever the browser might block on the plugin.
347 // If the plugin indeed spins a nested loop, this timer event
348 // will fire "soon" thereafter.
349 //
350 // (2) When a nested loop is detected, deschedule the
351 // nested-loop-detection timer and in its place, schedule
352 // another timer that periodically calls back into the
353 // browser and spins a mini event loop. This mini event loop
354 // processes a handful of pending native events.
355 //
356 // Because only timer (1) or (2) (or neither) may be active at any
357 // point in time, we use the same member variable
358 // |mNestedLoopTimerId| to refer to both.
359 //
360 // When the browser no longer might be blocked on a plugin's IPC
361 // response, we deschedule whichever of (1) or (2) is active.
362 guint mNestedLoopTimerId;
363 # ifdef DEBUG
364 // Depth of the stack of calls to g_main_context_dispatch before any
365 // nested loops are run. This is 1 when IPC calls are dispatched from
366 // g_main_context_iteration, or 0 when dispatched directly from
367 // MessagePumpForUI.
368 int mTopLoopDepth;
369 # endif
370 #elif defined (MOZ_WIDGET_QT)
371 NestedLoopTimer *mNestedLoopTimerObject;
372 #endif
373
374 struct NPObjectData : public nsPtrHashKey<NPObject>
375 {
376 NPObjectData(const NPObject* key)
377 : nsPtrHashKey<NPObject>(key)
378 , instance(nullptr)
379 , actor(nullptr)
380 { }
381
382 // never nullptr
383 PluginInstanceChild* instance;
384
385 // sometimes nullptr (no actor associated with an NPObject)
386 PluginScriptableObjectChild* actor;
387 };
388 /**
389 * mObjectMap contains all the currently active NPObjects (from NPN_CreateObject until the
390 * final release/dealloc, whether or not an actor is currently associated with the object.
391 */
392 nsTHashtable<NPObjectData> mObjectMap;
393
394 friend class PluginIdentifierChild;
395 friend class PluginIdentifierChildString;
396 friend class PluginIdentifierChildInt;
397 nsDataHashtable<nsCStringHashKey, PluginIdentifierChildString*> mStringIdentifiers;
398 nsDataHashtable<nsUint32HashKey, PluginIdentifierChildInt*> mIntIdentifiers;
399
400 public: // called by PluginInstanceChild
401 /**
402 * Dealloc an NPObject after last-release or when the associated instance
403 * is destroyed. This function will remove the object from mObjectMap.
404 */
405 static void DeallocNPObject(NPObject* o);
406
407 NPError NPP_Destroy(PluginInstanceChild* instance) {
408 return mFunctions.destroy(instance->GetNPP(), 0);
409 }
410
411 /**
412 * Fill PluginInstanceChild.mDeletingHash with all the remaining NPObjects
413 * associated with that instance.
414 */
415 void FindNPObjectsForInstance(PluginInstanceChild* instance);
416
417 private:
418 static PLDHashOperator CollectForInstance(NPObjectData* d, void* userArg);
419
420 #if defined(OS_WIN)
421 virtual void EnteredCall() MOZ_OVERRIDE;
422 virtual void ExitedCall() MOZ_OVERRIDE;
423
424 // Entered/ExitedCall notifications keep track of whether the plugin has
425 // entered a nested event loop within this interrupt call.
426 struct IncallFrame
427 {
428 IncallFrame()
429 : _spinning(false)
430 , _savedNestableTasksAllowed(false)
431 { }
432
433 bool _spinning;
434 bool _savedNestableTasksAllowed;
435 };
436
437 nsAutoTArray<IncallFrame, 8> mIncallPumpingStack;
438
439 static LRESULT CALLBACK NestedInputEventHook(int code,
440 WPARAM wParam,
441 LPARAM lParam);
442 static LRESULT CALLBACK CallWindowProcHook(int code,
443 WPARAM wParam,
444 LPARAM lParam);
445 void SetEventHooks();
446 void ResetEventHooks();
447 HHOOK mNestedEventHook;
448 HHOOK mGlobalCallWndProcHook;
449 #endif
450 };
451
452 } /* namespace plugins */
453 } /* namespace mozilla */
454
455 #endif // ifndef dom_plugins_PluginModuleChild_h

mercurial