Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/plugins/ipc/PluginModuleParent.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/plugins/PluginModuleParent.h"
8
9
#include "base/process_util.h"
10
#include "mozilla/Attributes.h"
11
#include "mozilla/AutoRestore.h"
12
#include "mozilla/BackgroundHangMonitor.h"
13
#include "mozilla/dom/ContentParent.h"
14
#include "mozilla/dom/ContentChild.h"
15
#include "mozilla/ipc/CrashReporterClient.h"
16
#include "mozilla/ipc/CrashReporterHost.h"
17
#include "mozilla/dom/Element.h"
18
#include "mozilla/ipc/GeckoChildProcessHost.h"
19
#include "mozilla/ipc/MessageChannel.h"
20
#include "mozilla/ipc/ProtocolUtils.h"
21
#include "mozilla/plugins/BrowserStreamParent.h"
22
#include "mozilla/plugins/PluginBridge.h"
23
#include "mozilla/plugins/PluginInstanceParent.h"
24
#include "mozilla/Preferences.h"
25
#include "mozilla/ProcessHangMonitor.h"
26
#include "mozilla/Services.h"
27
#include "mozilla/Telemetry.h"
28
#include "mozilla/Unused.h"
29
#include "nsAutoPtr.h"
30
#include "nsCRT.h"
31
#include "nsIFile.h"
32
#include "nsIObserverService.h"
33
#include "nsIXULRuntime.h"
34
#include "nsNPAPIPlugin.h"
35
#include "nsPrintfCString.h"
36
#include "prsystem.h"
37
#include "prclist.h"
38
#include "PluginQuirks.h"
39
#include "gfxPlatform.h"
40
#include "GeckoProfiler.h"
41
#include "nsPluginTags.h"
42
#include "nsUnicharUtils.h"
43
#include "mozilla/layers/TextureClientRecycleAllocator.h"
44
45
#ifdef XP_WIN
46
#include "mozilla/plugins/PluginSurfaceParent.h"
47
#include "mozilla/widget/AudioSession.h"
48
#include "PluginHangUIParent.h"
49
#include "FunctionBrokerParent.h"
50
#include "PluginUtilsWin.h"
51
#endif
52
53
#ifdef MOZ_WIDGET_GTK
54
#include <glib.h>
55
#elif XP_MACOSX
56
#include "PluginInterposeOSX.h"
57
#include "PluginUtilsOSX.h"
58
#endif
59
60
#ifdef MOZ_GECKO_PROFILER
61
#include "ProfilerParent.h"
62
#endif
63
64
using base::KillProcess;
65
66
using mozilla::PluginLibrary;
67
using mozilla::ipc::MessageChannel;
68
using mozilla::ipc::GeckoChildProcessHost;
69
70
using namespace mozilla;
71
using namespace mozilla::plugins;
72
using namespace mozilla::plugins::parent;
73
74
using namespace CrashReporter;
75
76
static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs";
77
static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
78
static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
79
static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
80
#ifdef XP_WIN
81
static const char kHangUITimeoutPref[] = "dom.ipc.plugins.hangUITimeoutSecs";
82
static const char kHangUIMinDisplayPref[] = "dom.ipc.plugins.hangUIMinDisplaySecs";
83
#define CHILD_TIMEOUT_PREF kHangUITimeoutPref
84
#else
85
0
#define CHILD_TIMEOUT_PREF kChildTimeoutPref
86
#endif
87
88
bool
89
mozilla::plugins::SetupBridge(uint32_t aPluginId,
90
                              dom::ContentParent* aContentParent,
91
                              nsresult* rv,
92
                              uint32_t* runID,
93
                              ipc::Endpoint<PPluginModuleParent>* aEndpoint)
94
0
{
95
0
    AUTO_PROFILER_LABEL("plugins::SetupBridge", OTHER);
96
0
    if (NS_WARN_IF(!rv) || NS_WARN_IF(!runID)) {
97
0
        return false;
98
0
    }
99
0
100
0
    RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
101
0
    RefPtr<nsNPAPIPlugin> plugin;
102
0
    *rv = host->GetPluginForContentProcess(aPluginId, getter_AddRefs(plugin));
103
0
    if (NS_FAILED(*rv)) {
104
0
        return true;
105
0
    }
106
0
    PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
107
0
    *rv = chromeParent->GetRunID(runID);
108
0
    if (NS_FAILED(*rv)) {
109
0
        return true;
110
0
    }
111
0
112
0
    ipc::Endpoint<PPluginModuleParent> parent;
113
0
    ipc::Endpoint<PPluginModuleChild> child;
114
0
115
0
    *rv = PPluginModule::CreateEndpoints(aContentParent->OtherPid(),
116
0
                                         chromeParent->OtherPid(),
117
0
                                         &parent, &child);
118
0
    if (NS_FAILED(*rv)) {
119
0
        return true;
120
0
    }
121
0
122
0
    *aEndpoint = std::move(parent);
123
0
124
0
    if (!chromeParent->SendInitPluginModuleChild(std::move(child))) {
125
0
        *rv = NS_ERROR_BRIDGE_OPEN_CHILD;
126
0
        return true;
127
0
    }
128
0
129
0
    return true;
130
0
}
131
132
#ifdef MOZ_CRASHREPORTER_INJECTOR
133
134
/**
135
 * Use for executing CreateToolhelp32Snapshot off main thread
136
 */
