1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Plugin App.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Chris Jones <jones.chris.g@gmail.com>
20 : * Portions created by the Initial Developer are Copyright (C) 2009
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifdef MOZ_WIDGET_GTK2
40 : #include <glib.h>
41 : #elif XP_MACOSX
42 : #include "PluginInterposeOSX.h"
43 : #include "PluginUtilsOSX.h"
44 : #include "nsIPrefService.h"
45 : #include "nsIPrefBranch.h"
46 : #endif
47 : #ifdef MOZ_WIDGET_QT
48 : #include <QtCore/QCoreApplication>
49 : #include <QtCore/QEventLoop>
50 : #endif
51 :
52 : #include "base/process_util.h"
53 :
54 : #include "mozilla/Preferences.h"
55 : #include "mozilla/unused.h"
56 : #include "mozilla/ipc/SyncChannel.h"
57 : #include "mozilla/plugins/PluginModuleParent.h"
58 : #include "mozilla/plugins/BrowserStreamParent.h"
59 : #include "mozilla/dom/PCrashReporterParent.h"
60 : #include "PluginIdentifierParent.h"
61 :
62 : #include "nsAutoPtr.h"
63 : #include "nsCRT.h"
64 : #ifdef MOZ_CRASHREPORTER
65 : #include "mozilla/dom/CrashReporterParent.h"
66 : #endif
67 : #include "nsNPAPIPlugin.h"
68 : #include "nsILocalFile.h"
69 :
70 : #ifdef XP_WIN
71 : #include "mozilla/widget/AudioSession.h"
72 : #endif
73 : #include "sampler.h"
74 :
75 : using base::KillProcess;
76 :
77 : using mozilla::PluginLibrary;
78 : using mozilla::ipc::SyncChannel;
79 : using mozilla::dom::PCrashReporterParent;
80 : using mozilla::dom::CrashReporterParent;
81 :
82 : using namespace mozilla;
83 : using namespace mozilla::plugins;
84 : using namespace mozilla::plugins::parent;
85 :
86 : static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
87 : static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
88 : static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
89 :
90 : template<>
91 : struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
92 : {
93 : typedef mozilla::plugins::PluginModuleParent Class;
94 : static void RetainCallee(Class* obj) { }
95 : static void ReleaseCallee(Class* obj) { }
96 : };
97 :
98 : // static
99 : PluginLibrary*
100 0 : PluginModuleParent::LoadModule(const char* aFilePath)
101 : {
102 0 : PLUGIN_LOG_DEBUG_FUNCTION;
103 :
104 0 : PRInt32 prefSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
105 :
106 : // Block on the child process being launched and initialized.
107 0 : nsAutoPtr<PluginModuleParent> parent(new PluginModuleParent(aFilePath));
108 0 : bool launched = parent->mSubprocess->Launch(prefSecs * 1000);
109 0 : if (!launched) {
110 : // Need to set this so the destructor doesn't complain.
111 0 : parent->mShutdown = true;
112 0 : return nsnull;
113 : }
114 0 : parent->Open(parent->mSubprocess->GetChannel(),
115 0 : parent->mSubprocess->GetChildProcessHandle());
116 :
117 0 : TimeoutChanged(kChildTimeoutPref, parent);
118 :
119 : #ifdef MOZ_CRASHREPORTER
120 : // If this fails, we're having IPC troubles, and we're doomed anyways.
121 0 : if (!CrashReporterParent::CreateCrashReporter(parent.get())) {
122 0 : parent->mShutdown = true;
123 0 : return nsnull;
124 : }
125 : #endif
126 :
127 0 : return parent.forget();
128 : }
129 :
130 :
131 0 : PluginModuleParent::PluginModuleParent(const char* aFilePath)
132 0 : : mSubprocess(new PluginProcessParent(aFilePath))
133 : , mShutdown(false)
134 : , mClearSiteDataSupported(false)
135 : , mGetSitesWithDataSupported(false)
136 : , mNPNIface(NULL)
137 : , mPlugin(NULL)
138 0 : , mTaskFactory(this)
139 : {
140 0 : NS_ASSERTION(mSubprocess, "Out of memory!");
141 :
142 0 : if (!mIdentifiers.Init()) {
143 0 : NS_ERROR("Out of memory");
144 : }
145 :
146 0 : Preferences::RegisterCallback(TimeoutChanged, kChildTimeoutPref, this);
147 0 : Preferences::RegisterCallback(TimeoutChanged, kParentTimeoutPref, this);
148 0 : }
149 :
150 0 : PluginModuleParent::~PluginModuleParent()
151 : {
152 0 : NS_ASSERTION(OkToCleanup(), "unsafe destruction");
153 :
154 0 : if (!mShutdown) {
155 0 : NS_WARNING("Plugin host deleted the module without shutting down.");
156 : NPError err;
157 0 : NP_Shutdown(&err);
158 : }
159 0 : NS_ASSERTION(mShutdown, "NP_Shutdown didn't");
160 :
161 0 : if (mSubprocess) {
162 0 : mSubprocess->Delete();
163 0 : mSubprocess = nsnull;
164 : }
165 :
166 0 : Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
167 0 : Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
168 0 : }
169 :
170 : #ifdef MOZ_CRASHREPORTER
171 : void
172 0 : PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
173 : {
174 : typedef nsDependentCString CS;
175 :
176 : // Get the plugin filename, try to get just the file leafname
177 0 : const std::string& pluginFile = mSubprocess->GetPluginFilePath();
178 0 : size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
179 0 : if (filePos == std::string::npos)
180 0 : filePos = 0;
181 : else
182 0 : filePos++;
183 0 : notes.Put(CS("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
184 :
185 : //TODO: add plugin name and version: bug 539841
186 : // (as PluginName, PluginVersion)
187 0 : notes.Put(CS("PluginName"), CS(""));
188 0 : notes.Put(CS("PluginVersion"), CS(""));
189 :
190 0 : const nsString& hangID = CrashReporter()->HangID();
191 0 : if (!hangID.IsEmpty())
192 0 : notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
193 0 : }
194 : #endif // MOZ_CRASHREPORTER
195 :
196 : int
197 0 : PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
198 : {
199 0 : NS_ASSERTION(NS_IsMainThread(), "Wrong thead!");
200 0 : if (!strcmp(aPref, kChildTimeoutPref)) {
201 : // The timeout value used by the parent for children
202 0 : PRInt32 timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
203 : int32 timeoutMs = (timeoutSecs > 0) ? (1000 * timeoutSecs) :
204 0 : SyncChannel::kNoTimeout;
205 0 : static_cast<PluginModuleParent*>(aModule)->SetReplyTimeoutMs(timeoutMs);
206 0 : } else if (!strcmp(aPref, kParentTimeoutPref)) {
207 : // The timeout value used by the child for its parent
208 0 : PRInt32 timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
209 0 : unused << static_cast<PluginModuleParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs);
210 : }
211 0 : return 0;
212 : }
213 :
214 : void
215 0 : PluginModuleParent::CleanupFromTimeout()
216 : {
217 0 : if (!mShutdown)
218 0 : Close();
219 0 : }
220 :
221 : bool
222 0 : PluginModuleParent::ShouldContinueFromReplyTimeout()
223 : {
224 : #ifdef MOZ_CRASHREPORTER
225 0 : CrashReporterParent* crashReporter = CrashReporter();
226 0 : if (crashReporter->GeneratePairedMinidump(this)) {
227 0 : mBrowserDumpID = crashReporter->ParentDumpID();
228 0 : mPluginDumpID = crashReporter->ChildDumpID();
229 0 : PLUGIN_LOG_DEBUG(
230 : ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
231 : NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
232 : NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
233 : NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
234 : } else {
235 0 : NS_WARNING("failed to capture paired minidumps from hang");
236 : }
237 : #endif
238 :
239 : // this must run before the error notification from the channel,
240 : // or not at all
241 : MessageLoop::current()->PostTask(
242 : FROM_HERE,
243 : mTaskFactory.NewRunnableMethod(
244 0 : &PluginModuleParent::CleanupFromTimeout));
245 :
246 0 : if (!KillProcess(OtherProcess(), 1, false))
247 0 : NS_WARNING("failed to kill subprocess!");
248 :
249 0 : return false;
250 : }
251 :
252 : #ifdef MOZ_CRASHREPORTER
253 : CrashReporterParent*
254 0 : PluginModuleParent::CrashReporter()
255 : {
256 0 : MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
257 0 : return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
258 : }
259 : #endif
260 :
261 : void
262 0 : PluginModuleParent::ActorDestroy(ActorDestroyReason why)
263 : {
264 0 : switch (why) {
265 : case AbnormalShutdown: {
266 : #ifdef MOZ_CRASHREPORTER
267 0 : CrashReporterParent* crashReporter = CrashReporter();
268 :
269 0 : CrashReporter::AnnotationTable notes;
270 0 : notes.Init(4);
271 0 : WriteExtraDataForMinidump(notes);
272 :
273 0 : if (crashReporter->GenerateCrashReport(this, ¬es)) {
274 0 : mPluginDumpID = crashReporter->ChildDumpID();
275 0 : PLUGIN_LOG_DEBUG(("got child minidump: %s",
276 : NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
277 : }
278 0 : else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
279 0 : crashReporter->GenerateHangCrashReport(¬es);
280 : }
281 : else {
282 0 : NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
283 : }
284 : #endif
285 :
286 0 : mShutdown = true;
287 : // Defer the PluginCrashed method so that we don't re-enter
288 : // and potentially modify the actor child list while enumerating it.
289 0 : if (mPlugin)
290 : MessageLoop::current()->PostTask(
291 : FROM_HERE,
292 : mTaskFactory.NewRunnableMethod(
293 0 : &PluginModuleParent::NotifyPluginCrashed));
294 : break;
295 : }
296 : case NormalShutdown:
297 0 : mShutdown = true;
298 0 : break;
299 :
300 : default:
301 0 : NS_ERROR("Unexpected shutdown reason for toplevel actor.");
302 : }
303 0 : }
304 :
305 : void
306 0 : PluginModuleParent::NotifyPluginCrashed()
307 : {
308 0 : if (!OkToCleanup()) {
309 : // there's still plugin code on the C++ stack. try again
310 : MessageLoop::current()->PostDelayedTask(
311 : FROM_HERE,
312 : mTaskFactory.NewRunnableMethod(
313 0 : &PluginModuleParent::NotifyPluginCrashed), 10);
314 0 : return;
315 : }
316 :
317 0 : if (mPlugin)
318 0 : mPlugin->PluginCrashed(mPluginDumpID, mBrowserDumpID);
319 : }
320 :
321 : PPluginIdentifierParent*
322 0 : PluginModuleParent::AllocPPluginIdentifier(const nsCString& aString,
323 : const int32_t& aInt,
324 : const bool& aTemporary)
325 : {
326 0 : if (aTemporary) {
327 0 : NS_ERROR("Plugins don't create temporary identifiers.");
328 0 : return NULL; // should abort the plugin
329 : }
330 :
331 0 : NPIdentifier npident = aString.IsVoid() ?
332 0 : mozilla::plugins::parent::_getintidentifier(aInt) :
333 0 : mozilla::plugins::parent::_getstringidentifier(aString.get());
334 :
335 0 : if (!npident) {
336 0 : NS_WARNING("Failed to get identifier!");
337 0 : return nsnull;
338 : }
339 :
340 0 : PluginIdentifierParent* ident = new PluginIdentifierParent(npident, false);
341 0 : mIdentifiers.Put(npident, ident);
342 0 : return ident;
343 : }
344 :
345 : bool
346 0 : PluginModuleParent::DeallocPPluginIdentifier(PPluginIdentifierParent* aActor)
347 : {
348 0 : delete aActor;
349 0 : return true;
350 : }
351 :
352 : PPluginInstanceParent*
353 0 : PluginModuleParent::AllocPPluginInstance(const nsCString& aMimeType,
354 : const uint16_t& aMode,
355 : const InfallibleTArray<nsCString>& aNames,
356 : const InfallibleTArray<nsCString>& aValues,
357 : NPError* rv)
358 : {
359 0 : NS_ERROR("Not reachable!");
360 0 : return NULL;
361 : }
362 :
363 : bool
364 0 : PluginModuleParent::DeallocPPluginInstance(PPluginInstanceParent* aActor)
365 : {
366 0 : PLUGIN_LOG_DEBUG_METHOD;
367 0 : delete aActor;
368 0 : return true;
369 : }
370 :
371 : void
372 0 : PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
373 : {
374 0 : aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
375 0 : aFuncs->javaClass = nsnull;
376 :
377 : // Gecko should always call these functions through a PluginLibrary object.
378 0 : aFuncs->newp = NULL;
379 0 : aFuncs->clearsitedata = NULL;
380 0 : aFuncs->getsiteswithdata = NULL;
381 :
382 0 : aFuncs->destroy = NPP_Destroy;
383 0 : aFuncs->setwindow = NPP_SetWindow;
384 0 : aFuncs->newstream = NPP_NewStream;
385 0 : aFuncs->destroystream = NPP_DestroyStream;
386 0 : aFuncs->asfile = NPP_StreamAsFile;
387 0 : aFuncs->writeready = NPP_WriteReady;
388 0 : aFuncs->write = NPP_Write;
389 0 : aFuncs->print = NPP_Print;
390 0 : aFuncs->event = NPP_HandleEvent;
391 0 : aFuncs->urlnotify = NPP_URLNotify;
392 0 : aFuncs->getvalue = NPP_GetValue;
393 0 : aFuncs->setvalue = NPP_SetValue;
394 0 : aFuncs->gotfocus = NULL;
395 0 : aFuncs->lostfocus = NULL;
396 0 : aFuncs->urlredirectnotify = NULL;
397 :
398 : // Provide 'NPP_URLRedirectNotify', 'NPP_ClearSiteData', and
399 : // 'NPP_GetSitesWithData' functionality if it is supported by the plugin.
400 0 : bool urlRedirectSupported = false;
401 : unused << CallOptionalFunctionsSupported(&urlRedirectSupported,
402 : &mClearSiteDataSupported,
403 0 : &mGetSitesWithDataSupported);
404 0 : if (urlRedirectSupported) {
405 0 : aFuncs->urlredirectnotify = NPP_URLRedirectNotify;
406 : }
407 0 : }
408 :
409 : NPError
410 0 : PluginModuleParent::NPP_Destroy(NPP instance,
411 : NPSavedData** /*saved*/)
412 : {
413 : // FIXME/cjones:
414 : // (1) send a "destroy" message to the child
415 : // (2) the child shuts down its instance
416 : // (3) remove both parent and child IDs from map
417 : // (4) free parent
418 0 : PLUGIN_LOG_DEBUG_FUNCTION;
419 :
420 : PluginInstanceParent* parentInstance =
421 0 : static_cast<PluginInstanceParent*>(instance->pdata);
422 :
423 0 : if (!parentInstance)
424 0 : return NPERR_NO_ERROR;
425 :
426 0 : NPError retval = parentInstance->Destroy();
427 0 : instance->pdata = nsnull;
428 :
429 0 : unused << PluginInstanceParent::Call__delete__(parentInstance);
430 0 : return retval;
431 : }
432 :
433 : NPError
434 0 : PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type,
435 : NPStream* stream, NPBool seekable,
436 : uint16_t* stype)
437 : {
438 0 : SAMPLE_LABEL("PluginModuleParent", "NPP_NewStream");
439 0 : PluginInstanceParent* i = InstCast(instance);
440 0 : if (!i)
441 0 : return NPERR_GENERIC_ERROR;
442 :
443 : return i->NPP_NewStream(type, stream, seekable,
444 0 : stype);
445 : }
446 :
447 : NPError
448 0 : PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window)
449 : {
450 0 : PluginInstanceParent* i = InstCast(instance);
451 0 : if (!i)
452 0 : return NPERR_GENERIC_ERROR;
453 :
454 0 : return i->NPP_SetWindow(window);
455 : }
456 :
457 : NPError
458 0 : PluginModuleParent::NPP_DestroyStream(NPP instance,
459 : NPStream* stream,
460 : NPReason reason)
461 : {
462 0 : PluginInstanceParent* i = InstCast(instance);
463 0 : if (!i)
464 0 : return NPERR_GENERIC_ERROR;
465 :
466 0 : return i->NPP_DestroyStream(stream, reason);
467 : }
468 :
469 : int32_t
470 0 : PluginModuleParent::NPP_WriteReady(NPP instance,
471 : NPStream* stream)
472 : {
473 0 : BrowserStreamParent* s = StreamCast(instance, stream);
474 0 : if (!s)
475 0 : return -1;
476 :
477 0 : return s->WriteReady();
478 : }
479 :
480 : int32_t
481 0 : PluginModuleParent::NPP_Write(NPP instance,
482 : NPStream* stream,
483 : int32_t offset,
484 : int32_t len,
485 : void* buffer)
486 : {
487 0 : BrowserStreamParent* s = StreamCast(instance, stream);
488 0 : if (!s)
489 0 : return -1;
490 :
491 0 : return s->Write(offset, len, buffer);
492 : }
493 :
494 : void
495 0 : PluginModuleParent::NPP_StreamAsFile(NPP instance,
496 : NPStream* stream,
497 : const char* fname)
498 : {
499 0 : BrowserStreamParent* s = StreamCast(instance, stream);
500 0 : if (!s)
501 0 : return;
502 :
503 0 : s->StreamAsFile(fname);
504 : }
505 :
506 : void
507 0 : PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint)
508 : {
509 0 : PluginInstanceParent* i = InstCast(instance);
510 0 : if (i)
511 0 : i->NPP_Print(platformPrint);
512 0 : }
513 :
514 : int16_t
515 0 : PluginModuleParent::NPP_HandleEvent(NPP instance, void* event)
516 : {
517 0 : PluginInstanceParent* i = InstCast(instance);
518 0 : if (!i)
519 0 : return false;
520 :
521 0 : return i->NPP_HandleEvent(event);
522 : }
523 :
524 : void
525 0 : PluginModuleParent::NPP_URLNotify(NPP instance, const char* url,
526 : NPReason reason, void* notifyData)
527 : {
528 0 : PluginInstanceParent* i = InstCast(instance);
529 0 : if (!i)
530 0 : return;
531 :
532 0 : i->NPP_URLNotify(url, reason, notifyData);
533 : }
534 :
535 : NPError
536 0 : PluginModuleParent::NPP_GetValue(NPP instance,
537 : NPPVariable variable, void *ret_value)
538 : {
539 0 : PluginInstanceParent* i = InstCast(instance);
540 0 : if (!i)
541 0 : return NPERR_GENERIC_ERROR;
542 :
543 0 : return i->NPP_GetValue(variable, ret_value);
544 : }
545 :
546 : NPError
547 0 : PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
548 : void *value)
549 : {
550 0 : PluginInstanceParent* i = InstCast(instance);
551 0 : if (!i)
552 0 : return NPERR_GENERIC_ERROR;
553 :
554 0 : return i->NPP_SetValue(variable, value);
555 : }
556 :
557 : bool
558 0 : PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
559 : {
560 : #ifndef MOZ_X11
561 : NS_RUNTIMEABORT("This message only makes sense on X11 platforms");
562 : #else
563 0 : NS_ABORT_IF_FALSE(0 > mPluginXSocketFdDup.mFd,
564 : "Already backed up X resources??");
565 0 : mPluginXSocketFdDup.mFd = aXSocketFd.fd;
566 : #endif
567 0 : return true;
568 : }
569 :
570 : void
571 0 : PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
572 : int32_t status, void* notifyData)
573 : {
574 0 : PluginInstanceParent* i = InstCast(instance);
575 0 : if (!i)
576 0 : return;
577 :
578 0 : i->NPP_URLRedirectNotify(url, status, notifyData);
579 : }
580 :
581 : bool
582 0 : PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent)
583 : {
584 0 : *userAgent = NullableString(mNPNIface->uagent(nsnull));
585 0 : return true;
586 : }
587 :
588 : PluginIdentifierParent*
589 0 : PluginModuleParent::GetIdentifierForNPIdentifier(NPP npp, NPIdentifier aIdentifier)
590 : {
591 : PluginIdentifierParent* ident;
592 0 : if (mIdentifiers.Get(aIdentifier, &ident)) {
593 0 : if (ident->IsTemporary()) {
594 0 : ident->AddTemporaryRef();
595 : }
596 0 : return ident;
597 : }
598 :
599 0 : nsCString string;
600 0 : int32_t intval = -1;
601 0 : bool temporary = false;
602 0 : if (mozilla::plugins::parent::_identifierisstring(aIdentifier)) {
603 : NPUTF8* chars =
604 0 : mozilla::plugins::parent::_utf8fromidentifier(aIdentifier);
605 0 : if (!chars) {
606 0 : return nsnull;
607 : }
608 0 : string.Adopt(chars);
609 0 : temporary = !NPStringIdentifierIsPermanent(npp, aIdentifier);
610 : }
611 : else {
612 0 : intval = mozilla::plugins::parent::_intfromidentifier(aIdentifier);
613 0 : string.SetIsVoid(true);
614 : }
615 :
616 0 : ident = new PluginIdentifierParent(aIdentifier, temporary);
617 0 : if (!SendPPluginIdentifierConstructor(ident, string, intval, temporary))
618 0 : return nsnull;
619 :
620 0 : if (!temporary) {
621 0 : mIdentifiers.Put(aIdentifier, ident);
622 : }
623 0 : return ident;
624 : }
625 :
626 : PluginInstanceParent*
627 0 : PluginModuleParent::InstCast(NPP instance)
628 : {
629 : PluginInstanceParent* ip =
630 0 : static_cast<PluginInstanceParent*>(instance->pdata);
631 :
632 : // If the plugin crashed and the PluginInstanceParent was deleted,
633 : // instance->pdata will be NULL.
634 0 : if (!ip)
635 0 : return NULL;
636 :
637 0 : if (instance != ip->mNPP) {
638 0 : NS_RUNTIMEABORT("Corrupted plugin data.");
639 : }
640 0 : return ip;
641 : }
642 :
643 : BrowserStreamParent*
644 0 : PluginModuleParent::StreamCast(NPP instance,
645 : NPStream* s)
646 : {
647 0 : PluginInstanceParent* ip = InstCast(instance);
648 0 : if (!ip)
649 0 : return NULL;
650 :
651 : BrowserStreamParent* sp =
652 0 : static_cast<BrowserStreamParent*>(static_cast<AStream*>(s->pdata));
653 0 : if (sp->mNPP != ip || s != sp->mStream) {
654 0 : NS_RUNTIMEABORT("Corrupted plugin stream data.");
655 : }
656 0 : return sp;
657 : }
658 :
659 : bool
660 0 : PluginModuleParent::HasRequiredFunctions()
661 : {
662 0 : return true;
663 : }
664 :
665 : nsresult
666 0 : PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
667 : {
668 0 : PluginInstanceParent* i = InstCast(instance);
669 0 : if (!i)
670 0 : return NS_ERROR_FAILURE;
671 :
672 0 : return i->AsyncSetWindow(window);
673 : }
674 :
675 : #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
676 : nsresult
677 : PluginModuleParent::HandleGUIEvent(NPP instance,
678 : const nsGUIEvent& anEvent,
679 : bool* handled)
680 : {
681 : PluginInstanceParent* i = InstCast(instance);
682 : if (!i)
683 : return NS_ERROR_FAILURE;
684 :
685 : return i->HandleGUIEvent(anEvent, handled);
686 : }
687 : #endif
688 :
689 : nsresult
690 0 : PluginModuleParent::GetImageContainer(NPP instance,
691 : mozilla::layers::ImageContainer** aContainer)
692 : {
693 0 : PluginInstanceParent* i = InstCast(instance);
694 0 : return !i ? NS_ERROR_FAILURE : i->GetImageContainer(aContainer);
695 : }
696 :
697 : nsresult
698 0 : PluginModuleParent::GetImageSize(NPP instance,
699 : nsIntSize* aSize)
700 : {
701 0 : PluginInstanceParent* i = InstCast(instance);
702 0 : return !i ? NS_ERROR_FAILURE : i->GetImageSize(aSize);
703 : }
704 :
705 : nsresult
706 0 : PluginModuleParent::SetBackgroundUnknown(NPP instance)
707 : {
708 0 : PluginInstanceParent* i = InstCast(instance);
709 0 : if (!i)
710 0 : return NS_ERROR_FAILURE;
711 :
712 0 : return i->SetBackgroundUnknown();
713 : }
714 :
715 : nsresult
716 0 : PluginModuleParent::BeginUpdateBackground(NPP instance,
717 : const nsIntRect& aRect,
718 : gfxContext** aCtx)
719 : {
720 0 : PluginInstanceParent* i = InstCast(instance);
721 0 : if (!i)
722 0 : return NS_ERROR_FAILURE;
723 :
724 0 : return i->BeginUpdateBackground(aRect, aCtx);
725 : }
726 :
727 : nsresult
728 0 : PluginModuleParent::EndUpdateBackground(NPP instance,
729 : gfxContext* aCtx,
730 : const nsIntRect& aRect)
731 : {
732 0 : PluginInstanceParent* i = InstCast(instance);
733 0 : if (!i)
734 0 : return NS_ERROR_FAILURE;
735 :
736 0 : return i->EndUpdateBackground(aCtx, aRect);
737 : }
738 :
739 : #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
740 : nsresult
741 0 : PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
742 : {
743 0 : PLUGIN_LOG_DEBUG_METHOD;
744 :
745 0 : mNPNIface = bFuncs;
746 :
747 0 : if (mShutdown) {
748 0 : *error = NPERR_GENERIC_ERROR;
749 0 : return NS_ERROR_FAILURE;
750 : }
751 :
752 0 : uint32_t flags = 0;
753 0 : if (mozilla::Preferences::GetBool("plugin.allow.asyncdrawing", false)) {
754 0 : flags |= kAllowAsyncDrawing;
755 : }
756 :
757 0 : if (!CallNP_Initialize(flags, error)) {
758 0 : return NS_ERROR_FAILURE;
759 : }
760 0 : else if (*error != NPERR_NO_ERROR) {
761 0 : return NS_OK;
762 : }
763 :
764 0 : SetPluginFuncs(pFuncs);
765 :
766 0 : return NS_OK;
767 : }
768 : #else
769 : nsresult
770 : PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
771 : {
772 : PLUGIN_LOG_DEBUG_METHOD;
773 :
774 : mNPNIface = bFuncs;
775 :
776 : if (mShutdown) {
777 : *error = NPERR_GENERIC_ERROR;
778 : return NS_ERROR_FAILURE;
779 : }
780 :
781 : uint32_t flags = 0;
782 : if (mozilla::Preferences::GetBool("plugin.allow.asyncdrawing", false)) {
783 : flags |= kAllowAsyncDrawing;
784 : }
785 :
786 : if (!CallNP_Initialize(flags, error))
787 : return NS_ERROR_FAILURE;
788 :
789 : #if defined XP_WIN
790 : // Send the info needed to join the chrome process's audio session to the
791 : // plugin process
792 : nsID id;
793 : nsString sessionName;
794 : nsString iconPath;
795 :
796 : if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
797 : iconPath)))
798 : SendSetAudioSessionData(id, sessionName, iconPath);
799 : #endif
800 :
801 : return NS_OK;
802 : }
803 : #endif
804 :
805 : nsresult
806 0 : PluginModuleParent::NP_Shutdown(NPError* error)
807 : {
808 0 : PLUGIN_LOG_DEBUG_METHOD;
809 :
810 0 : if (mShutdown) {
811 0 : *error = NPERR_GENERIC_ERROR;
812 0 : return NS_ERROR_FAILURE;
813 : }
814 :
815 0 : bool ok = CallNP_Shutdown(error);
816 :
817 : // if NP_Shutdown() is nested within another RPC call, this will
818 : // break things. but lord help us if we're doing that anyway; the
819 : // plugin dso will have been unloaded on the other side by the
820 : // CallNP_Shutdown() message
821 0 : Close();
822 :
823 0 : return ok ? NS_OK : NS_ERROR_FAILURE;
824 : }
825 :
826 : nsresult
827 0 : PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
828 : {
829 0 : PLUGIN_LOG_DEBUG_METHOD;
830 :
831 0 : *mimeDesc = "application/x-foobar";
832 0 : return NS_OK;
833 : }
834 :
835 : nsresult
836 0 : PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable,
837 : void *aValue, NPError* error)
838 : {
839 0 : PR_LOG(gPluginLog, PR_LOG_WARNING, ("%s Not implemented, requested variable %i", __FUNCTION__,
840 : (int) aVariable));
841 :
842 : //TODO: implement this correctly
843 0 : *error = NPERR_GENERIC_ERROR;
844 0 : return NS_OK;
845 : }
846 :
847 : #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
848 : nsresult
849 : PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
850 : {
851 : NS_ASSERTION(pFuncs, "Null pointer!");
852 :
853 : // We need to have the child process update its function table
854 : // here by actually calling NP_GetEntryPoints since the parent's
855 : // function table can reflect NULL entries in the child's table.
856 : if (!CallNP_GetEntryPoints(error)) {
857 : return NS_ERROR_FAILURE;
858 : }
859 : else if (*error != NPERR_NO_ERROR) {
860 : return NS_OK;
861 : }
862 :
863 : SetPluginFuncs(pFuncs);
864 :
865 : return NS_OK;
866 : }
867 : #endif
868 :
869 : nsresult
870 0 : PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
871 : uint16_t mode, int16_t argc, char* argn[],
872 : char* argv[], NPSavedData* saved,
873 : NPError* error)
874 : {
875 0 : PLUGIN_LOG_DEBUG_METHOD;
876 :
877 0 : if (mShutdown) {
878 0 : *error = NPERR_GENERIC_ERROR;
879 0 : return NS_ERROR_FAILURE;
880 : }
881 :
882 : // create the instance on the other side
883 0 : InfallibleTArray<nsCString> names;
884 0 : InfallibleTArray<nsCString> values;
885 :
886 0 : for (int i = 0; i < argc; ++i) {
887 0 : names.AppendElement(NullableString(argn[i]));
888 0 : values.AppendElement(NullableString(argv[i]));
889 : }
890 :
891 : PluginInstanceParent* parentInstance =
892 : new PluginInstanceParent(this, instance,
893 0 : nsDependentCString(pluginType), mNPNIface);
894 :
895 0 : if (!parentInstance->Init()) {
896 0 : delete parentInstance;
897 0 : return NS_ERROR_FAILURE;
898 : }
899 :
900 0 : instance->pdata = parentInstance;
901 :
902 0 : if (!CallPPluginInstanceConstructor(parentInstance,
903 0 : nsDependentCString(pluginType), mode,
904 0 : names, values, error)) {
905 : // |parentInstance| is automatically deleted.
906 0 : instance->pdata = nsnull;
907 : // if IPC is down, we'll get an immediate "failed" return, but
908 : // without *error being set. So make sure that the error
909 : // condition is signaled to nsNPAPIPluginInstance
910 0 : if (NPERR_NO_ERROR == *error)
911 0 : *error = NPERR_GENERIC_ERROR;
912 0 : return NS_ERROR_FAILURE;
913 : }
914 :
915 0 : if (*error != NPERR_NO_ERROR) {
916 0 : NPP_Destroy(instance, 0);
917 0 : return NS_ERROR_FAILURE;
918 : }
919 :
920 0 : TimeoutChanged(kParentTimeoutPref, this);
921 :
922 0 : return NS_OK;
923 : }
924 :
925 : nsresult
926 0 : PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags,
927 : uint64_t maxAge)
928 : {
929 0 : if (!mClearSiteDataSupported)
930 0 : return NS_ERROR_NOT_AVAILABLE;
931 :
932 : NPError result;
933 0 : if (!CallNPP_ClearSiteData(NullableString(site), flags, maxAge, &result))
934 0 : return NS_ERROR_FAILURE;
935 :
936 0 : switch (result) {
937 : case NPERR_NO_ERROR:
938 0 : return NS_OK;
939 : case NPERR_TIME_RANGE_NOT_SUPPORTED:
940 0 : return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
941 : case NPERR_MALFORMED_SITE:
942 0 : return NS_ERROR_INVALID_ARG;
943 : default:
944 0 : return NS_ERROR_FAILURE;
945 : }
946 : }
947 :
948 : nsresult
949 0 : PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
950 : {
951 0 : if (!mGetSitesWithDataSupported)
952 0 : return NS_ERROR_NOT_AVAILABLE;
953 :
954 0 : if (!CallNPP_GetSitesWithData(&result))
955 0 : return NS_ERROR_FAILURE;
956 :
957 0 : return NS_OK;
958 : }
959 :
960 : #if defined(XP_MACOSX)
961 : nsresult
962 : PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
963 : {
964 : PluginInstanceParent* i = InstCast(instance);
965 : if (!i)
966 : return NS_ERROR_FAILURE;
967 :
968 : return i->IsRemoteDrawingCoreAnimation(aDrawing);
969 : }
970 : #endif
971 :
972 : bool
973 0 : PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,
974 : NPError* aError,
975 : bool* aBoolVal)
976 : {
977 0 : NPBool boolVal = false;
978 0 : *aError = mozilla::plugins::parent::_getvalue(nsnull, aVariable, &boolVal);
979 0 : *aBoolVal = boolVal ? true : false;
980 0 : return true;
981 : }
982 :
983 : #if defined(MOZ_WIDGET_QT)
984 : static const int kMaxtimeToProcessEvents = 30;
985 : bool
986 : PluginModuleParent::AnswerProcessSomeEvents()
987 : {
988 : PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
989 : QCoreApplication::processEvents(QEventLoop::AllEvents, kMaxtimeToProcessEvents);
990 :
991 : PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
992 :
993 : return true;
994 : }
995 :
996 : #elif defined(XP_MACOSX)
997 : bool
998 : PluginModuleParent::AnswerProcessSomeEvents()
999 : {
1000 : mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
1001 : return true;
1002 : }
1003 :
1004 : #elif !defined(MOZ_WIDGET_GTK2)
1005 : bool
1006 : PluginModuleParent::AnswerProcessSomeEvents()
1007 : {
1008 : NS_RUNTIMEABORT("unreached");
1009 : return false;
1010 : }
1011 :
1012 : #else
1013 : static const int kMaxChancesToProcessEvents = 20;
1014 :
1015 : bool
1016 0 : PluginModuleParent::AnswerProcessSomeEvents()
1017 : {
1018 0 : PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
1019 :
1020 0 : int i = 0;
1021 0 : for (; i < kMaxChancesToProcessEvents; ++i)
1022 0 : if (!g_main_context_iteration(NULL, FALSE))
1023 0 : break;
1024 :
1025 0 : PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i));
1026 :
1027 0 : return true;
1028 : }
1029 : #endif
1030 :
1031 : bool
1032 0 : PluginModuleParent::RecvProcessNativeEventsInRPCCall()
1033 : {
1034 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1035 : #if defined(OS_WIN)
1036 : ProcessNativeEventsInRPCCall();
1037 : return true;
1038 : #else
1039 : NS_NOTREACHED(
1040 0 : "PluginModuleParent::RecvProcessNativeEventsInRPCCall not implemented!");
1041 0 : return false;
1042 : #endif
1043 : }
1044 :
1045 : void
1046 0 : PluginModuleParent::ProcessRemoteNativeEventsInRPCCall()
1047 : {
1048 : #if defined(OS_WIN)
1049 : SendProcessNativeEventsInRPCCall();
1050 : return;
1051 : #endif
1052 : NS_NOTREACHED(
1053 0 : "PluginModuleParent::ProcessRemoteNativeEventsInRPCCall not implemented!");
1054 0 : }
1055 :
1056 : bool
1057 0 : PluginModuleParent::RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
1058 : const int32_t& aX, const int32_t& aY,
1059 : const size_t& aWidth, const size_t& aHeight)
1060 : {
1061 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1062 : #if defined(XP_MACOSX)
1063 : CGRect windowBound = ::CGRectMake(aX, aY, aWidth, aHeight);
1064 : mac_plugin_interposing::parent::OnPluginShowWindow(aWindowId, windowBound, aModal);
1065 : return true;
1066 : #else
1067 : NS_NOTREACHED(
1068 0 : "PluginInstanceParent::RecvPluginShowWindow not implemented!");
1069 0 : return false;
1070 : #endif
1071 : }
1072 :
1073 : bool
1074 0 : PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
1075 : {
1076 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1077 : #if defined(XP_MACOSX)
1078 : mac_plugin_interposing::parent::OnPluginHideWindow(aWindowId, OtherSidePID());
1079 : return true;
1080 : #else
1081 : NS_NOTREACHED(
1082 0 : "PluginInstanceParent::RecvPluginHideWindow not implemented!");
1083 0 : return false;
1084 : #endif
1085 : }
1086 :
1087 : PCrashReporterParent*
1088 0 : PluginModuleParent::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
1089 : PRUint32* processType)
1090 : {
1091 : #ifdef MOZ_CRASHREPORTER
1092 0 : return new CrashReporterParent();
1093 : #else
1094 : return nsnull;
1095 : #endif
1096 : }
1097 :
1098 : bool
1099 0 : PluginModuleParent::DeallocPCrashReporter(PCrashReporterParent* actor)
1100 : {
1101 0 : delete actor;
1102 0 : return true;
1103 : }
1104 :
1105 : bool
1106 0 : PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
1107 : {
1108 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1109 : #if defined(XP_MACOSX)
1110 : mac_plugin_interposing::parent::OnSetCursor(aCursorInfo);
1111 : return true;
1112 : #else
1113 : NS_NOTREACHED(
1114 0 : "PluginInstanceParent::RecvSetCursor not implemented!");
1115 0 : return false;
1116 : #endif
1117 : }
1118 :
1119 : bool
1120 0 : PluginModuleParent::RecvShowCursor(const bool& aShow)
1121 : {
1122 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1123 : #if defined(XP_MACOSX)
1124 : mac_plugin_interposing::parent::OnShowCursor(aShow);
1125 : return true;
1126 : #else
1127 : NS_NOTREACHED(
1128 0 : "PluginInstanceParent::RecvShowCursor not implemented!");
1129 0 : return false;
1130 : #endif
1131 : }
1132 :
1133 : bool
1134 0 : PluginModuleParent::RecvPushCursor(const NSCursorInfo& aCursorInfo)
1135 : {
1136 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1137 : #if defined(XP_MACOSX)
1138 : mac_plugin_interposing::parent::OnPushCursor(aCursorInfo);
1139 : return true;
1140 : #else
1141 : NS_NOTREACHED(
1142 0 : "PluginInstanceParent::RecvPushCursor not implemented!");
1143 0 : return false;
1144 : #endif
1145 : }
1146 :
1147 : bool
1148 0 : PluginModuleParent::RecvPopCursor()
1149 : {
1150 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1151 : #if defined(XP_MACOSX)
1152 : mac_plugin_interposing::parent::OnPopCursor();
1153 : return true;
1154 : #else
1155 : NS_NOTREACHED(
1156 0 : "PluginInstanceParent::RecvPopCursor not implemented!");
1157 0 : return false;
1158 : #endif
1159 : }
1160 :
1161 : bool
1162 0 : PluginModuleParent::RecvGetNativeCursorsSupported(bool* supported)
1163 : {
1164 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1165 : #if defined(XP_MACOSX)
1166 : bool nativeCursorsSupported = false;
1167 : nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
1168 : if (prefs) {
1169 : if (NS_FAILED(prefs->GetBoolPref("dom.ipc.plugins.nativeCursorSupport",
1170 : &nativeCursorsSupported))) {
1171 : nativeCursorsSupported = false;
1172 : }
1173 : }
1174 : *supported = nativeCursorsSupported;
1175 : return true;
1176 : #else
1177 : NS_NOTREACHED(
1178 0 : "PluginInstanceParent::RecvGetNativeCursorSupportLevel not implemented!");
1179 0 : return false;
1180 : #endif
1181 : }
1182 :
1183 : bool
1184 0 : PluginModuleParent::RecvNPN_SetException(PPluginScriptableObjectParent* aActor,
1185 : const nsCString& aMessage)
1186 : {
1187 0 : PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1188 :
1189 0 : NPObject* aNPObj = NULL;
1190 0 : if (aActor) {
1191 0 : aNPObj = static_cast<PluginScriptableObjectParent*>(aActor)->GetObject(true);
1192 0 : if (!aNPObj) {
1193 0 : NS_ERROR("Failed to get object!");
1194 0 : return false;
1195 : }
1196 : }
1197 0 : mozilla::plugins::parent::_setexception(aNPObj, NullableStringGet(aMessage));
1198 0 : return true;
1199 : }
|