137
class mozilla::plugins::FinishInjectorInitTask : public mozilla::CancelableRunnable
138
{
139
public:
140
    FinishInjectorInitTask()
141
        : CancelableRunnable("FinishInjectorInitTask")
142
        , mMutex("FlashInjectorInitTask::mMutex")
143
        , mParent(nullptr)
144
        , mMainThreadMsgLoop(MessageLoop::current())
145
    {
146
        MOZ_ASSERT(NS_IsMainThread());
147
    }
148
149
    void Init(PluginModuleChromeParent* aParent)
150
    {
151
        MOZ_ASSERT(aParent);
152
        mParent = aParent;
153
    }
154
155
    void PostToMainThread()
156
    {
157
        RefPtr<Runnable> self = this;
158
        mSnapshot.own(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
159
        {   // Scope for lock
160
            mozilla::MutexAutoLock lock(mMutex);
161
            if (mMainThreadMsgLoop) {
162
                mMainThreadMsgLoop->PostTask(self.forget());
163
            }
164
        }
165
    }
166
167
    NS_IMETHOD Run() override
168
    {
169
        mParent->DoInjection(mSnapshot);
170
        // We don't need to hold this lock during DoInjection, but we do need
171
        // to obtain it before returning from Run() to ensure that
172
        // PostToMainThread has completed before we return.
173
        mozilla::MutexAutoLock lock(mMutex);
174
        return NS_OK;
175
    }
176
177
    nsresult Cancel() override
178
    {
179
        mozilla::MutexAutoLock lock(mMutex);
180
        mMainThreadMsgLoop = nullptr;
181
        return NS_OK;
182
    }
183
184
private:
185
    mozilla::Mutex            mMutex;
186
    nsAutoHandle              mSnapshot;
187
    PluginModuleChromeParent* mParent;
188
    MessageLoop*              mMainThreadMsgLoop;
189
};
190
191
#endif // MOZ_CRASHREPORTER_INJECTOR
192
193
namespace {
194
195
/**
196
 * Objects of this class remain linked until an error occurs in the
197
 * plugin initialization sequence.
198
 */
199
class PluginModuleMapping : public PRCList
200
{
201
public:
202
  explicit PluginModuleMapping(uint32_t aPluginId)
203
    : mPluginId(aPluginId)
204
    , mProcessIdValid(false)
205
    , mProcessId(0)
206
    , mModule(nullptr)
207
    , mChannelOpened(false)
208
0
  {
209
0
    MOZ_COUNT_CTOR(PluginModuleMapping);
210
0
    PR_INIT_CLIST(this);
211
0
    PR_APPEND_LINK(this, &sModuleListHead);
212
0
  }
213
214
    ~PluginModuleMapping()
215
0
    {
216
0
        PR_REMOVE_LINK(this);
217
0
        MOZ_COUNT_DTOR(PluginModuleMapping);
218
0
    }
219
220
    bool
221
    IsChannelOpened() const
222
0
    {
223
0
        return mChannelOpened;
224
0
    }
225
226
    void
227
    SetChannelOpened()
228
0
    {
229
0
        mChannelOpened = true;
230
0
    }
231
232
    PluginModuleContentParent*
233
    GetModule()
234
0
    {
235
0
        if (!mModule) {
236
0
            mModule = new PluginModuleContentParent();
237
0
        }
238
0
        return mModule;
239
0
    }
240
241
    static PluginModuleMapping*
242
    AssociateWithProcessId(uint32_t aPluginId, base::ProcessId aProcessId)
243
0
    {
244
0
        PluginModuleMapping* mapping =
245
0
            static_cast<PluginModuleMapping*>(PR_NEXT_LINK(&sModuleListHead));
246
0
        while (mapping != &sModuleListHead) {
247
0
            if (mapping->mPluginId == aPluginId) {
248
0
                mapping->AssociateWithProcessId(aProcessId);
249
0
                return mapping;
250
0
            }
251
0
            mapping = static_cast<PluginModuleMapping*>(PR_NEXT_LINK(mapping));
252
0
        }
253
0
        return nullptr;
254
0
    }
255
256
    static PluginModuleMapping*
257
    Resolve(base::ProcessId aProcessId)
258
0
    {
259
0
        PluginModuleMapping* mapping = nullptr;
260
0
261
0
        if (sIsLoadModuleOnStack) {
262
0
            // Special case: If loading synchronously, we just need to access
263
0
            // the tail entry of the list.
264
0
            mapping =
265
0
                static_cast<PluginModuleMapping*>(PR_LIST_TAIL(&sModuleListHead));
266
0
            MOZ_ASSERT(mapping);
267
0
            return mapping;
268
0
        }
269
0
270
0
        mapping =
271
0
            static_cast<PluginModuleMapping*>(PR_NEXT_LINK(&sModuleListHead));
272
0
        while (mapping != &sModuleListHead) {
273
0
            if (mapping->mProcessIdValid && mapping->mProcessId == aProcessId) {
274
0
                return mapping;
275
0
            }
276
0
            mapping = static_cast<PluginModuleMapping*>(PR_NEXT_LINK(mapping));
277
0
        }
278
0
        return nullptr;
279
0
    }
280
281
    static PluginModuleMapping*
282
    FindModuleByPluginId(uint32_t aPluginId)
283
0
    {
284
0
        PluginModuleMapping* mapping =
285
0
            static_cast<PluginModuleMapping*>(PR_NEXT_LINK(&sModuleListHead));
286
0
        while (mapping != &sModuleListHead) {
287
0
            if (mapping->mPluginId == aPluginId) {
288
0
                return mapping;
289
0
            }
290
0
            mapping = static_cast<PluginModuleMapping*>(PR_NEXT_LINK(mapping));
291
0
        }
292
0
        return nullptr;
293
0
    }
294
295
    class MOZ_RAII NotifyLoadingModule
296
    {
297
    public:
298
        explicit NotifyLoadingModule(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
299
0
        {
300
0
            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
301
0
            PluginModuleMapping::sIsLoadModuleOnStack = true;
302
0
        }
303
304
        ~NotifyLoadingModule()
305
0
        {
306
0
            PluginModuleMapping::sIsLoadModuleOnStack = false;
307
0
        }
308
309
    private:
310
        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
311
    };
312
313
private:
314
    void
315
    AssociateWithProcessId(base::ProcessId aProcessId)
316
0
    {
317
0
        MOZ_ASSERT(!mProcessIdValid);
318
0
        mProcessId = aProcessId;
319
0
        mProcessIdValid = true;
320
0
    }
321
322
    uint32_t mPluginId;
323
    bool mProcessIdValid;
324
    base::ProcessId mProcessId;
325
    PluginModuleContentParent* mModule;
326
    bool mChannelOpened;
327
328
    friend class NotifyLoadingModule;
329
330
    static PRCList sModuleListHead;
331
    static bool sIsLoadModuleOnStack;
332
};
333
334
PRCList PluginModuleMapping::sModuleListHead =
335
    PR_INIT_STATIC_CLIST(&PluginModuleMapping::sModuleListHead);
336
337
bool PluginModuleMapping::sIsLoadModuleOnStack = false;
338
339
} // namespace
340
341
static PluginModuleChromeParent*
342
PluginModuleChromeParentForId(const uint32_t aPluginId)
343
0
{
344
0
  MOZ_ASSERT(XRE_IsParentProcess());
345
0
346
0
  RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
347
0
  nsPluginTag* pluginTag = host->PluginWithId(aPluginId);
348
0
  if (!pluginTag || !pluginTag->mPlugin) {
349
0
    return nullptr;
350
0
  }
351
0
  RefPtr<nsNPAPIPlugin> plugin = pluginTag->mPlugin;
352
0
353
0
  return static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
354
0
}
355
356
void
357
mozilla::plugins::TakeFullMinidump(uint32_t aPluginId,
358
                                   base::ProcessId aContentProcessId,
359
                                   const nsAString& aBrowserDumpId,
360
                                   nsString& aDumpId)
361
0
{
362
0
  PluginModuleChromeParent* chromeParent =
363
0
    PluginModuleChromeParentForId(aPluginId);
364
0
365
0
  if (chromeParent) {
366
0
    chromeParent->TakeFullMinidump(aContentProcessId, aBrowserDumpId, aDumpId);
367
0
  }
368
0
}
369
370
void
371
mozilla::plugins::TerminatePlugin(uint32_t aPluginId,
372
                                  base::ProcessId aContentProcessId,
373
                                  const nsCString& aMonitorDescription,
374
                                  const nsAString& aDumpId)
375
0
{
376
0
  PluginModuleChromeParent* chromeParent =
377
0
    PluginModuleChromeParentForId(aPluginId);
378
0
379
0
  if (chromeParent) {
380
0
    chromeParent->TerminateChildProcess(MessageLoop::current(),
381
0
                                        aContentProcessId,
382
0
                                        aMonitorDescription,
383
0
                                        aDumpId);
384
0
  }
385
0
}
386
387
/* static */ PluginLibrary*
388
PluginModuleContentParent::LoadModule(uint32_t aPluginId,
389
                                      nsPluginTag* aPluginTag)
390
0
{
391
0
    PluginModuleMapping::NotifyLoadingModule loadingModule;
392
0
    nsAutoPtr<PluginModuleMapping> mapping(new PluginModuleMapping(aPluginId));
393
0
394
0
    MOZ_ASSERT(XRE_IsContentProcess());
395
0
396
0
    /*
397
0
     * We send a LoadPlugin message to the chrome process using an intr
398
0
     * message. Before it sends its response, it sends a message to create
399
0
     * PluginModuleParent instance. That message is handled by
400
0
     * PluginModuleContentParent::Initialize, which saves the instance in
401
0
     * its module mapping. We fetch it from there after LoadPlugin finishes.
402
0
     */
403
0
    dom::ContentChild* cp = dom::ContentChild::GetSingleton();
404
0
    nsresult rv;
405
0
    uint32_t runID;
406
0
    Endpoint<PPluginModuleParent> endpoint;
407
0
    if (!cp->SendLoadPlugin(aPluginId, &rv, &runID, &endpoint) ||
408
0
        NS_FAILED(rv)) {
409
0
        return nullptr;
410
0
    }
411
0
    Initialize(std::move(endpoint));
412
0
413
0
    PluginModuleContentParent* parent = mapping->GetModule();
414
0
    MOZ_ASSERT(parent);
415
0
416
0
    if (!mapping->IsChannelOpened()) {
417
0
        // mapping is linked into PluginModuleMapping::sModuleListHead and is
418
0
        // needed later, so since this function is returning successfully we
419
0
        // forget it here.
420
0
        mapping.forget();
421
0
    }
422
0
423
0
    parent->mPluginId = aPluginId;
424
0
    parent->mRunID = runID;
425
0
426
0
    return parent;
427
0
}
428
429
/* static */ void
430
PluginModuleContentParent::Initialize(Endpoint<PPluginModuleParent>&& aEndpoint)
431
0
{
432
0
    nsAutoPtr<PluginModuleMapping> moduleMapping(
433
0
        PluginModuleMapping::Resolve(aEndpoint.OtherPid()));
434
0
    MOZ_ASSERT(moduleMapping);
435
0
    PluginModuleContentParent* parent = moduleMapping->GetModule();
436
0
    MOZ_ASSERT(parent);
437
0
438
0
    DebugOnly<bool> ok = aEndpoint.Bind(parent);
439
0
    MOZ_ASSERT(ok);
440
0
441
0
    moduleMapping->SetChannelOpened();
442
0
443
0
    // Request Windows message deferral behavior on our channel. This
444
0
    // applies to the top level and all sub plugin protocols since they
445
0
    // all share the same channel.
446
0
    parent->GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
447
0
448
0
    TimeoutChanged(kContentTimeoutPref, parent);
449
0
450
0
    // moduleMapping is linked into PluginModuleMapping::sModuleListHead and is
451
0
    // needed later, so since this function is returning successfully we
452
0
    // forget it here.
453
0
    moduleMapping.forget();
454
0
}
455
456
// static
457
PluginLibrary*
458
PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId,
459
                                     nsPluginTag* aPluginTag)
460
0
{
461
0
    PLUGIN_LOG_DEBUG_FUNCTION;
462
0
463
0
    nsAutoPtr<PluginModuleChromeParent> parent(
464
0
            new PluginModuleChromeParent(aFilePath, aPluginId,
465
0
                                         aPluginTag->mSandboxLevel));
466
0
    UniquePtr<LaunchCompleteTask> onLaunchedRunnable(new LaunchedTask(parent));
467
0
    bool launched = parent->mSubprocess->Launch(std::move(onLaunchedRunnable),
468
0
                                                aPluginTag->mSandboxLevel,
469
0
                                                aPluginTag->mIsSandboxLoggingEnabled);
470
0
    if (!launched) {
471
0
        // We never reached open
472
0
        parent->mShutdown = true;
473
0
        return nullptr;
474
0
    }
475
0
    parent->mIsFlashPlugin = aPluginTag->mIsFlashPlugin;
476
0
    uint32_t blocklistState;
477
0
    nsresult rv = aPluginTag->GetBlocklistState(&blocklistState);
478
0
    parent->mIsBlocklisted = NS_FAILED(rv) || blocklistState != 0;
479
0
    int32_t launchTimeoutSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
480
0
    if (!parent->mSubprocess->WaitUntilConnected(launchTimeoutSecs * 1000)) {
481
0
        parent->mShutdown = true;
482
0
        return nullptr;
483
0
    }
484
0
485
#if defined(XP_WIN)
486
    Endpoint<PFunctionBrokerParent> brokerParentEnd;
487
    Endpoint<PFunctionBrokerChild> brokerChildEnd;
488
    rv = PFunctionBroker::CreateEndpoints(base::GetCurrentProcId(), parent->OtherPid(),
489
                                        &brokerParentEnd, &brokerChildEnd);
490
    if (NS_FAILED(rv)) {
491
        parent->mShutdown = true;
492
        return nullptr;
493
    }
494
495
    parent->mBrokerParent =
496
      FunctionBrokerParent::Create(std::move(brokerParentEnd));
497
    if (parent->mBrokerParent) {
498
      parent->SendInitPluginFunctionBroker(std::move(brokerChildEnd));
499
    }
500
#endif
501
0
    return parent.forget();
502
0
}
503
504
static const char* gCallbackPrefs[] = {
505
    kChildTimeoutPref,
506
    kParentTimeoutPref,
507
#ifdef XP_WIN
508
    kHangUITimeoutPref,
509
    kHangUIMinDisplayPref,
510
#endif
511
    nullptr,
512
};
513
514
void
515
PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
516
0
{
517
0
    if (!aSucceeded) {
518
0
        mShutdown = true;
519
0
        OnInitFailure();
520
0
        return;
521
0
    }
522
0
    // We may have already been initialized by another call that was waiting
523
0
    // for process connect. If so, this function doesn't need to run.
524
0
    if (mShutdown) {
525
0
        return;
526
0
    }
527
0
528
0
    Open(mSubprocess->GetChannel(),
529
0
         base::GetProcId(mSubprocess->GetChildProcessHandle()));
530
0
531
0
    // Request Windows message deferral behavior on our channel. This
532
0
    // applies to the top level and all sub plugin protocols since they
533
0
    // all share the same channel.
534
0
    GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
535
0
536
0
    TimeoutChanged(CHILD_TIMEOUT_PREF, this);
537
0
538
0
    Preferences::RegisterCallbacks(TimeoutChanged, gCallbackPrefs,
539
0
                                   static_cast<PluginModuleParent*>(this));
540
0
541
0
    RegisterSettingsCallbacks();
542
0
543
0
    // If this fails, we're having IPC troubles, and we're doomed anyways.
544
0
    if (!InitCrashReporter()) {
545
0
        mShutdown = true;
546
0
        Close();
547
0
        OnInitFailure();
548
0
        return;
549
0
    }
550
0
551
#if defined(XP_WIN) && defined(_X86_)
552
    // Protected mode only applies to Windows and only to x86.
553
    if (!mIsBlocklisted && mIsFlashPlugin &&
554
        (Preferences::GetBool("dom.ipc.plugins.flash.disable-protected-mode", false) ||
555
         mSandboxLevel >= 2)) {
556
        Unused << SendDisableFlashProtectedMode();
557
    }
558
#endif
559
560
0
#ifdef MOZ_GECKO_PROFILER
561
0
    Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
562
0
#endif
563
0
}
564
565
bool
566
PluginModuleChromeParent::InitCrashReporter()
567
0
{
568
0
    ipc::Shmem shmem;
569
0
    if (!ipc::CrashReporterClient::AllocShmem(this, &shmem)) {
570
0
        return false;
571
0
    }
572
0
573
0
    NativeThreadId threadId;
574
0
    if (!CallInitCrashReporter(shmem, &threadId)) {
575
0
        return false;
576
0
    }
577
0
578
0
    {
579
0
      mozilla::MutexAutoLock lock(mCrashReporterMutex);
580
0
      mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
581
0
        GeckoProcessType_Plugin,
582
0
        shmem,
583
0
        threadId);
584
0
    }
585
0
586
0
    return true;
587
0
}
588
589
PluginModuleParent::PluginModuleParent(bool aIsChrome)
590
  : mQuirks(QUIRKS_NOT_INITIALIZED)
591
  , mIsChrome(aIsChrome)
592
  , mShutdown(false)
593
  , mHadLocalInstance(false)
594
  , mClearSiteDataSupported(false)
595
  , mGetSitesWithDataSupported(false)
596
  , mNPNIface(nullptr)
597
  , mNPPIface(nullptr)
598
  , mPlugin(nullptr)
599
  , mTaskFactory(this)
600
  , mSandboxLevel(0)
601
  , mIsFlashPlugin(false)
602
  , mRunID(0)
603
  , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
604
0
{
605
0
}
606
607
PluginModuleParent::~PluginModuleParent()
608
0
{
609
0
    if (!OkToCleanup()) {
610
0
        MOZ_CRASH("unsafe destruction");
611
0
    }
612
0
613
0
    if (!mShutdown) {
614
0
        NS_WARNING("Plugin host deleted the module without shutting down.");
615
0
        NPError err;
616
0
        NP_Shutdown(&err);
617
0
    }
618
0
}
619
620
PluginModuleContentParent::PluginModuleContentParent()
621
  : PluginModuleParent(false)
622
  , mPluginId(0)
623
0
{
624
0
  Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref,
625
0
                                static_cast<PluginModuleParent*>(this));
626
0
}
627
628
PluginModuleContentParent::~PluginModuleContentParent()
629
0
{
630
0
    Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref,
631
0
                                    static_cast<PluginModuleParent*>(this));
632
0
}
633
634
PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
635
                                                   uint32_t aPluginId,
636
                                                   int32_t aSandboxLevel)
637
  : PluginModuleParent(true)
638
  , mSubprocess(new PluginProcessParent(aFilePath))
639
  , mPluginId(aPluginId)
640
  , mChromeTaskFactory(this)
641
  , mHangAnnotationFlags(0)
642
#ifdef XP_WIN
643
  , mPluginCpuUsageOnHang()
644
  , mHangUIParent(nullptr)
645
  , mHangUIEnabled(true)
646
  , mIsTimerReset(true)
647
  , mBrokerParent(nullptr)
648
#endif
649
#ifdef MOZ_CRASHREPORTER_INJECTOR
650
  , mFlashProcess1(0)
651
  , mFlashProcess2(0)
652
  , mFinishInitTask(nullptr)
653
#endif
654
  , mIsBlocklisted(false)
655
  , mIsCleaningFromTimeout(false)
656
0
{
657
0
    NS_ASSERTION(mSubprocess, "Out of memory!");
658
0
    mSandboxLevel = aSandboxLevel;
659
0
    mRunID = GeckoChildProcessHost::GetUniqueID();
660
0
661
0
    mozilla::BackgroundHangMonitor::RegisterAnnotator(*this);
662
0
}
663
664
PluginModuleChromeParent::~PluginModuleChromeParent()
665
0
{
666
0
    if (!OkToCleanup()) {
667
0
        MOZ_CRASH("unsafe destruction");
668
0
    }
669
0
670
#ifdef XP_WIN
671
    // If we registered for audio notifications, stop.
672
    mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
673
                                                                    false);
674
#endif
675
676
0
    if (!mShutdown) {
677
0
        NS_WARNING("Plugin host deleted the module without shutting down.");
678
0
        NPError err;
679
0
        NP_Shutdown(&err);
680
0
    }
681
0
682
0
    NS_ASSERTION(mShutdown, "NP_Shutdown didn't");
683
0
684
0
    if (mSubprocess) {
685
0
        mSubprocess->Delete();
686
0
        mSubprocess = nullptr;
687
0
    }
688
0
689
#ifdef MOZ_CRASHREPORTER_INJECTOR
690
    if (mFlashProcess1)
691
        UnregisterInjectorCallback(mFlashProcess1);
692
    if (mFlashProcess2)
693
        UnregisterInjectorCallback(mFlashProcess2);
694
    if (mFinishInitTask) {
695
        // mFinishInitTask will be deleted by the main thread message_loop
696
        mFinishInitTask->Cancel();
697
    }
698
#endif
699
700
0
    UnregisterSettingsCallbacks();
701
0
702
0
    Preferences::UnregisterCallbacks(TimeoutChanged, gCallbackPrefs,
703
0
                                     static_cast<PluginModuleParent*>(this));
704
0
705
#ifdef XP_WIN
706
    if (mHangUIParent) {
707
        delete mHangUIParent;
708
        mHangUIParent = nullptr;
709
    }
710
#endif
711
712
0
    mozilla::BackgroundHangMonitor::UnregisterAnnotator(*this);
713
0
}
714
715
void
716
PluginModuleChromeParent::WriteExtraDataForMinidump()
717
0
{
718
0
    // mCrashReporterMutex is already held by the caller
719
0
    mCrashReporterMutex.AssertCurrentThreadOwns();
720
0
721
0
    typedef nsDependentCString cstring;
722
0
723
0
    // Get the plugin filename, try to get just the file leafname
724
0
    const std::string& pluginFile = mSubprocess->GetPluginFilePath();
725
0
    size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
726
0
    if (filePos == std::string::npos)
727
0
        filePos = 0;
728
0
    else
729
0
        filePos++;
730
0
    mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginFilename,
731
0
                                  cstring(pluginFile.substr(filePos).c_str()));
732
0
    mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginName,
733
0
                                  mPluginName);
734
0
    mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginVersion,
735
0
                                  mPluginVersion);
736
0
737
0
    if (mCrashReporter) {
738
#ifdef XP_WIN
739
        if (mPluginCpuUsageOnHang.Length() > 0) {
740
            mCrashReporter->AddAnnotation(
741
              CrashReporter::Annotation::NumberOfProcessors,
742
              PR_GetNumberOfProcessors());
743
744
            nsCString cpuUsageStr;
745
            cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
746
            mCrashReporter->AddAnnotation(
747
              CrashReporter::Annotation::PluginCpuUsage,
748
              cpuUsageStr);
749
750
#ifdef MOZ_CRASHREPORTER_INJECTOR
751
            for (uint32_t i = 1; i < mPluginCpuUsageOnHang.Length(); ++i) {
752
                nsCString tempStr;
753
                tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100);
754
                // HACK: There can only be at most two flash processes hence
755
                // the hardcoded annotations
756
                CrashReporter::Annotation annotation =
757
                  (i == 1) ? CrashReporter::Annotation::CpuUsageFlashProcess1
758
                           : CrashReporter::Annotation::CpuUsageFlashProcess2;
759
                mCrashReporter->AddAnnotation(annotation, tempStr);
760
            }
761
#endif
762
        }
763
#endif
764
    }
765
0
}
766
767
void
768
PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
769
0
{
770
0
    int32_t timeoutMs = (aChildTimeout > 0) ? (1000 * aChildTimeout) :
771
0
                      MessageChannel::kNoTimeout;
772
0
    SetReplyTimeoutMs(timeoutMs);
773
0
}
774
775
void
776
PluginModuleParent::TimeoutChanged(const char* aPref, PluginModuleParent* aModule)
777
0
{
778
0
    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
779
0
#ifndef XP_WIN
780
0
    if (!strcmp(aPref, kChildTimeoutPref)) {
781
0
      MOZ_ASSERT(aModule->IsChrome());
782
0
      // The timeout value used by the parent for children
783
0
      int32_t timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
784
0
      aModule->SetChildTimeout(timeoutSecs);
785
#else
786
    if (!strcmp(aPref, kChildTimeoutPref) ||
787
        !strcmp(aPref, kHangUIMinDisplayPref) ||
788
        !strcmp(aPref, kHangUITimeoutPref)) {
789
      MOZ_ASSERT(aModule->IsChrome());
790
      static_cast<PluginModuleChromeParent*>(aModule)->EvaluateHangUIState(true);
791
#endif // XP_WIN
792
0
    } else if (!strcmp(aPref, kParentTimeoutPref)) {
793
0
      // The timeout value used by the child for its parent
794
0
      MOZ_ASSERT(aModule->IsChrome());
795
0
      int32_t timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0);
796
0
      Unused << static_cast<PluginModuleChromeParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs);
797
0
    } else if (!strcmp(aPref, kContentTimeoutPref)) {
798
0
      MOZ_ASSERT(!aModule->IsChrome());
799
0
      int32_t timeoutSecs = Preferences::GetInt(kContentTimeoutPref, 0);
800
0
      aModule->SetChildTimeout(timeoutSecs);
801
0
    }
802
0
}
803
804
void
805
PluginModuleChromeParent::CleanupFromTimeout(const bool aFromHangUI)
806
0
{
807
0
    if (mShutdown) {
808
0
      return;
809
0
    }
810
0
811
0
    if (!OkToCleanup()) {
812
0
        // there's still plugin code on the C++ stack, try again
813
0
        MessageLoop::current()->PostDelayedTask(
814
0
            mChromeTaskFactory.NewRunnableMethod(
815
0
                &PluginModuleChromeParent::CleanupFromTimeout, aFromHangUI), 10);
816
0
        return;
817
0
    }
818
0
819
0
    // Avoid recursively calling this method.  MessageChannel::Close() can
820
0
    // cause this task to be re-launched.
821
0
    if (mIsCleaningFromTimeout) {
822
0
      return;
823
0
    }
824
0
825
0
    AutoRestore<bool> resetCleaningFlag(mIsCleaningFromTimeout);
826
0
    mIsCleaningFromTimeout = true;
827
0
828
0
    /* If the plugin container was terminated by the Plugin Hang UI,
829
0
       then either the I/O thread detects a channel error, or the
830
0
       main thread must set the error (whomever gets there first).
831
0
       OTOH, if we terminate and return false from
832
0
       ShouldContinueFromReplyTimeout, then the channel state has
833
0
       already been set to ChannelTimeout and we should call the
834
0
       regular Close function. */
835
0
    if (aFromHangUI) {
836
0
        GetIPCChannel()->CloseWithError();
837
0
    } else {
838
0
        Close();
839
0
    }
840
0
}
841
842
#ifdef XP_WIN
843
namespace {
844
845
uint64_t
846
FileTimeToUTC(const FILETIME& ftime)
847
{
848
  ULARGE_INTEGER li;
849
  li.LowPart = ftime.dwLowDateTime;
850
  li.HighPart = ftime.dwHighDateTime;
851
  return li.QuadPart;
852
}
853
854
struct CpuUsageSamples
855
{
856
  uint64_t sampleTimes[2];
857
  uint64_t cpuTimes[2];
858
};
859
860
bool
861
GetProcessCpuUsage(const InfallibleTArray<base::ProcessHandle>& processHandles, InfallibleTArray<float>& cpuUsage)
862
{
863
  InfallibleTArray<CpuUsageSamples> samples(processHandles.Length());
864
  FILETIME creationTime, exitTime, kernelTime, userTime, currentTime;
865
  BOOL res;
866
867
  for (uint32_t i = 0; i < processHandles.Length(); ++i) {
868
    ::GetSystemTimeAsFileTime(&currentTime);
869
    res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
870
    if (!res) {
871
      NS_WARNING("failed to get process times");
872
      return false;
873
    }
874
875
    CpuUsageSamples s;
876
    s.sampleTimes[0] = FileTimeToUTC(currentTime);
877
    s.cpuTimes[0]    = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
878
    samples.AppendElement(s);
879
  }
880
881
  // we already hung for a while, a little bit longer won't matter
882
  ::Sleep(50);
883
884
  const int32_t numberOfProcessors = PR_GetNumberOfProcessors();
885
886
  for (uint32_t i = 0; i < processHandles.Length(); ++i) {
887
    ::GetSystemTimeAsFileTime(&currentTime);
888
    res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
889
    if (!res) {
890
      NS_WARNING("failed to get process times");
891
      return false;
892
    }
893
894
    samples[i].sampleTimes[1] = FileTimeToUTC(currentTime);
895
    samples[i].cpuTimes[1]    = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
896
897
    const uint64_t deltaSampleTime = samples[i].sampleTimes[1] - samples[i].sampleTimes[0];
898
    const uint64_t deltaCpuTime    = samples[i].cpuTimes[1]    - samples[i].cpuTimes[0];
899
    const float usage = 100.f * (float(deltaCpuTime) / deltaSampleTime) / numberOfProcessors;
900
    cpuUsage.AppendElement(usage);
901
  }
902
903
  return true;
904
}
905
906
} // namespace
907
908
#endif // #ifdef XP_WIN
909
910
/**
911
 * This function converts the topmost routing id on the call stack (as recorded
912
 * by the MessageChannel) into a pointer to a IProtocol object.
913
 */
914
mozilla::ipc::IProtocol*
915
PluginModuleChromeParent::GetInvokingProtocol()
916
0
{
917
0
    int32_t routingId = GetIPCChannel()->GetTopmostMessageRoutingId();
918
0
    // Nothing being routed. No protocol. Just return nullptr.
919
0
    if (routingId == MSG_ROUTING_NONE) {
920
0
        return nullptr;
921
0
    }
922
0
    // If routingId is MSG_ROUTING_CONTROL then we're dealing with control
923
0
    // messages that were initiated by the topmost managing protocol, ie. this.
924
0
    if (routingId == MSG_ROUTING_CONTROL) {
925
0
        return this;
926
0
    }
927
0
    // Otherwise we can look up the protocol object by the routing id.
928
0
    mozilla::ipc::IProtocol* protocol = Lookup(routingId);
929
0
    return protocol;
930
0
}
931
932
/**
933
 * This function examines the IProtocol object parameter and converts it into
934
 * the PluginInstanceParent object that is associated with that protocol, if
935
 * any. Since PluginInstanceParent manages subprotocols, this function needs
936
 * to determine whether |aProtocol| is a subprotocol, and if so it needs to
937
 * obtain the protocol's manager.
938
 *
939
 * This function needs to be updated if the subprotocols are modified in
940
 * PPluginInstance.ipdl.
941
 */
942
PluginInstanceParent*
943
PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol)
944
0
{
945
0
    MOZ_ASSERT(aProtocol);
946
0
    mozilla::ipc::IProtocol* listener = aProtocol;
947
0
    switch (listener->GetProtocolTypeId()) {
948
0
        case PPluginInstanceMsgStart:
949
0
            // In this case, aProtocol is the instance itself. Just cast it.
950
0
            return static_cast<PluginInstanceParent*>(aProtocol);
951
0
        case PPluginBackgroundDestroyerMsgStart: {
952
0
            PPluginBackgroundDestroyerParent* actor =
953
0
                static_cast<PPluginBackgroundDestroyerParent*>(aProtocol);
954
0
            return static_cast<PluginInstanceParent*>(actor->Manager());
955
0
        }
956
0
        case PPluginScriptableObjectMsgStart: {
957
0
            PPluginScriptableObjectParent* actor =
958
0
                static_cast<PPluginScriptableObjectParent*>(aProtocol);
959
0
            return static_cast<PluginInstanceParent*>(actor->Manager());
960
0
        }
961
0
        case PBrowserStreamMsgStart: {
962
0
            PBrowserStreamParent* actor =
963
0
                static_cast<PBrowserStreamParent*>(aProtocol);
964
0
            return static_cast<PluginInstanceParent*>(actor->Manager());
965
0
        }
966
0
        case PStreamNotifyMsgStart: {
967
0
            PStreamNotifyParent* actor =
968
0
                static_cast<PStreamNotifyParent*>(aProtocol);
969
0
            return static_cast<PluginInstanceParent*>(actor->Manager());
970
0
        }
971
#ifdef XP_WIN
972
        case PPluginSurfaceMsgStart: {
973
            PPluginSurfaceParent* actor =
974
                static_cast<PPluginSurfaceParent*>(aProtocol);
975
            return static_cast<PluginInstanceParent*>(actor->Manager());
976
        }
977
#endif
978
0
        default:
979
0
            return nullptr;
980
0
    }
981
0
}
982
983
void
984
PluginModuleChromeParent::EnteredCxxStack()
985
0
{
986
0
    mHangAnnotationFlags |= kInPluginCall;
987
0
}
988
989
void
990
PluginModuleChromeParent::ExitedCxxStack()
991
0
{
992
0
    mHangAnnotationFlags = 0;
993
#ifdef XP_WIN
994
    FinishHangUI();
995
#endif
996
}
997
998
/**
999
 * This function is always called by the BackgroundHangMonitor thread.
1000
 */
1001
void
1002
PluginModuleChromeParent::AnnotateHang(mozilla::BackgroundHangAnnotations& aAnnotations)
1003
0
{
1004
0
    uint32_t flags = mHangAnnotationFlags;
1005
0
    if (flags) {
1006
0
        /* We don't actually annotate anything specifically for kInPluginCall;
1007
0
           we use it to determine whether to annotate other things. It will
1008
0
           be pretty obvious from the hang stack that we're in a plugin
1009
0
           call when the hang occurred. */
1010
0
        if (flags & kHangUIShown) {
1011
0
            aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIShown"),
1012
0
                                       true);
1013
0
        }
1014
0
        if (flags & kHangUIContinued) {
1015
0
            aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIContinued"),
1016
0
                                       true);
1017
0
        }
1018
0
        if (flags & kHangUIDontShow) {
1019
0
            aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIDontShow"),
1020
0
                                       true);
1021
0
        }
1022
0
        aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName);
1023
0
        aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"),
1024
0
                                   mPluginVersion);
1025
0
    }
1026
0
}
1027
1028
static bool
1029
CreatePluginMinidump(base::ProcessId processId, ThreadId childThread,
1030
                     nsIFile* parentMinidump, const nsACString& name)
1031
0
{
1032
0
  mozilla::ipc::ScopedProcessHandle handle;
1033
0
  if (processId == 0 ||
1034
0
      !base::OpenPrivilegedProcessHandle(processId, &handle.rwget())) {
1035
0
    return false;
1036
0
  }
1037
0
  return CreateAdditionalChildMinidump(handle, 0, parentMinidump, name);
1038
0
}
1039
1040
bool
1041
PluginModuleChromeParent::ShouldContinueFromReplyTimeout()
1042
0
{
1043
0
    if (mIsFlashPlugin) {
1044
0
        MessageLoop::current()->PostTask(
1045
0
            mTaskFactory.NewRunnableMethod(
1046
0
                &PluginModuleChromeParent::NotifyFlashHang));
1047
0
    }
1048
0
1049
#ifdef XP_WIN
1050
    if (LaunchHangUI()) {
1051
        return true;
1052
    }
1053
    // If LaunchHangUI returned false then we should proceed with the
1054
    // original plugin hang behaviour and kill the plugin container.
1055
    FinishHangUI();
1056
#endif // XP_WIN
1057
1058
0
    TerminateChildProcess(MessageLoop::current(),
1059
0
                          mozilla::ipc::kInvalidProcessId,
1060
0
                          NS_LITERAL_CSTRING("ModalHangUI"),
1061
0
                          EmptyString());
1062
0
    GetIPCChannel()->CloseWithTimeout();
1063
0
    return false;
1064
0
}
1065
1066
bool
1067
PluginModuleContentParent::ShouldContinueFromReplyTimeout()
1068
0
{
1069
0
    RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
1070
0
    if (!monitor) {
1071
0
        return true;
1072
0
    }
1073
0
    monitor->NotifyPluginHang(mPluginId);
1074
0
    return true;
1075
0
}
1076
1077
void
1078
PluginModuleContentParent::OnExitedSyncSend()
1079
0
{
1080
0
    ProcessHangMonitor::ClearHang();
1081
0
}
1082
1083
void
1084
PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
1085
                                           const nsAString& aBrowserDumpId,
1086
                                           nsString& aDumpId)
1087
0
{
1088
0
    mozilla::MutexAutoLock lock(mCrashReporterMutex);
1089
0
1090
0
    if (!mCrashReporter) {
1091
0
        return;
1092
0
    }
1093
0
1094
0
    bool reportsReady = false;
1095
0
1096
0
    // Check to see if we already have a browser dump id - with e10s plugin
1097
0
    // hangs we take this earlier (see ProcessHangMonitor) from a background
1098
0
    // thread. We do this before we message the main thread about the hang
1099
0
    // since the posted message will trash our browser stack state.
1100
0
    nsCOMPtr<nsIFile> browserDumpFile;
1101
0
    if (CrashReporter::GetMinidumpForID(aBrowserDumpId,
1102
0
                                        getter_AddRefs(browserDumpFile))) {
1103
0
        // We have a single browser report, generate a new plugin process parent
1104
0
        // report and pair it up with the browser report handed in.
1105
0
        reportsReady = mCrashReporter->GenerateMinidumpAndPair(
1106
0
          this,
1107
0
          browserDumpFile,
1108
0
          NS_LITERAL_CSTRING("browser"));
1109
0
1110
0
        if (!reportsReady) {
1111
0
          browserDumpFile = nullptr;
1112
0
          CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
1113
0
        }
1114
0
    }
1115
0
1116
0
    // Generate crash report including plugin and browser process minidumps.
1117
0
    // The plugin process is the parent report with additional dumps including
1118
0
    // the browser process, content process when running under e10s, and
1119
0
    // various flash subprocesses if we're the flash module.
1120
0
    if (!reportsReady) {
1121
0
        reportsReady = mCrashReporter->GenerateMinidumpAndPair(
1122
0
          this,
1123
0
          nullptr, // Pair with a dump of this process and thread.
1124
0
          NS_LITERAL_CSTRING("browser"));
1125
0
    }
1126
0
1127
0
    if (reportsReady) {
1128
0
        aDumpId = mCrashReporter->MinidumpID();
1129
0
        PLUGIN_LOG_DEBUG(
1130
0
                ("generated paired browser/plugin minidumps: %s)",
1131
0
                 NS_ConvertUTF16toUTF8(aDumpId).get()));
1132
0
        nsAutoCString additionalDumps("browser");
1133
0
        nsCOMPtr<nsIFile> pluginDumpFile;
1134
0
        if (GetMinidumpForID(aDumpId, getter_AddRefs(pluginDumpFile))) {
1135
#ifdef MOZ_CRASHREPORTER_INJECTOR
1136
            // If we have handles to the flash sandbox processes on Windows,
1137
            // include those minidumps as well.
1138
            if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile,
1139
                                     NS_LITERAL_CSTRING("flash1"))) {
1140
                additionalDumps.AppendLiteral(",flash1");
1141
            }
1142
            if (CreatePluginMinidump(mFlashProcess2, 0, pluginDumpFile,
1143
                                     NS_LITERAL_CSTRING("flash2"))) {
1144
                additionalDumps.AppendLiteral(",flash2");
1145
            }
1146
#endif // MOZ_CRASHREPORTER_INJECTOR
1147
0
            if (aContentPid != mozilla::ipc::kInvalidProcessId) {
1148
0
                // Include the content process minidump
1149
0
                if (CreatePluginMinidump(aContentPid, 0,
1150
0
                                         pluginDumpFile,
1151
0
                                         NS_LITERAL_CSTRING("content"))) {
1152
0
                    additionalDumps.AppendLiteral(",content");
1153
0
                }
1154
0
            }
1155
0
        }
1156
0
        mCrashReporter->AddAnnotation(Annotation::additional_minidumps,
1157
0
                                      additionalDumps);
1158
0
    } else {
1159
0
        NS_WARNING("failed to capture paired minidumps from hang");
1160
0
    }
1161
0
}
1162
1163
void
1164
PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
1165
                                                base::ProcessId aContentPid,
1166
                                                const nsCString& aMonitorDescription,
1167
                                                const nsAString& aDumpId)
1168
0
{
1169
0
    // Start by taking a full minidump if necessary, this is done early
1170
0
    // because it also needs to lock the mCrashReporterMutex and Mutex doesn't
1171
0
    // support recursive locking.
1172
0
    nsAutoString dumpId;
1173
0
    if (aDumpId.IsEmpty()) {
1174
0
        TakeFullMinidump(aContentPid, EmptyString(), dumpId);
1175
0
    }
1176
0
1177
0
    mozilla::MutexAutoLock lock(mCrashReporterMutex);
1178
0
    if (!mCrashReporter) {
1179
0
        // If mCrashReporter is null then the hang has ended, the plugin module
1180
0
        // is shutting down. There's nothing to do here.
1181
0
        return;
1182
0
    }
1183
0
    mCrashReporter->AddAnnotation(Annotation::PluginHang, true);
1184
0
    mCrashReporter->AddAnnotation(Annotation::HangMonitorDescription,
1185
0
                                  aMonitorDescription);
1186
#ifdef XP_WIN
1187
    if (mHangUIParent) {
1188
        unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
1189
        if (hangUIDuration) {
1190
            mCrashReporter->AddAnnotation(Annotation::PluginHangUIDuration,
1191
                                          hangUIDuration);
1192
        }
1193
    }
1194
#endif // XP_WIN
1195
1196
0
    mozilla::ipc::ScopedProcessHandle geckoChildProcess;
1197
0
    bool childOpened = base::OpenProcessHandle(OtherPid(),
1198
0
                                               &geckoChildProcess.rwget());
1199
0
1200
#ifdef XP_WIN
1201
    // collect cpu usage for plugin processes
1202
1203
    InfallibleTArray<base::ProcessHandle> processHandles;
1204
1205
    if (childOpened) {
1206
        processHandles.AppendElement(geckoChildProcess);
1207
    }
1208
1209
#ifdef MOZ_CRASHREPORTER_INJECTOR
1210
    mozilla::ipc::ScopedProcessHandle flashBrokerProcess;
1211
    if (mFlashProcess1 &&
1212
        base::OpenProcessHandle(mFlashProcess1, &flashBrokerProcess.rwget())) {
1213
        processHandles.AppendElement(flashBrokerProcess);
1214
    }
1215
    mozilla::ipc::ScopedProcessHandle flashSandboxProcess;
1216
    if (mFlashProcess2 &&
1217
        base::OpenProcessHandle(mFlashProcess2, &flashSandboxProcess.rwget())) {
1218
        processHandles.AppendElement(flashSandboxProcess);
1219
    }
1220
#endif
1221
1222
    if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
1223
      mPluginCpuUsageOnHang.Clear();
1224
    }
1225
#endif
1226
1227
0
    // this must run before the error notification from the channel,
1228
0
    // or not at all
1229
0
    bool isFromHangUI = aMsgLoop != MessageLoop::current();
1230
0
    aMsgLoop->PostTask(
1231
0
        mChromeTaskFactory.NewRunnableMethod(
1232
0
            &PluginModuleChromeParent::CleanupFromTimeout, isFromHangUI));
1233
0
1234
0
    if (!childOpened || !KillProcess(geckoChildProcess, 1, false)) {
1235
0
        NS_WARNING("failed to kill subprocess!");
1236
0
    }
1237
0
}
1238
1239
bool
1240
PluginModuleParent::GetPluginDetails()
1241
0
{
1242
0
    RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
1243
0
    if (!host) {
1244
0
        return false;
1245
0
    }
1246
0
    nsPluginTag* pluginTag = host->TagForPlugin(mPlugin);
1247
0
    if (!pluginTag) {
1248
0
        return false;
1249
0
    }
1250
0
    mPluginName = pluginTag->Name();
1251
0
    mPluginVersion = pluginTag->Version();
1252
0
    mPluginFilename = pluginTag->FileName();
1253
0
    mIsFlashPlugin = pluginTag->mIsFlashPlugin;
1254
0
    mSandboxLevel = pluginTag->mSandboxLevel;
1255
0
    return true;
1256
0
}
1257
1258
void
1259
PluginModuleParent::InitQuirksModes(const nsCString& aMimeType)
1260
0
{
1261
0
    if (mQuirks != QUIRKS_NOT_INITIALIZED) {
1262
0
      return;
1263
0
    }
1264
0
1265
0
    mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename);
1266
0
}
1267
1268
#ifdef XP_WIN
1269
void
1270
PluginModuleChromeParent::EvaluateHangUIState(const bool aReset)
1271
{
1272
    int32_t minDispSecs = Preferences::GetInt(kHangUIMinDisplayPref, 10);
1273
    int32_t autoStopSecs = Preferences::GetInt(kChildTimeoutPref, 0);
1274
    int32_t timeoutSecs = 0;
1275
    if (autoStopSecs > 0 && autoStopSecs < minDispSecs) {
1276
        /* If we're going to automatically terminate the plugin within a
1277
           time frame shorter than minDispSecs, there's no point in
1278
           showing the hang UI; it would just flash briefly on the screen. */
1279
        mHangUIEnabled = false;
1280
    } else {
1281
        timeoutSecs = Preferences::GetInt(kHangUITimeoutPref, 0);
1282
        mHangUIEnabled = timeoutSecs > 0;
1283
    }
1284
    if (mHangUIEnabled) {
1285
        if (aReset) {
1286
            mIsTimerReset = true;
1287
            SetChildTimeout(timeoutSecs);
1288
            return;
1289
        } else if (mIsTimerReset) {
1290
            /* The Hang UI is being shown, so now we're setting the
1291
               timeout to kChildTimeoutPref while we wait for a user
1292
               response. ShouldContinueFromReplyTimeout will fire
1293
               after (reply timeout / 2) seconds, which is not what
1294
               we want. Doubling the timeout value here so that we get
1295
               the right result. */
1296
            autoStopSecs *= 2;
1297
        }
1298
    }
1299
    mIsTimerReset = false;
1300
    SetChildTimeout(autoStopSecs);
1301
}
1302
1303
bool
1304
PluginModuleChromeParent::LaunchHangUI()
1305
{
1306
    if (!mHangUIEnabled) {
1307
        return false;
1308
    }
1309
    if (mHangUIParent) {
1310
        if (mHangUIParent->IsShowing()) {
1311
            // We've already shown the UI but the timeout has expired again.
1312
            return false;
1313
        }
1314
        if (mHangUIParent->DontShowAgain()) {
1315
            mHangAnnotationFlags |= kHangUIDontShow;
1316
            bool wasLastHangStopped = mHangUIParent->WasLastHangStopped();
1317
            if (!wasLastHangStopped) {
1318
                mHangAnnotationFlags |= kHangUIContinued;
1319
            }
1320
            return !wasLastHangStopped;
1321
        }
1322
        delete mHangUIParent;
1323
        mHangUIParent = nullptr;
1324
    }
1325
    mHangUIParent = new PluginHangUIParent(this,
1326
            Preferences::GetInt(kHangUITimeoutPref, 0),
1327
            Preferences::GetInt(kChildTimeoutPref, 0));
1328
    bool retval = mHangUIParent->Init(NS_ConvertUTF8toUTF16(mPluginName));
1329
    if (retval) {
1330
        mHangAnnotationFlags |= kHangUIShown;
1331
        /* Once the UI is shown we switch the timeout over to use
1332
           kChildTimeoutPref, allowing us to terminate a hung plugin
1333
           after kChildTimeoutPref seconds if the user doesn't respond to
1334
           the hang UI. */
1335
        EvaluateHangUIState(false);
1336
    }
1337
    return retval;
1338
}
1339
1340
void
1341
PluginModuleChromeParent::FinishHangUI()
1342
{
1343
    if (mHangUIEnabled && mHangUIParent) {
1344
        bool needsCancel = mHangUIParent->IsShowing();
1345
        // If we're still showing, send a Cancel notification
1346
        if (needsCancel) {
1347
            mHangUIParent->Cancel();
1348
        }
1349
        /* If we cancelled the UI or if the user issued a response,
1350
           we need to reset the child process timeout. */
1351
        if (needsCancel ||
1352
            (!mIsTimerReset && mHangUIParent->WasShown())) {
1353
            /* We changed the timeout to kChildTimeoutPref when the plugin hang
1354
               UI was displayed. Now that we're finishing the UI, we need to
1355
               switch it back to kHangUITimeoutPref. */
1356
            EvaluateHangUIState(true);
1357
        }
1358
    }
1359
}
1360
1361
void
1362
PluginModuleChromeParent::OnHangUIContinue()
1363
{
1364
    mHangAnnotationFlags |= kHangUIContinued;
1365
}
1366
#endif // XP_WIN
1367
1368
#ifdef MOZ_CRASHREPORTER_INJECTOR
1369
static void
1370
RemoveMinidump(nsIFile* minidump)
1371
{
1372
    if (!minidump)
1373
        return;
1374
1375
    minidump->Remove(false);
1376
    nsCOMPtr<nsIFile> extraFile;
1377
    if (GetExtraFileForMinidump(minidump,
1378
                                getter_AddRefs(extraFile))) {
1379
        extraFile->Remove(true);
1380
    }
1381
}
1382
#endif // MOZ_CRASHREPORTER_INJECTOR
1383
1384
void
1385
PluginModuleChromeParent::ProcessFirstMinidump()
1386
0
{
1387
0
    mozilla::MutexAutoLock lock(mCrashReporterMutex);
1388
0
1389
0
    if (!mCrashReporter)
1390
0
        return;
1391
0
1392
0
    WriteExtraDataForMinidump();
1393
0
1394
0
    if (mCrashReporter->HasMinidump()) {
1395
0
        // A minidump may be set in TerminateChildProcess, which means the
1396
0
        // process hang monitor has already collected a 3-way browser, plugin,
1397
0
        // content crash report. If so, update the existing report with our
1398
0
        // annotations and finalize it. If not, fall through for standard
1399
0
        // plugin crash report handling.
1400
0
        mCrashReporter->FinalizeCrashReport();
1401
0
        return;
1402
0
    }
1403
0
1404
0
    uint32_t sequence = UINT32_MAX;
1405
0
    nsAutoCString flashProcessType;
1406
0
    RefPtr<nsIFile> dumpFile = mCrashReporter->TakeCrashedChildMinidump(OtherPid(), &sequence);
1407
0
1408
#ifdef MOZ_CRASHREPORTER_INJECTOR
1409
    nsCOMPtr<nsIFile> childDumpFile;
1410
    uint32_t childSequence;
1411
1412
    if (mFlashProcess1 &&
1413
        TakeMinidumpForChild(mFlashProcess1,
1414
                             getter_AddRefs(childDumpFile),
1415
                             &childSequence)) {
1416
        if (childSequence < sequence &&
1417
            mCrashReporter->AdoptMinidump(childDumpFile))
1418
        {
1419
            RemoveMinidump(dumpFile);
1420
            dumpFile = childDumpFile;
1421
            sequence = childSequence;
1422
            flashProcessType.AssignLiteral("Broker");
1423
        }
1424
        else {
1425
            RemoveMinidump(childDumpFile);
1426
        }
1427
    }
1428
    if (mFlashProcess2 &&
1429
        TakeMinidumpForChild(mFlashProcess2,
1430
                             getter_AddRefs(childDumpFile),
1431
                             &childSequence)) {
1432
        if (childSequence < sequence &&
1433
            mCrashReporter->AdoptMinidump(childDumpFile))
1434
        {
1435
            RemoveMinidump(dumpFile);
1436
            dumpFile = childDumpFile;
1437
            sequence = childSequence;
1438
            flashProcessType.AssignLiteral("Sandbox");
1439
        }
1440
        else {
1441
            RemoveMinidump(childDumpFile);
1442
        }
1443
    }
1444
#endif
1445
1446
0
    if (!dumpFile) {
1447
0
        NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
1448
0
        return;
1449
0
    }
1450
0
1451
0
    PLUGIN_LOG_DEBUG(("got child minidump: %s",
1452
0
                      NS_ConvertUTF16toUTF8(mCrashReporter->MinidumpID()).get()));
1453
0
1454
0
    if (!flashProcessType.IsEmpty()) {
1455
0
        mCrashReporter->AddAnnotation(Annotation::FlashProcessDump,
1456
0
                                      flashProcessType);
1457
0
    }
1458
0
    mCrashReporter->FinalizeCrashReport();
1459
0
}
1460
1461
void
1462
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
1463
0
{
1464
0
    switch (why) {
1465
0
    case AbnormalShutdown: {
1466
0
        mShutdown = true;
1467
0
        // Defer the PluginCrashed method so that we don't re-enter
1468
0
        // and potentially modify the actor child list while enumerating it.
1469
0
        if (mPlugin)
1470
0
            MessageLoop::current()->PostTask(
1471
0
                mTaskFactory.NewRunnableMethod(
1472
0
                    &PluginModuleParent::NotifyPluginCrashed));
1473
0
        break;
1474
0
    }
1475
0
    case NormalShutdown:
1476
0
        mShutdown = true;
1477
0
        break;
1478
0
1479
0
    default:
1480
0
        MOZ_CRASH("Unexpected shutdown reason for toplevel actor.");
1481
0
    }
1482
0
}
1483
1484
nsresult
1485
PluginModuleParent::GetRunID(uint32_t* aRunID)
1486
0
{
1487
0
    if (NS_WARN_IF(!aRunID)) {
1488
0
      return NS_ERROR_INVALID_POINTER;
1489
0
    }
1490
0
    *aRunID = mRunID;
1491
0
    return NS_OK;
1492
0
}
1493
1494
void
1495
PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why)
1496
0
{
1497
0
    if (why == AbnormalShutdown) {
1498
0
        ProcessFirstMinidump();
1499
0
        Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
1500
0
                              NS_LITERAL_CSTRING("plugin"), 1);
1501
0
    }
1502
0
1503
0
    // We can't broadcast settings changes anymore.
1504
0
    UnregisterSettingsCallbacks();
1505
0
1506
#if defined(XP_WIN)
1507
    if (mBrokerParent) {
1508
        FunctionBrokerParent::Destroy(mBrokerParent);
1509
        mBrokerParent = nullptr;
1510
    }
1511
#endif
1512
1513
0
    PluginModuleParent::ActorDestroy(why);
1514
0
}
1515
1516
void
1517
PluginModuleParent::NotifyFlashHang()
1518
0
{
1519
0
    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1520
0
    if (obs) {
1521
0
        obs->NotifyObservers(nullptr, "flash-plugin-hang", nullptr);
1522
0
    }
1523
0
}
1524
1525
void
1526
PluginModuleParent::NotifyPluginCrashed()
1527
0
{
1528
0
    if (!OkToCleanup()) {
1529
0
        // there's still plugin code on the C++ stack.  try again
1530
0
        MessageLoop::current()->PostDelayedTask(
1531
0
            mTaskFactory.NewRunnableMethod(
1532
0
                &PluginModuleParent::NotifyPluginCrashed), 10);
1533
0
        return;
1534
0
    }
1535
0
1536
0
    if (!mPlugin) {
1537
0
        return;
1538
0
    }
1539
0
1540
0
    nsString dumpID;
1541
0
    nsString browserDumpID;
1542
0
1543
0
    if (mCrashReporter && mCrashReporter->HasMinidump()) {
1544
0
        dumpID = mCrashReporter->MinidumpID();
1545
0
    }
1546
0
1547
0
    mPlugin->PluginCrashed(dumpID, browserDumpID);
1548
0
}
1549
1550
PPluginInstanceParent*
1551
PluginModuleParent::AllocPPluginInstanceParent(const nsCString& aMimeType,
1552
                                               const InfallibleTArray<nsCString>& aNames,
1553
                                               const InfallibleTArray<nsCString>& aValues)
1554
0
{
1555
0
    NS_ERROR("Not reachable!");
1556
0
    return nullptr;
1557
0
}
1558
1559
bool
1560
PluginModuleParent::DeallocPPluginInstanceParent(PPluginInstanceParent* aActor)
1561
0
{
1562
0
    PLUGIN_LOG_DEBUG_METHOD;
1563
0
    delete aActor;
1564
0
    return true;
1565
0
}
1566
1567
void
1568
PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
1569
0
{
1570
0
    MOZ_ASSERT(aFuncs);
1571
0
1572
0
    aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
1573
0
    aFuncs->javaClass = nullptr;
1574
0
1575
0
    // Gecko should always call these functions through a PluginLibrary object.
1576
0
    aFuncs->newp = nullptr;
1577
0
    aFuncs->clearsitedata = nullptr;
1578
0
    aFuncs->getsiteswithdata = nullptr;
1579
0
1580
0
    aFuncs->destroy = NPP_Destroy;
1581
0
    aFuncs->setwindow = NPP_SetWindow;
1582
0
    aFuncs->newstream = NPP_NewStream;
1583
0
    aFuncs->destroystream = NPP_DestroyStream;
1584
0
    aFuncs->writeready = NPP_WriteReady;
1585
0
    aFuncs->write = NPP_Write;
1586
0
    aFuncs->print = NPP_Print;
1587
0
    aFuncs->event = NPP_HandleEvent;
1588
0
    aFuncs->urlnotify = NPP_URLNotify;
1589
0
    aFuncs->getvalue = NPP_GetValue;
1590
0
    aFuncs->setvalue = NPP_SetValue;
1591
0
    aFuncs->gotfocus = nullptr;
1592
0
    aFuncs->lostfocus = nullptr;
1593
0
    aFuncs->urlredirectnotify = nullptr;
1594
0
1595
0
    // Provide 'NPP_URLRedirectNotify', 'NPP_ClearSiteData', and
1596
0
    // 'NPP_GetSitesWithData' functionality if it is supported by the plugin.
1597
0
    bool urlRedirectSupported = false;
1598
0
    Unused << CallOptionalFunctionsSupported(&urlRedirectSupported,
1599
0
                                             &mClearSiteDataSupported,
1600
0
                                             &mGetSitesWithDataSupported);
1601
0
    if (urlRedirectSupported) {
1602
0
      aFuncs->urlredirectnotify = NPP_URLRedirectNotify;
1603
0
    }
1604
0
}
1605
1606
NPError
1607
PluginModuleParent::NPP_Destroy(NPP instance,
1608
                                NPSavedData** saved)
1609
0
{
1610
0
    // FIXME/cjones:
1611
0
    //  (1) send a "destroy" message to the child
1612
0
    //  (2) the child shuts down its instance
1613
0
    //  (3) remove both parent and child IDs from map
1614
0
    //  (4) free parent
1615
0
1616
0
    PLUGIN_LOG_DEBUG_FUNCTION;
1617
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1618
0
    if (!pip)
1619
0
        return NPERR_NO_ERROR;
1620
0
1621
0
    NPError retval = pip->Destroy();
1622
0
    instance->pdata = nullptr;
1623
0
1624
0
    Unused << PluginInstanceParent::Call__delete__(pip);
1625
0
    return retval;
1626
0
}
1627
1628
NPError
1629
PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type,
1630
                                  NPStream* stream, NPBool seekable,
1631
                                  uint16_t* stype)
1632
0
{
1633
0
    AUTO_PROFILER_LABEL("PluginModuleParent::NPP_NewStream", OTHER);
1634
0
1635
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1636
0
    return pip ? pip->NPP_NewStream(type, stream, seekable, stype)
1637
0
               : NPERR_GENERIC_ERROR;
1638
0
}
1639
1640
NPError
1641
PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window)
1642
0
{
1643
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1644
0
    return pip ? pip->NPP_SetWindow(window) : NPERR_GENERIC_ERROR;
1645
0
}
1646
1647
NPError
1648
PluginModuleParent::NPP_DestroyStream(NPP instance,
1649
                                      NPStream* stream,
1650
                                      NPReason reason)
1651
0
{
1652
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1653
0
    return pip ? pip->NPP_DestroyStream(stream, reason) : NPERR_GENERIC_ERROR;
1654
0
}
1655
1656
int32_t
1657
PluginModuleParent::NPP_WriteReady(NPP instance,
1658
                                   NPStream* stream)
1659
0
{
1660
0
    BrowserStreamParent* s = StreamCast(instance, stream);
1661
0
    return s ? s->WriteReady() : -1;
1662
0
}
1663
1664
int32_t
1665
PluginModuleParent::NPP_Write(NPP instance,
1666
                              NPStream* stream,
1667
                              int32_t offset,
1668
                              int32_t len,
1669
                              void* buffer)
1670
0
{
1671
0
    BrowserStreamParent* s = StreamCast(instance, stream);
1672
0
    if (!s)
1673
0
        return -1;
1674
0
1675
0
    return s->Write(offset, len, buffer);
1676
0
}
1677
1678
void
1679
PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint)
1680
0
{
1681
0
1682
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1683
0
    return pip ? pip->NPP_Print(platformPrint) : (void)0;
1684
0
}
1685
1686
int16_t
1687
PluginModuleParent::NPP_HandleEvent(NPP instance, void* event)
1688
0
{
1689
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1690
0
    return pip ? pip->NPP_HandleEvent(event) : NPERR_GENERIC_ERROR;
1691
0
}
1692
1693
void
1694
PluginModuleParent::NPP_URLNotify(NPP instance, const char* url,
1695
                                  NPReason reason, void* notifyData)
1696
0
{
1697
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1698
0
    return pip ? pip->NPP_URLNotify(url, reason, notifyData) : (void)0;
1699
0
}
1700
1701
NPError
1702
PluginModuleParent::NPP_GetValue(NPP instance,
1703
                                 NPPVariable variable, void *ret_value)
1704
0
{
1705
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1706
0
    return pip ? pip->NPP_GetValue(variable, ret_value) : NPERR_GENERIC_ERROR;
1707
0
}
1708
1709
NPError
1710
PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
1711
                                 void *value)
1712
0
{
1713
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1714
0
    return pip ? pip->NPP_SetValue(variable, value) : NPERR_GENERIC_ERROR;
1715
0
}
1716
1717
mozilla::ipc::IPCResult
1718
PluginModuleChromeParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
1719
    const bool& shouldRegister, NPError* result)
1720
0
{
1721
#ifdef XP_WIN
1722
    *result = NPERR_NO_ERROR;
1723
    nsresult err =
1724
      mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
1725
                                                               shouldRegister);
1726
    if (err != NS_OK) {
1727
      *result = NPERR_GENERIC_ERROR;
1728
    }
1729
    return IPC_OK();
1730
#else
1731
0
    MOZ_CRASH("NPPVpluginRequiresAudioDeviceChanges is not valid on this platform.");
1732
0
#endif
1733
0
}
1734
1735
mozilla::ipc::IPCResult
1736
PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
1737
0
{
1738
#ifndef MOZ_X11
1739
    MOZ_CRASH("This message only makes sense on X11 platforms");
1740
#else
1741
0
    MOZ_ASSERT(0 > mPluginXSocketFdDup.get(),
1742
0
               "Already backed up X resources??");
1743
0
    if (aXSocketFd.IsValid()) {
1744
0
      auto rawFD = aXSocketFd.ClonePlatformHandle();
1745
0
      mPluginXSocketFdDup.reset(rawFD.release());
1746
0
    }
1747
0
#endif
1748
0
    return IPC_OK();
1749
0
}
1750
1751
void
1752
PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
1753
                                          int32_t status, void* notifyData)
1754
0
{
1755
0
  PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1756
0
  return pip ? pip->NPP_URLRedirectNotify(url, status, notifyData) : (void)0;
1757
0
}
1758
1759
BrowserStreamParent*
1760
PluginModuleParent::StreamCast(NPP instance, NPStream* s)
1761
0
{
1762
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1763
0
    if (!pip) {
1764
0
        return nullptr;
1765
0
    }
1766
0
1767
0
    BrowserStreamParent* sp =
1768
0
        static_cast<BrowserStreamParent*>(static_cast<AStream*>(s->pdata));
1769
0
    if (sp && (sp->mNPP != pip || s != sp->mStream)) {
1770
0
        MOZ_CRASH("Corrupted plugin stream data.");
1771
0
    }
1772
0
    return sp;
1773
0
}
1774
1775
bool
1776
PluginModuleParent::HasRequiredFunctions()
1777
0
{
1778
0
    return true;
1779
0
}
1780
1781
nsresult
1782
PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
1783
0
{
1784
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1785
0
    return pip ? pip->AsyncSetWindow(window) : NS_ERROR_FAILURE;
1786
0
}
1787
1788
nsresult
1789
PluginModuleParent::GetImageContainer(NPP instance,
1790
                             mozilla::layers::ImageContainer** aContainer)
1791
0
{
1792
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1793
0
    return pip ? pip->GetImageContainer(aContainer) : NS_ERROR_FAILURE;
1794
0
}
1795
1796
nsresult
1797
PluginModuleParent::GetImageSize(NPP instance,
1798
                                 nsIntSize* aSize)
1799
0
{
1800
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1801
0
    return pip ? pip->GetImageSize(aSize) : NS_ERROR_FAILURE;
1802
0
}
1803
1804
void
1805
PluginModuleParent::DidComposite(NPP aInstance)
1806
0
{
1807
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(aInstance);
1808
0
    return pip ? pip->DidComposite() : (void)0;
1809
0
}
1810
1811
nsresult
1812
PluginModuleParent::SetBackgroundUnknown(NPP instance)
1813
0
{
1814
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1815
0
    return pip ? pip->SetBackgroundUnknown() : NS_ERROR_FAILURE;
1816
0
}
1817
1818
nsresult
1819
PluginModuleParent::BeginUpdateBackground(NPP instance,
1820
                                          const nsIntRect& aRect,
1821
                                          DrawTarget** aDrawTarget)
1822
0
{
1823
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1824
0
    return pip ? pip->BeginUpdateBackground(aRect, aDrawTarget)
1825
0
               : NS_ERROR_FAILURE;
1826
0
}
1827
1828
nsresult
1829
PluginModuleParent::EndUpdateBackground(NPP instance, const nsIntRect& aRect)
1830
0
{
1831
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
1832
0
    return pip ? pip->EndUpdateBackground(aRect) : NS_ERROR_FAILURE;
1833
0
}
1834
1835
#if defined(XP_WIN)
1836
nsresult
1837
PluginModuleParent::GetScrollCaptureContainer(NPP aInstance,
1838
                                              mozilla::layers::ImageContainer** aContainer)
1839
{
1840
    PluginInstanceParent* pip = PluginInstanceParent::Cast(aInstance);
1841
    return pip ? pip->GetScrollCaptureContainer(aContainer) : NS_ERROR_FAILURE;
1842
}
1843
#endif
1844
1845
nsresult
1846
PluginModuleParent::HandledWindowedPluginKeyEvent(
1847
                        NPP aInstance,
1848
                        const NativeEventData& aNativeKeyData,
1849
                        bool aIsConsumed)
1850
0
{
1851
0
    PluginInstanceParent* pip = PluginInstanceParent::Cast(aInstance);
1852
0
    return pip ? pip->HandledWindowedPluginKeyEvent(aNativeKeyData, aIsConsumed)
1853
0
               : NS_ERROR_FAILURE;
1854
0
}
1855
1856
void
1857
PluginModuleParent::OnInitFailure()
1858
0
{
1859
0
    if (GetIPCChannel()->CanSend()) {
1860
0
        Close();
1861
0
    }
1862
0
1863
0
    mShutdown = true;
1864
0
}
1865
1866
class PluginOfflineObserver final : public nsIObserver
1867
{
1868
public:
1869
    NS_DECL_ISUPPORTS
1870
    NS_DECL_NSIOBSERVER
1871
1872
    explicit PluginOfflineObserver(PluginModuleChromeParent* pmp)
1873
      : mPmp(pmp)
1874
0
    {}
1875
1876
private:
1877
0
    ~PluginOfflineObserver() {}
1878
    PluginModuleChromeParent* mPmp;
1879
};
1880
1881
NS_IMPL_ISUPPORTS(PluginOfflineObserver, nsIObserver)
1882
1883
NS_IMETHODIMP
1884
PluginOfflineObserver::Observe(nsISupports *aSubject,
1885
                               const char *aTopic,
1886
                               const char16_t *aData)
1887
0
{
1888
0
    MOZ_ASSERT(!strcmp(aTopic, "ipc:network:set-offline"));
1889
0
    mPmp->CachedSettingChanged();
1890
0
    return NS_OK;
1891
0
}
1892
1893
void
1894
PluginModuleChromeParent::RegisterSettingsCallbacks()
1895
0
{
1896
0
    Preferences::RegisterCallback(CachedSettingChanged, "javascript.enabled", this);
1897
0
    Preferences::RegisterCallback(CachedSettingChanged, "dom.ipc.plugins.nativeCursorSupport", this);
1898
0
1899
0
    nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1900
0
    if (observerService) {
1901
0
        mPluginOfflineObserver = new PluginOfflineObserver(this);
1902
0
        observerService->AddObserver(mPluginOfflineObserver, "ipc:network:set-offline", false);
1903
0
    }
1904
0
}
1905
1906
void
1907
PluginModuleChromeParent::UnregisterSettingsCallbacks()
1908
0
{
1909
0
    Preferences::UnregisterCallback(CachedSettingChanged, "javascript.enabled", this);
1910
0
    Preferences::UnregisterCallback(CachedSettingChanged, "dom.ipc.plugins.nativeCursorSupport", this);
1911
0
1912
0
    nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1913
0
    if (observerService) {
1914
0
        observerService->RemoveObserver(mPluginOfflineObserver, "ipc:network:set-offline");
1915
0
        mPluginOfflineObserver = nullptr;
1916
0
    }
1917
0
}
1918
1919
bool
1920
PluginModuleParent::GetSetting(NPNVariable aVariable)
1921
0
{
1922
0
    NPBool boolVal = false;
1923
0
    mozilla::plugins::parent::_getvalue(nullptr, aVariable, &boolVal);
1924
0
    return boolVal;
1925
0
}
1926
1927
void
1928
PluginModuleParent::GetSettings(PluginSettings* aSettings)
1929
0
{
1930
0
    aSettings->javascriptEnabled() = GetSetting(NPNVjavascriptEnabledBool);
1931
0
    aSettings->asdEnabled() = GetSetting(NPNVasdEnabledBool);
1932
0
    aSettings->isOffline() = GetSetting(NPNVisOfflineBool);
1933
0
    aSettings->supportsXembed() = GetSetting(NPNVSupportsXEmbedBool);
1934
0
    aSettings->supportsWindowless() = GetSetting(NPNVSupportsWindowless);
1935
0
    aSettings->userAgent() = NullableString(mNPNIface->uagent(nullptr));
1936
0
1937
#if defined(XP_MACOSX)
1938
    aSettings->nativeCursorsSupported() =
1939
      Preferences::GetBool("dom.ipc.plugins.nativeCursorSupport", false);
1940
#else
1941
    // Need to initialize this to satisfy IPDL.
1942
0
    aSettings->nativeCursorsSupported() = false;
1943
0
#endif
1944
0
}
1945
1946
void
1947
PluginModuleChromeParent::CachedSettingChanged()
1948
0
{
1949
0
    PluginSettings settings;
1950
0
    GetSettings(&settings);
1951
0
    Unused << SendSettingChanged(settings);
1952
0
}
1953
1954
/* static */ void
1955
PluginModuleChromeParent::CachedSettingChanged(const char* aPref, PluginModuleChromeParent* aModule)
1956
0
{
1957
0
    aModule->CachedSettingChanged();
1958
0
}
1959
1960
#if defined(XP_UNIX) && !defined(XP_MACOSX)
1961
nsresult
1962
PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
1963
0
{
1964
0
    PLUGIN_LOG_DEBUG_METHOD;
1965
0
1966
0
    mNPNIface = bFuncs;
1967
0
    mNPPIface = pFuncs;
1968
0
1969
0
    if (mShutdown) {
1970
0
        *error = NPERR_GENERIC_ERROR;
1971
0
        return NS_ERROR_FAILURE;
1972
0
    }
1973
0
1974
0
    *error = NPERR_NO_ERROR;
1975
0
    SetPluginFuncs(pFuncs);
1976
0
1977
0
    return NS_OK;
1978
0
}
1979
1980
nsresult
1981
PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
1982
0
{
1983
0
    PLUGIN_LOG_DEBUG_METHOD;
1984
0
1985
0
    if (mShutdown) {
1986
0
        *error = NPERR_GENERIC_ERROR;
1987
0
        return NS_ERROR_FAILURE;
1988
0
    }
1989
0
1990
0
    *error = NPERR_NO_ERROR;
1991
0
1992
0
    mNPNIface = bFuncs;
1993
0
    mNPPIface = pFuncs;
1994
0
1995
0
    PluginSettings settings;
1996
0
    GetSettings(&settings);
1997
0
1998
0
    if (!CallNP_Initialize(settings, error)) {
1999
0
        Close();
2000
0
        return NS_ERROR_FAILURE;
2001
0
    }
2002
0
    else if (*error != NPERR_NO_ERROR) {
2003
0
        Close();
2004
0
        return NS_ERROR_FAILURE;
2005
0
    }
2006
0
2007
0
    if (*error != NPERR_NO_ERROR) {
2008
0
        OnInitFailure();
2009
0
        return NS_OK;
2010
0
    }
2011
0
2012
0
    SetPluginFuncs(mNPPIface);
2013
0
2014
0
    return NS_OK;
2015
0
}
2016
2017
#else
2018
2019
nsresult
2020
PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
2021
{
2022
    PLUGIN_LOG_DEBUG_METHOD;
2023
2024
    mNPNIface = bFuncs;
2025
2026
    if (mShutdown) {
2027
        *error = NPERR_GENERIC_ERROR;
2028
        return NS_ERROR_FAILURE;
2029
    }
2030
2031
    *error = NPERR_NO_ERROR;
2032
    return NS_OK;
2033
}
2034
2035
#if defined(XP_WIN) || defined(XP_MACOSX)
2036
2037
nsresult
2038
PluginModuleContentParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
2039
{
2040
    PLUGIN_LOG_DEBUG_METHOD;
2041
    return PluginModuleParent::NP_Initialize(bFuncs, error);
2042
}
2043
2044
#endif
2045
2046
nsresult
2047
PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
2048
{
2049
    nsresult rv = PluginModuleParent::NP_Initialize(bFuncs, error);
2050
    if (NS_FAILED(rv))
2051
        return rv;
2052
2053
    PluginSettings settings;
2054
    GetSettings(&settings);
2055
2056
    if (!CallNP_Initialize(settings, error)) {
2057
        Close();
2058
        return NS_ERROR_FAILURE;
2059
    }
2060
2061
    bool ok = true;
2062
    if (*error == NPERR_NO_ERROR) {
2063
        // Initialization steps for (e10s && !asyncInit) || !e10s
2064
#if defined XP_WIN
2065
        // Send the info needed to join the browser process's audio session to
2066
        // the plugin process.
2067
        nsID id;
2068
        nsString sessionName;
2069
        nsString iconPath;
2070
2071
        if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
2072
                                                              iconPath))) {
2073
            Unused << SendSetAudioSessionData(id, sessionName, iconPath);
2074
        }
2075
#endif
2076
2077
#ifdef MOZ_CRASHREPORTER_INJECTOR
2078
        InitializeInjector();
2079
#endif
2080
    }
2081
2082
    if (!ok) {
2083
        return NS_ERROR_FAILURE;
2084
    }
2085
2086
    if (*error != NPERR_NO_ERROR) {
2087
        OnInitFailure();
2088
        return NS_OK;
2089
    }
2090
2091
    return NS_OK;
2092
}
2093
2094
#endif
2095
2096
nsresult
2097
PluginModuleParent::NP_Shutdown(NPError* error)
2098
0
{
2099
0
    PLUGIN_LOG_DEBUG_METHOD;
2100
0
2101
0
    if (mShutdown) {
2102
0
        *error = NPERR_GENERIC_ERROR;
2103
0
        return NS_ERROR_FAILURE;
2104
0
    }
2105
0
2106
0
    if (!DoShutdown(error)) {
2107
0
        return NS_ERROR_FAILURE;
2108
0
    }
2109
0
2110
0
    return NS_OK;
2111
0
}
2112
2113
bool
2114
PluginModuleParent::DoShutdown(NPError* error)
2115
0
{
2116
0
    bool ok = true;
2117
0
    if (IsChrome() && mHadLocalInstance) {
2118
0
        // We synchronously call NP_Shutdown if the chrome process was using
2119
0
        // plugins itself. That way we can service any requests the plugin
2120
0
        // makes. If we're in e10s, though, the content processes will have
2121
0
        // already shut down and there's no one to talk to. So we shut down
2122
0
        // asynchronously in PluginModuleChild::ActorDestroy.
2123
0
        ok = CallNP_Shutdown(error);
2124
0
    }
2125
0
2126
0
    // if NP_Shutdown() is nested within another interrupt call, this will
2127
0
    // break things.  but lord help us if we're doing that anyway; the
2128
0
    // plugin dso will have been unloaded on the other side by the
2129
0
    // CallNP_Shutdown() message
2130
0
    Close();
2131
0
2132
0
    // mShutdown should either be initialized to false, or be transitiong from
2133
0
    // false to true. It is never ok to go from true to false. Using OR for
2134
0
    // the following assignment to ensure this.
2135
0
    mShutdown |= ok;
2136
0
    if (!ok) {
2137
0
        *error = NPERR_GENERIC_ERROR;
2138
0
    }
2139
0
    return ok;
2140
0
}
2141
2142
nsresult
2143
PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
2144
0
{
2145
0
    PLUGIN_LOG_DEBUG_METHOD;
2146
0
2147
0
    *mimeDesc = "application/x-foobar";
2148
0
    return NS_OK;
2149
0
}
2150
2151
nsresult
2152
PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable,
2153
                                   void *aValue, NPError* error)
2154
0
{
2155
0
    MOZ_LOG(GetPluginLog(), LogLevel::Warning, ("%s Not implemented, requested variable %i", __FUNCTION__,
2156
0
                                        (int) aVariable));
2157
0
2158
0
    //TODO: implement this correctly
2159
0
    *error = NPERR_GENERIC_ERROR;
2160
0
    return NS_OK;
2161
0
}
2162
2163
#if defined(XP_WIN) || defined(XP_MACOSX)
2164
nsresult
2165
PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
2166
{
2167
    NS_ASSERTION(pFuncs, "Null pointer!");
2168
2169
    *error = NPERR_NO_ERROR;
2170
    SetPluginFuncs(pFuncs);
2171
2172
    return NS_OK;
2173
}
2174
2175
nsresult
2176
PluginModuleChromeParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
2177
{
2178
#if !defined(XP_MACOSX)
2179
    if (!mSubprocess->IsConnected()) {
2180
        mNPPIface = pFuncs;
2181
        *error = NPERR_NO_ERROR;
2182
        return NS_OK;
2183
    }
2184
#endif
2185
2186
    // We need to have the plugin process update its function table here by
2187
    // actually calling NP_GetEntryPoints. The parent's function table will
2188
    // reflect nullptr entries in the child's table once SetPluginFuncs is
2189
    // called.
2190
2191
    if (!CallNP_GetEntryPoints(error)) {
2192
        return NS_ERROR_FAILURE;
2193
    }
2194
    else if (*error != NPERR_NO_ERROR) {
2195
        return NS_OK;
2196
    }
2197
2198
    return PluginModuleParent::NP_GetEntryPoints(pFuncs, error);
2199
}
2200
2201
#endif
2202
2203
nsresult
2204
PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
2205
                            int16_t argc, char* argn[],
2206
                            char* argv[], NPSavedData* saved,
2207
                            NPError* error)
2208
0
{
2209
0
    PLUGIN_LOG_DEBUG_METHOD;
2210
0
2211
0
    if (mShutdown) {
2212
0
        *error = NPERR_GENERIC_ERROR;
2213
0
        return NS_ERROR_FAILURE;
2214
0
    }
2215
0
2216
0
    // create the instance on the other side
2217
0
    InfallibleTArray<nsCString> names;
2218
0
    InfallibleTArray<nsCString> values;
2219
0
2220
0
    for (int i = 0; i < argc; ++i) {
2221
0
        names.AppendElement(NullableString(argn[i]));
2222
0
        values.AppendElement(NullableString(argv[i]));
2223
0
    }
2224
0
2225
0
    return NPP_NewInternal(pluginType, instance, names, values, saved, error);
2226
0
}
2227
2228
class nsCaseInsensitiveUTF8StringArrayComparator
2229
{
2230
public:
2231
  template<class A, class B>
2232
0
  bool Equals(const A& a, const B& b) const {
2233
0
    return a.Equals(b.get(), nsCaseInsensitiveUTF8StringComparator());
2234
0
  }
2235
};
2236
2237
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
2238
static void
2239
ForceWindowless(InfallibleTArray<nsCString>& names,
2240
                InfallibleTArray<nsCString>& values)
2241
0
{
2242
0
    nsCaseInsensitiveUTF8StringArrayComparator comparator;
2243
0
    NS_NAMED_LITERAL_CSTRING(wmodeAttributeName, "wmode");
2244
0
    NS_NAMED_LITERAL_CSTRING(opaqueAttributeValue, "opaque");
2245
0
    auto wmodeAttributeIndex =
2246
0
        names.IndexOf(wmodeAttributeName, 0, comparator);
2247
0
    if (wmodeAttributeIndex != names.NoIndex) {
2248
0
        if (!values[wmodeAttributeIndex].EqualsLiteral("transparent")) {
2249
0
            values[wmodeAttributeIndex].Assign(opaqueAttributeValue);
2250
0
        }
2251
0
    } else {
2252
0
        names.AppendElement(wmodeAttributeName);
2253
0
        values.AppendElement(opaqueAttributeValue);
2254
0
    }
2255
0
}
2256
#endif // windows or linux
2257
#if defined(XP_WIN)
2258
static void
2259
ForceDirect(InfallibleTArray<nsCString>& names,
2260
            InfallibleTArray<nsCString>& values)
2261
{
2262
    nsCaseInsensitiveUTF8StringArrayComparator comparator;
2263
    NS_NAMED_LITERAL_CSTRING(wmodeAttributeName, "wmode");
2264
    NS_NAMED_LITERAL_CSTRING(directAttributeValue, "direct");
2265
    auto wmodeAttributeIndex =
2266
        names.IndexOf(wmodeAttributeName, 0, comparator);
2267
    if (wmodeAttributeIndex != names.NoIndex) {
2268
        if (values[wmodeAttributeIndex].EqualsLiteral("window")) {
2269
            values[wmodeAttributeIndex].Assign(directAttributeValue);
2270
        }
2271
    } else {
2272
        names.AppendElement(wmodeAttributeName);
2273
        values.AppendElement(directAttributeValue);
2274
    }
2275
}
2276
#endif // windows
2277
2278
nsresult
2279
PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
2280
                                    InfallibleTArray<nsCString>& names,
2281
                                    InfallibleTArray<nsCString>& values,
2282
                                    NPSavedData* saved, NPError* error)
2283
0
{
2284
0
    MOZ_ASSERT(names.Length() == values.Length());
2285
0
    if (mPluginName.IsEmpty()) {
2286
0
        GetPluginDetails();
2287
0
        InitQuirksModes(nsDependentCString(pluginType));
2288
0
    }
2289
0
2290
0
    nsCaseInsensitiveUTF8StringArrayComparator comparator;
2291
0
    NS_NAMED_LITERAL_CSTRING(srcAttributeName, "src");
2292
0
    auto srcAttributeIndex = names.IndexOf(srcAttributeName, 0, comparator);
2293
0
    nsAutoCString srcAttribute;
2294
0
    if (srcAttributeIndex != names.NoIndex) {
2295
0
        srcAttribute = values[srcAttributeIndex];
2296
0
    }
2297
0
2298
0
    nsDependentCString strPluginType(pluginType);
2299
0
    PluginInstanceParent* parentInstance =
2300
0
        new PluginInstanceParent(this, instance, strPluginType, mNPNIface);
2301
0
2302
0
    if (mIsFlashPlugin) {
2303
0
        parentInstance->InitMetadata(strPluginType, srcAttribute);
2304
#ifdef XP_WIN
2305
        bool supportsAsyncRender =
2306
          Preferences::GetBool("dom.ipc.plugins.asyncdrawing.enabled", false);
2307
        bool supportsForceDirect =
2308
          Preferences::GetBool("dom.ipc.plugins.forcedirect.enabled", false);
2309
        if (supportsAsyncRender) {
2310
          // Prefs indicates we want async plugin rendering, make sure
2311
          // the flash module has support.
2312
          if(!CallModuleSupportsAsyncRender(&supportsAsyncRender)) {
2313
            *error = NPERR_GENERIC_ERROR;
2314
            return NS_ERROR_FAILURE;
2315
          }
2316
        }
2317
#ifdef _WIN64
2318
        // For 64-bit builds force windowless if the flash library doesn't support
2319
        // async rendering regardless of sandbox level.
2320
        if (!supportsAsyncRender) {
2321
#else
2322
        // For 32-bit builds force windowless if the flash library doesn't support
2323
        // async rendering and the sandbox level is 2 or greater.
2324
        if (!supportsAsyncRender && mSandboxLevel >= 2) {
2325
#endif
2326
            ForceWindowless(names, values);
2327
        }
2328
#elif defined(MOZ_WIDGET_GTK)
2329
        // We no longer support windowed mode on Linux.
2330
0
        ForceWindowless(names, values);
2331
0
#endif
2332
#ifdef XP_WIN
2333
        // For all builds that use async rendering force use of the accelerated
2334
        // direct path for flash objects that have wmode=window or no wmode
2335
        // specified.
2336
        if (supportsAsyncRender && supportsForceDirect &&
2337
            gfxWindowsPlatform::GetPlatform()->SupportsPluginDirectDXGIDrawing()) {
2338
            ForceDirect(names, values);
2339
        }
2340
#endif
2341
    }
2342
0
2343
0
    instance->pdata = parentInstance;
2344
0
2345
0
    // Any IPC messages for the PluginInstance actor should be dispatched to the
2346
0
    // DocGroup for the plugin's document.
2347
0
    RefPtr<nsPluginInstanceOwner> owner = parentInstance->GetOwner();
2348
0
    RefPtr<dom::Element> elt;
2349
0
    owner->GetDOMElement(getter_AddRefs(elt));
2350
0
    if (elt) {
2351
0
        nsCOMPtr<nsIDocument> doc = elt->OwnerDoc();
2352
0
        if (doc) {
2353
0
            nsCOMPtr<nsIEventTarget> eventTarget = doc->EventTargetFor(TaskCategory::Other);
2354
0
            SetEventTargetForActor(parentInstance, eventTarget);
2355
0
        }
2356
0
    }
2357
0
2358
0
    if (!SendPPluginInstanceConstructor(parentInstance,
2359
0
                                        nsDependentCString(pluginType),
2360
0
                                        names, values)) {
2361
0
        // |parentInstance| is automatically deleted.
2362
0
        instance->pdata = nullptr;
2363
0
        *error = NPERR_GENERIC_ERROR;
2364
0
        return NS_ERROR_FAILURE;
2365
0
    }
2366
0
2367
0
    if (!CallSyncNPP_New(parentInstance, error)) {
2368
0
        // if IPC is down, we'll get an immediate "failed" return, but
2369
0
        // without *error being set.  So make sure that the error
2370
0
        // condition is signaled to nsNPAPIPluginInstance
2371
0
        if (NPERR_NO_ERROR == *error) {
2372
0
            *error = NPERR_GENERIC_ERROR;
2373
0
        }
2374
0
        return NS_ERROR_FAILURE;
2375
0
    }
2376
0
2377
0
    if (*error != NPERR_NO_ERROR) {
2378
0
        NPP_Destroy(instance, 0);
2379
0
        return NS_ERROR_FAILURE;
2380
0
    }
2381
0
2382
0
    Telemetry::ScalarAdd(Telemetry::ScalarID::BROWSER_USAGE_PLUGIN_INSTANTIATED, 1);
2383
0
2384
0
    UpdatePluginTimeout();
2385
0
2386
0
    return NS_OK;
2387
0
}
2388
2389
void
2390
PluginModuleChromeParent::UpdatePluginTimeout()
2391
0
{
2392
0
    TimeoutChanged(kParentTimeoutPref, this);
2393
0
}
2394
2395
nsresult
2396
PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
2397
                                      nsCOMPtr<nsIClearSiteDataCallback> callback)
2398
0
{
2399
0
    if (!mClearSiteDataSupported)
2400
0
        return NS_ERROR_NOT_AVAILABLE;
2401
0
2402
0
    static uint64_t callbackId = 0;
2403
0
    callbackId++;
2404
0
    mClearSiteDataCallbacks[callbackId] = callback;
2405
0
2406
0
    if (!SendNPP_ClearSiteData(NullableString(site), flags, maxAge, callbackId)) {
2407
0
        return NS_ERROR_FAILURE;
2408
0
    }
2409
0
    return NS_OK;
2410
0
}
2411
2412
2413
nsresult
2414
PluginModuleParent::NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback)
2415
0
{
2416
0
    if (!mGetSitesWithDataSupported)
2417
0
        return NS_ERROR_NOT_AVAILABLE;
2418
0
2419
0
    static uint64_t callbackId = 0;
2420
0
    callbackId++;
2421
0
    mSitesWithDataCallbacks[callbackId] = callback;
2422
0
2423
0
    if (!SendNPP_GetSitesWithData(callbackId))
2424
0
        return NS_ERROR_FAILURE;
2425
0
2426
0
    return NS_OK;
2427
0
}
2428
2429
#if defined(XP_MACOSX)
2430
nsresult
2431
PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
2432
{
2433
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
2434
    return pip ? pip->IsRemoteDrawingCoreAnimation(aDrawing) : NS_ERROR_FAILURE;
2435
}
2436
#endif
2437
#if defined(XP_MACOSX) || defined(XP_WIN)
2438
nsresult
2439
PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
2440
{
2441
    PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
2442
    return pip ? pip->ContentsScaleFactorChanged(aContentsScaleFactor)
2443
               : NS_ERROR_FAILURE;
2444
}
2445
#endif // #if defined(XP_MACOSX)
2446
2447
#if defined(XP_MACOSX)
2448
mozilla::ipc::IPCResult
2449
PluginModuleParent::AnswerProcessSomeEvents()
2450
{
2451
    mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
2452
    return IPC_OK();
2453
}
2454
2455
#elif !defined(MOZ_WIDGET_GTK)
2456
mozilla::ipc::IPCResult
2457
PluginModuleParent::AnswerProcessSomeEvents()
2458
{
2459
    MOZ_CRASH("unreached");
2460
}
2461
2462
#else
2463
static const int kMaxChancesToProcessEvents = 20;
2464
2465
mozilla::ipc::IPCResult
2466
PluginModuleParent::AnswerProcessSomeEvents()
2467
0
{
2468
0
    PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
2469
0
2470
0
    int i = 0;
2471
0
    for (; i < kMaxChancesToProcessEvents; ++i)
2472
0
        if (!g_main_context_iteration(nullptr, FALSE))
2473
0
            break;
2474
0
2475
0
    PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i));
2476
0
2477
0
    return IPC_OK();
2478
0
}
2479
#endif
2480
2481
mozilla::ipc::IPCResult
2482
PluginModuleParent::RecvProcessNativeEventsInInterruptCall()
2483
0
{
2484
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2485
#if defined(OS_WIN)
2486
    ProcessNativeEventsInInterruptCall();
2487
    return IPC_OK();
2488
#else
2489
0
    MOZ_ASSERT_UNREACHABLE(
2490
0
        "PluginModuleParent::RecvProcessNativeEventsInInterruptCall not implemented!");
2491
0
    return IPC_FAIL_NO_REASON(this);
2492
0
#endif
2493
0
}
2494
2495
void
2496
PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall()
2497
0
{
2498
#if defined(OS_WIN)
2499
    Unused << SendProcessNativeEventsInInterruptCall();
2500
    return;
2501
#endif
2502
0
    MOZ_ASSERT_UNREACHABLE(
2503
0
        "PluginModuleParent::ProcessRemoteNativeEventsInInterruptCall not implemented!");
2504
0
}
2505
2506
mozilla::ipc::IPCResult
2507
PluginModuleParent::RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
2508
                                         const int32_t& aX, const int32_t& aY,
2509
                                         const size_t& aWidth, const size_t& aHeight)
2510
0
{
2511
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2512
#if defined(XP_MACOSX)
2513
    CGRect windowBound = ::CGRectMake(aX, aY, aWidth, aHeight);
2514
    mac_plugin_interposing::parent::OnPluginShowWindow(aWindowId, windowBound, aModal);
2515
    return IPC_OK();
2516
#else
2517
0
    MOZ_ASSERT_UNREACHABLE(
2518
0
        "PluginInstanceParent::RecvPluginShowWindow not implemented!");
2519
0
    return IPC_FAIL_NO_REASON(this);
2520
0
#endif
2521
0
}
2522
2523
mozilla::ipc::IPCResult
2524
PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
2525
0
{
2526
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2527
#if defined(XP_MACOSX)
2528
    mac_plugin_interposing::parent::OnPluginHideWindow(aWindowId, OtherPid());
2529
    return IPC_OK();
2530
#else
2531
0
    MOZ_ASSERT_UNREACHABLE(
2532
0
        "PluginInstanceParent::RecvPluginHideWindow not implemented!");
2533
0
    return IPC_FAIL_NO_REASON(this);
2534
0
#endif
2535
0
}
2536
2537
mozilla::ipc::IPCResult
2538
PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
2539
0
{
2540
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2541
#if defined(XP_MACOSX)
2542
    mac_plugin_interposing::parent::OnSetCursor(aCursorInfo);
2543
    return IPC_OK();
2544
#else
2545
0
    MOZ_ASSERT_UNREACHABLE(
2546
0
        "PluginInstanceParent::RecvSetCursor not implemented!");
2547
0
    return IPC_FAIL_NO_REASON(this);
2548
0
#endif
2549
0
}
2550
2551
mozilla::ipc::IPCResult
2552
PluginModuleParent::RecvShowCursor(const bool& aShow)
2553
0
{
2554
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2555
#if defined(XP_MACOSX)
2556
    mac_plugin_interposing::parent::OnShowCursor(aShow);
2557
    return IPC_OK();
2558
#else
2559
0
    MOZ_ASSERT_UNREACHABLE(
2560
0
        "PluginInstanceParent::RecvShowCursor not implemented!");
2561
0
    return IPC_FAIL_NO_REASON(this);
2562
0
#endif
2563
0
}
2564
2565
mozilla::ipc::IPCResult
2566
PluginModuleParent::RecvPushCursor(const NSCursorInfo& aCursorInfo)
2567
0
{
2568
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2569
#if defined(XP_MACOSX)
2570
    mac_plugin_interposing::parent::OnPushCursor(aCursorInfo);
2571
    return IPC_OK();
2572
#else
2573
0
    MOZ_ASSERT_UNREACHABLE(
2574
0
        "PluginInstanceParent::RecvPushCursor not implemented!");
2575
0
    return IPC_FAIL_NO_REASON(this);
2576
0
#endif
2577
0
}
2578
2579
mozilla::ipc::IPCResult
2580
PluginModuleParent::RecvPopCursor()
2581
0
{
2582
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2583
#if defined(XP_MACOSX)
2584
    mac_plugin_interposing::parent::OnPopCursor();
2585
    return IPC_OK();
2586
#else
2587
0
    MOZ_ASSERT_UNREACHABLE(
2588
0
        "PluginInstanceParent::RecvPopCursor not implemented!");
2589
0
    return IPC_FAIL_NO_REASON(this);
2590
0
#endif
2591
0
}
2592
2593
mozilla::ipc::IPCResult
2594
PluginModuleParent::RecvNPN_SetException(const nsCString& aMessage)
2595
0
{
2596
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2597
0
2598
0
    // This function ignores its first argument.
2599
0
    mozilla::plugins::parent::_setexception(nullptr, NullableStringGet(aMessage));
2600
0
    return IPC_OK();
2601
0
}
2602
2603
mozilla::ipc::IPCResult
2604
PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
2605
0
{
2606
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2607
0
2608
0
    mozilla::plugins::parent::_reloadplugins(aReloadPages);
2609
0
    return IPC_OK();
2610
0
}
2611
2612
mozilla::ipc::IPCResult
2613
PluginModuleChromeParent::RecvNotifyContentModuleDestroyed()
2614
0
{
2615
0
    RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
2616
0
    if (host) {
2617
0
        host->NotifyContentModuleDestroyed(mPluginId);
2618
0
    }
2619
0
    return IPC_OK();
2620
0
}
2621
2622
mozilla::ipc::IPCResult
2623
PluginModuleParent::RecvReturnClearSiteData(const NPError& aRv,
2624
                                            const uint64_t& aCallbackId)
2625
0
{
2626
0
    if (mClearSiteDataCallbacks.find(aCallbackId) == mClearSiteDataCallbacks.end()) {
2627
0
        return IPC_OK();
2628
0
    }
2629
0
    if (!!mClearSiteDataCallbacks[aCallbackId]) {
2630
0
        nsresult rv;
2631
0
        switch (aRv) {
2632
0
        case NPERR_NO_ERROR:
2633
0
            rv = NS_OK;
2634
0
            break;
2635
0
        case NPERR_TIME_RANGE_NOT_SUPPORTED:
2636
0
            rv = NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
2637
0
            break;
2638
0
        case NPERR_MALFORMED_SITE:
2639
0
            rv = NS_ERROR_INVALID_ARG;
2640
0
            break;
2641
0
        default:
2642
0
            rv = NS_ERROR_FAILURE;
2643
0
        }
2644
0
        mClearSiteDataCallbacks[aCallbackId]->Callback(rv);
2645
0
    }
2646
0
    mClearSiteDataCallbacks.erase(aCallbackId);
2647
0
    return IPC_OK();
2648
0
}
2649
2650
mozilla::ipc::IPCResult
2651
PluginModuleParent::RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
2652
                                            const uint64_t& aCallbackId)
2653
0
{
2654
0
    if (mSitesWithDataCallbacks.find(aCallbackId) == mSitesWithDataCallbacks.end()) {
2655
0
        return IPC_OK();
2656
0
    }
2657
0
2658
0
    if (!!mSitesWithDataCallbacks[aCallbackId]) {
2659
0
        mSitesWithDataCallbacks[aCallbackId]->SitesWithData(aSites);
2660
0
    }
2661
0
    mSitesWithDataCallbacks.erase(aCallbackId);
2662
0
    return IPC_OK();
2663
0
}
2664
2665
layers::TextureClientRecycleAllocator*
2666
PluginModuleParent::EnsureTextureAllocatorForDirectBitmap()
2667
0
{
2668
0
    if (!mTextureAllocatorForDirectBitmap) {
2669
0
        mTextureAllocatorForDirectBitmap = new TextureClientRecycleAllocator(ImageBridgeChild::GetSingleton().get());
2670
0
    }
2671
0
    return mTextureAllocatorForDirectBitmap;
2672
0
}
2673
2674
layers::TextureClientRecycleAllocator*
2675
PluginModuleParent::EnsureTextureAllocatorForDXGISurface()
2676
0
{
2677
0
    if (!mTextureAllocatorForDXGISurface) {
2678
0
        mTextureAllocatorForDXGISurface = new TextureClientRecycleAllocator(ImageBridgeChild::GetSingleton().get());
2679
0
    }
2680
0
    return mTextureAllocatorForDXGISurface;
2681
0
}
2682
2683
2684
mozilla::ipc::IPCResult
2685
PluginModuleParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
2686
                                        const bool& shouldRegister,
2687
0
                                        NPError* result) {
2688
0
    MOZ_CRASH("SetValue_NPPVpluginRequiresAudioDeviceChanges is only valid "
2689
0
              "with PluginModuleChromeParent");
2690
0
}
2691
2692
#ifdef MOZ_CRASHREPORTER_INJECTOR
2693
2694
// We only add the crash reporter to subprocess which have the filename
2695
// FlashPlayerPlugin*
2696
#define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
2697
2698
static DWORD
2699
GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
2700
{
2701
    PROCESSENTRY32 entry = {
2702
        sizeof(entry)
2703
    };
2704
    for (BOOL ok = Process32First(snapshot, &entry);
2705
         ok;
2706
         ok = Process32Next(snapshot, &entry)) {
2707
        if (entry.th32ParentProcessID == pid) {
2708
            nsString name(entry.szExeFile);
2709
            ToUpperCase(name);
2710
            if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) {
2711
                return entry.th32ProcessID;
2712
            }
2713
        }
2714
    }
2715
    return 0;
2716
}
2717
2718
// We only look for child processes of the Flash plugin, NPSWF*
2719
#define FLASH_PLUGIN_PREFIX "NPSWF"
2720
2721
void
2722
PluginModuleChromeParent::InitializeInjector()
2723
{
2724
    if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
2725
        return;
2726
2727
    nsCString path(Process()->GetPluginFilePath().c_str());
2728
    ToUpperCase(path);
2729
    int32_t lastSlash = path.RFindCharInSet("\\/");
2730
    if (kNotFound == lastSlash)
2731
        return;
2732
2733
    if (!StringBeginsWith(Substring(path, lastSlash + 1),
2734
                          NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
2735
        return;
2736
2737
    mFinishInitTask = mChromeTaskFactory.NewTask<FinishInjectorInitTask>();
2738
    mFinishInitTask->Init(this);
2739
    if (!::QueueUserWorkItem(&PluginModuleChromeParent::GetToolhelpSnapshot,
2740
                             mFinishInitTask, WT_EXECUTEDEFAULT)) {
2741
        mFinishInitTask = nullptr;
2742
        return;
2743
    }
2744
}
2745
2746
void
2747
PluginModuleChromeParent::DoInjection(const nsAutoHandle& aSnapshot)
2748
{
2749
    DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
2750
    mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, aSnapshot);
2751
    if (mFlashProcess1) {
2752
        InjectCrashReporterIntoProcess(mFlashProcess1, this);
2753
2754
        mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, aSnapshot);
2755
        if (mFlashProcess2) {
2756
            InjectCrashReporterIntoProcess(mFlashProcess2, this);
2757
        }
2758
    }
2759
    mFinishInitTask = nullptr;
2760
}
2761
2762
DWORD WINAPI
2763
PluginModuleChromeParent::GetToolhelpSnapshot(LPVOID aContext)
2764
{
2765
    FinishInjectorInitTask* task = static_cast<FinishInjectorInitTask*>(aContext);
2766
    MOZ_ASSERT(task);
2767
    task->PostToMainThread();
2768
    return 0;
2769
}
2770
2771
void
2772
PluginModuleChromeParent::OnCrash(DWORD processID)
2773
{
2774
    if (!mShutdown) {
2775
        GetIPCChannel()->CloseWithError();
2776
        mozilla::ipc::ScopedProcessHandle geckoPluginChild;
2777
        if (base::OpenProcessHandle(OtherPid(), &geckoPluginChild.rwget())) {
2778
            if (!base::KillProcess(geckoPluginChild,
2779
                                   base::PROCESS_END_KILLED_BY_USER, false)) {
2780
                NS_ERROR("May have failed to kill child process.");
2781
            }
2782
        } else {
2783
            NS_ERROR("Failed to open child process when attempting kill.");
2784
        }
2785
    }
2786
}
2787
2788
#endif // MOZ_CRASHREPORTER_INJECTOR