mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
bc8ce42355
- Bug 1226200: Don't assume a TCPSocket has only one managee (and rename LoneManagedOrNull) r=jdm (aa2d0fcc14) - Bug 1227300, Part 1 - Add an alert notification component. r=MattN,wchen (37758ce9ff) - Bug 1230700. Make Notification::ShowInternal explicitly suppress the exception from GetPermissionInternal. r=smaug (9e288cf5ae) - Bug 1225336 - Add telemetry about web notification display/messages. r=wchen,kitcambridge p=vladan# Please enter the commit message for your changes. Lines starting (b2e481691a) - Bug 1219030 - Collect notification management telemetry. r=wchen,MattN; p=ally (c0ba425b4e) - Bug 1212611 - Use system notification for website notifications in Android. r=mfinkle (84985bcf01) - Bug 1227300, Part 2 - Implement showAlert. r=MattN,wchen (33eedc7e91) - Bug 1214305 - Part 0: Ensure site security service is initialized before trying to use DataStorage via IPC. (8bd73f43b0) - Bug 1137681 - Make user agent docshell overrides affect network requests. r=jduell (e8dabb8338) - Bug 1233245 - Propagate the interception information in the non-e10s case for all HTTP redirects, not just the internal ones; r=jdm (6922fddcf8) - Bug 1226444 - Use helper function to identify preloads. r=sicking (d110669f73) - Bug 1214305 - Part 1: Refactor the logic for querying whether a connection should go through a secure upgrade into NS_ShouldSecureUpgrade; r=mcmanus (2d04c78290) - Bug 1137681 - Per-tab user agent emulation. r=bz (4ff70db690) - Bug 1227300, Part 3 - Implement showAlert for the OS X alerts backend. r=mstange (5eb05d0728) - Bug 1227300, Part 4 - Implement showAlert for the libnotify alerts backend. r=karlt (0942fa2764) - Bug 1227300, Part 5 - Implement showAlert for the B2G alerts backend. r=mhenretty (e39581aea5) - Bug 1227300, Part 6 - Use showAlert to display web notifications. r=wchen (ab79eaa0c8) - domBug 1227300, Part 7 - Update test interfaces. a=testonly (387cb62772) - Bug 1214305 - Part 3: Add a nsIInterceptedChannel.secureUpgradedChannelURI helper; r=jdm (811d25bd58) - Bug 1214305 - Part 4: Use the secure upgraded channel URI in ServiceWorkerManager::PrepareFetchEvent; r=jdm (0c44bf527c) - Bug 1214305 - Part 5: Use the secure upgraded channel URI in FetchEventRunnable::Init; r=jdm (a30f239261) - Bug 1214305 - Part 6: Use a non-IPC redirect for synthesized upgraded responses to ensure the response URL is correctly propagated; r=mcmanus (8ba8a5728c) - Bug 1214305 - Part 7: Decide in the child process whether an intercepted channel should go through a secure upgrade; r=mcmanus (93e27decae) - Bug 1198397 - Add a test for interception of requests upgraded through the CSP upgrade-insecure-requests directive; r=jdm (21eb14eb34) - Bug 1214305 - Part 8: Enable secure upgrade service worker tests on e10s; r=jdm (c14f5fb504) - Bug 1214305 - Part 10: Clean up global DataStorage references in the child process; r=keeler (ef0b52d049) - Bug 1224771 - Close all web notifications when the originating tab is closed. r=wchen (da295b4ba7) - Bug 1214305 - Part 2: Refactor the logic for obtaining the secure upgraded URI into HttpBaseChannel; r=mcmanus (3346078285) - Bug 1237151 (part 1) - Remove ignored qualifiers in dom/media/gmp/. r=cpearce. (18134820a6) - Bug 1237151 (part 2) - Remove ignored qualifiers in WebRTC-relate code. r=jesup. (effe5bd694) - Bug 1118820 part 1 (style system part) - [css-grid] Implement the 'auto-fill' and 'auto-fit' keywords in the repeat() function. r=dholbert (5db1a577db) - Bug 1118820 part 2a - [css-grid] Add a LineNameMap class that lets us lookup line names with a dynamic number of 'repeat(auto-fill/auto-fit)' tracks taken into account. r=dholbert (3ecf4b53f0) - Bug 1118820 part 2b - [css-grid] Move the static functions FindLine/RFindLine/FindNamedLine into the LineNameMap class (idempotent patch). r=dholbert (efb12c594b) - Bug 1118820 part 2c+2d - [css-grid] Modify the LineNameMap::FindLine/RFindLine/FindNamedLine methods to take line names associated with 'repeat(auto-fill/auto-fit)' tracks into account. Instantiate and pass around a LineNameMap object instead of an array of line name arrays. r=dholbert (a3db750297) - Bug 1118820 part 3a - [css-grid] Modify TrackSizingFunctions to take a dynamic number of 'repeat(auto-fill/auto-fit)' tracks taking into account. r=dholbert (9aa6033332) - Bug 1118820 part 3b - [css-grid] Implement the CalculateRepeatFillCount method that calculates the number of 'repeat(auto-fill/auto-fit)' tracks to use for the given sizes. r=dholbert (cf75fab8a8) - Bug 1118820 part 4 - [css-grid] Provide the sizes to use for CalculateRepeatFillCount. r=dholbert (8184c00dba) - Bug 1118820 part 5 - [css-grid] Remove any empty 'repeat(auto-fit)' tracks at the end of its range and adjust affected grid area line numbers accordingly. r=dholbert (c02ba6a6e3) - Bug 1229165 - [css-grid] Reftests for min/max-width/height properties on the grid container. (725097f878) - Bug 1229999 - [css-grid] Reftest. (51b5bc9535) - Bug 1237151 (part 3) - Remove ignored qualifiers in all remaining code. r=froydnj. (69917ebbad) - more bits of Bug 1178892 - Split the profiler into Core & Gecko files (41bb127b9c) - Bug 1199841 - Restructure private browsing to remember status after OnStopRequest r=jdm (16c2c1044d) - Bug 1233845 - Report an interception error and cancel the HTTP channel when encountering a known topcrash situation. r=ehsan (5d08075110) - Bug 664163 - Fix Get(Local|Remote)(Address|Port) in HttpChannelChild. r=jduell (cbf70af4e8) - Bug 1229177 - Show the tracking protection shield for fetch and XHR requests. r=jduell (5833b3e872) - Bug 1220678 Don't crash when DivertToParent() is called on an intercepted channel. r=jdm (5d7ff6ecc8) - Bug 1220681 P1 Make HttpChannelChild::DivertToParent() work with synthetic responses. r=jdm (67715703ef) - Bug 1169819 Add browser chrome test to validate SW force refresh. r=ehsan (c0b6b3e874) - Bug 1220681 P2 Test synthetic responses that trigger downloads. r=ehsan (c701f3ddb1) - Bug 1220681 P3 Delay diversion on parent side until response head has been synthesized. r=jdm (7c697aacee) - Bug 1220681 P4 Automatically suspend the parent channel after synthesizing the response for diverison. r=jdm (27f31bcb35) - Bug 1220681 P5 Don't double suspend parent channel during synthesized divert to parent. r=jdm (62081d4b56) - Bug 1220681 P6 Use clients.claim() in browser_download.js to avoid worker unregister race. r=jdm (c8de291727) - Bug 1240161 - Remove "only-if-cached" from RequestCache; r=bkelly (283486f584) - Bug 1184550 - Add a mochitest for the Request constructor that tests that the body is set to used after being fetched and then fails on the second fetch with the same Request. r=bkelly (db4a967203) - Bug 1205495 - Correctly use the requests's body and redirect mode in reroute.js; r=nsm (a36a96624a) - Bug 1189656 - Fix fetch-request-fallback test paths. r=bkelly (366c884179) - Bug 1219085 - Import the fetch-request-redirect.https.html test from Blink; r=jdm (bf6b484d82) - Bug 1209081 - Part 1: Implement the "navigate" value for RequestMode; r=bkelly (a22f19d94b) - Bug 1209081 - Part 2: Upgrade the saved Requests in the DOM Cache to reflect the "navigate" RequestMode if they represent navigation content policy types; r=bkelly (60d1da23bb) - Bug 1219469 - Part 1: Revert the error reporting added in bug 1233845; r=jdm (dcc022b9d3) - Bug 1219469 - Part 2: Make HttpChannelParentListener be the controller; r=jdm,jduell (9c5f0dfbe0) - Bug 1229369 - Intercept redirected network fetches that have their request mode set to manual; r=jdm (fb21d86ed2)
1086 lines
29 KiB
C++
1086 lines
29 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "GMPParent.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsIInputStream.h"
|
|
#include "nsILineInputStream.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsCharSeparatedTokenizer.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsIRunnable.h"
|
|
#include "nsIWritablePropertyBag2.h"
|
|
#include "mozIGeckoMediaPluginService.h"
|
|
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
|
#include "mozilla/SyncRunnable.h"
|
|
#include "mozilla/unused.h"
|
|
#include "nsIObserverService.h"
|
|
#include "GMPTimerParent.h"
|
|
#include "runnable_utils.h"
|
|
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
|
#include "mozilla/SandboxInfo.h"
|
|
#endif
|
|
#include "GMPContentParent.h"
|
|
|
|
#include "mozilla/dom/CrashReporterParent.h"
|
|
using mozilla::dom::CrashReporterParent;
|
|
using mozilla::ipc::GeckoChildProcessHost;
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
#include "nsPrintfCString.h"
|
|
using CrashReporter::AnnotationTable;
|
|
using CrashReporter::GetIDFromMinidump;
|
|
#endif
|
|
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
namespace mozilla {
|
|
|
|
#undef LOG
|
|
#undef LOGD
|
|
|
|
extern LogModule* GetGMPLog();
|
|
#define LOG(level, x, ...) MOZ_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
|
|
#define LOGD(x, ...) LOG(mozilla::LogLevel::Debug, "GMPParent[%p|childPid=%d] " x, this, mChildPid, ##__VA_ARGS__)
|
|
|
|
#ifdef __CLASS__
|
|
#undef __CLASS__
|
|
#endif
|
|
#define __CLASS__ "GMPParent"
|
|
|
|
namespace gmp {
|
|
|
|
GMPParent::GMPParent()
|
|
: mState(GMPStateNotLoaded)
|
|
, mProcess(nullptr)
|
|
, mDeleteProcessOnlyOnUnload(false)
|
|
, mAbnormalShutdownInProgress(false)
|
|
, mIsBlockingDeletion(false)
|
|
, mCanDecrypt(false)
|
|
, mGMPContentChildCount(0)
|
|
, mAsyncShutdownRequired(false)
|
|
, mAsyncShutdownInProgress(false)
|
|
, mChildPid(0)
|
|
, mHoldingSelfRef(false)
|
|
{
|
|
LOGD("GMPParent ctor");
|
|
mPluginId = GeckoChildProcessHost::GetUniqueID();
|
|
}
|
|
|
|
GMPParent::~GMPParent()
|
|
{
|
|
LOGD("GMPParent dtor");
|
|
|
|
MOZ_ASSERT(!mProcess);
|
|
}
|
|
|
|
nsresult
|
|
GMPParent::CloneFrom(const GMPParent* aOther)
|
|
{
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
MOZ_ASSERT(aOther->mDirectory && aOther->mService, "null plugin directory");
|
|
return Init(aOther->mService, aOther->mDirectory);
|
|
}
|
|
|
|
nsresult
|
|
GMPParent::Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir)
|
|
{
|
|
MOZ_ASSERT(aPluginDir);
|
|
MOZ_ASSERT(aService);
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
|
|
mService = aService;
|
|
mDirectory = aPluginDir;
|
|
|
|
// aPluginDir is <profile-dir>/<gmp-plugin-id>/<version>
|
|
// where <gmp-plugin-id> should be gmp-gmpopenh264
|
|
nsCOMPtr<nsIFile> parent;
|
|
nsresult rv = aPluginDir->GetParent(getter_AddRefs(parent));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
nsAutoString parentLeafName;
|
|
rv = parent->GetLeafName(parentLeafName);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
LOGD("%s: for %s", __FUNCTION__, NS_LossyConvertUTF16toASCII(parentLeafName).get());
|
|
|
|
MOZ_ASSERT(parentLeafName.Length() > 4);
|
|
mName = Substring(parentLeafName, 4);
|
|
|
|
return ReadGMPMetaData();
|
|
}
|
|
|
|
void
|
|
GMPParent::Crash()
|
|
{
|
|
if (mState != GMPStateNotLoaded) {
|
|
Unused << SendCrashPluginNow();
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
GMPParent::LoadProcess()
|
|
{
|
|
MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
MOZ_ASSERT(mState == GMPStateNotLoaded);
|
|
|
|
nsAutoString path;
|
|
if (NS_FAILED(mDirectory->GetPath(path))) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
LOGD("%s: for %s", __FUNCTION__, NS_ConvertUTF16toUTF8(path).get());
|
|
|
|
if (!mProcess) {
|
|
mProcess = new GMPProcessParent(NS_ConvertUTF16toUTF8(path).get());
|
|
if (!mProcess->Launch(30 * 1000)) {
|
|
LOGD("%s: Failed to launch new child process", __FUNCTION__);
|
|
mProcess->Delete();
|
|
mProcess = nullptr;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
mChildPid = base::GetProcId(mProcess->GetChildProcessHandle());
|
|
LOGD("%s: Launched new child process", __FUNCTION__);
|
|
|
|
bool opened = Open(mProcess->GetChannel(),
|
|
base::GetProcId(mProcess->GetChildProcessHandle()));
|
|
if (!opened) {
|
|
LOGD("%s: Failed to open channel to new child process", __FUNCTION__);
|
|
mProcess->Delete();
|
|
mProcess = nullptr;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
LOGD("%s: Opened channel to new child process", __FUNCTION__);
|
|
|
|
bool ok = SendSetNodeId(mNodeId);
|
|
if (!ok) {
|
|
LOGD("%s: Failed to send node id to child process", __FUNCTION__);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
LOGD("%s: Sent node id to child process", __FUNCTION__);
|
|
|
|
// Intr call to block initialization on plugin load.
|
|
ok = CallStartPlugin();
|
|
if (!ok) {
|
|
LOGD("%s: Failed to send start to child process", __FUNCTION__);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
LOGD("%s: Sent StartPlugin to child process", __FUNCTION__);
|
|
}
|
|
|
|
mState = GMPStateLoaded;
|
|
|
|
// Hold a self ref while the child process is alive. This ensures that
|
|
// during shutdown the GMPParent stays alive long enough to
|
|
// terminate the child process.
|
|
MOZ_ASSERT(!mHoldingSelfRef);
|
|
mHoldingSelfRef = true;
|
|
AddRef();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
void
|
|
GMPParent::AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
|
|
{
|
|
NS_WARNING("Timed out waiting for GMP async shutdown!");
|
|
GMPParent* parent = reinterpret_cast<GMPParent*>(aClosure);
|
|
MOZ_ASSERT(parent->mService);
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
parent->mService->SetAsyncShutdownPluginState(parent, 'G',
|
|
NS_LITERAL_CSTRING("Timed out waiting for async shutdown"));
|
|
#endif
|
|
parent->mService->AsyncShutdownComplete(parent);
|
|
}
|
|
|
|
nsresult
|
|
GMPParent::EnsureAsyncShutdownTimeoutSet()
|
|
{
|
|
MOZ_ASSERT(mAsyncShutdownRequired);
|
|
if (mAsyncShutdownTimeout) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult rv;
|
|
mAsyncShutdownTimeout = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
// Set timer to abort waiting for plugin to shutdown if it takes
|
|
// too long.
|
|
rv = mAsyncShutdownTimeout->SetTarget(mGMPThread);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
int32_t timeout = GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT;
|
|
RefPtr<GeckoMediaPluginServiceParent> service =
|
|
GeckoMediaPluginServiceParent::GetSingleton();
|
|
if (service) {
|
|
timeout = service->AsyncShutdownTimeoutMs();
|
|
}
|
|
rv = mAsyncShutdownTimeout->InitWithFuncCallback(
|
|
&AbortWaitingForGMPAsyncShutdown, this, timeout,
|
|
nsITimer::TYPE_ONE_SHOT);
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
return rv;
|
|
}
|
|
|
|
bool
|
|
GMPParent::RecvPGMPContentChildDestroyed()
|
|
{
|
|
--mGMPContentChildCount;
|
|
if (!IsUsed()) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'E',
|
|
NS_LITERAL_CSTRING("Last content child destroyed"));
|
|
}
|
|
#endif
|
|
CloseIfUnused();
|
|
}
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
else {
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'F',
|
|
nsPrintfCString("Content child destroyed, remaining: %u", mGMPContentChildCount));
|
|
}
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void
|
|
GMPParent::CloseIfUnused()
|
|
{
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
LOGD("%s: mAsyncShutdownRequired=%d", __FUNCTION__, mAsyncShutdownRequired);
|
|
|
|
if ((mDeleteProcessOnlyOnUnload ||
|
|
mState == GMPStateLoaded ||
|
|
mState == GMPStateUnloading) &&
|
|
!IsUsed()) {
|
|
// Ensure all timers are killed.
|
|
for (uint32_t i = mTimers.Length(); i > 0; i--) {
|
|
mTimers[i - 1]->Shutdown();
|
|
}
|
|
|
|
if (mAsyncShutdownRequired) {
|
|
if (!mAsyncShutdownInProgress) {
|
|
LOGD("%s: sending async shutdown notification", __FUNCTION__);
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'H',
|
|
NS_LITERAL_CSTRING("Sent BeginAsyncShutdown"));
|
|
}
|
|
#endif
|
|
mAsyncShutdownInProgress = true;
|
|
if (!SendBeginAsyncShutdown()) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'I',
|
|
NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting async shutdown"));
|
|
}
|
|
#endif
|
|
AbortAsyncShutdown();
|
|
} else if (NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'J',
|
|
NS_LITERAL_CSTRING("Could not start timer after sending BeginAsyncShutdown - Aborting async shutdown"));
|
|
}
|
|
#endif
|
|
AbortAsyncShutdown();
|
|
}
|
|
}
|
|
} else {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'K',
|
|
NS_LITERAL_CSTRING("No (more) async-shutdown required"));
|
|
}
|
|
#endif
|
|
// No async-shutdown, kill async-shutdown timer started in CloseActive().
|
|
AbortAsyncShutdown();
|
|
// Any async shutdown must be complete. Shutdown GMPStorage.
|
|
for (size_t i = mStorage.Length(); i > 0; i--) {
|
|
mStorage[i - 1]->Shutdown();
|
|
}
|
|
Shutdown();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GMPParent::AbortAsyncShutdown()
|
|
{
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
LOGD("%s", __FUNCTION__);
|
|
|
|
if (mAsyncShutdownTimeout) {
|
|
mAsyncShutdownTimeout->Cancel();
|
|
mAsyncShutdownTimeout = nullptr;
|
|
}
|
|
|
|
if (!mAsyncShutdownRequired || !mAsyncShutdownInProgress) {
|
|
return;
|
|
}
|
|
|
|
RefPtr<GMPParent> kungFuDeathGrip(this);
|
|
mService->AsyncShutdownComplete(this);
|
|
mAsyncShutdownRequired = false;
|
|
mAsyncShutdownInProgress = false;
|
|
CloseIfUnused();
|
|
}
|
|
|
|
void
|
|
GMPParent::CloseActive(bool aDieWhenUnloaded)
|
|
{
|
|
LOGD("%s: state %d", __FUNCTION__, mState);
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
|
|
if (aDieWhenUnloaded) {
|
|
mDeleteProcessOnlyOnUnload = true; // don't allow this to go back...
|
|
}
|
|
if (mState == GMPStateLoaded) {
|
|
mState = GMPStateUnloading;
|
|
}
|
|
if (mState != GMPStateNotLoaded && IsUsed()) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'A',
|
|
nsPrintfCString("Sent CloseActive, content children to close: %u", mGMPContentChildCount));
|
|
}
|
|
#endif
|
|
if (!SendCloseActive()) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'B',
|
|
NS_LITERAL_CSTRING("Could not send CloseActive - Aborting async shutdown"));
|
|
}
|
|
#endif
|
|
AbortAsyncShutdown();
|
|
} else if (IsUsed()) {
|
|
// We're expecting RecvPGMPContentChildDestroyed's -> Start async-shutdown timer now if needed.
|
|
if (mAsyncShutdownRequired && NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'C',
|
|
NS_LITERAL_CSTRING("Could not start timer after sending CloseActive - Aborting async shutdown"));
|
|
}
|
|
#endif
|
|
AbortAsyncShutdown();
|
|
}
|
|
} else {
|
|
// We're not expecting any RecvPGMPContentChildDestroyed
|
|
// -> Call CloseIfUnused() now, to run async shutdown if necessary.
|
|
// Note that CloseIfUnused() may have already been called from a prior
|
|
// RecvPGMPContentChildDestroyed(), however depending on the state at
|
|
// that time, it might not have proceeded with shutdown; And calling it
|
|
// again after shutdown is fine because after the first one we'll be in
|
|
// GMPStateNotLoaded.
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'D',
|
|
NS_LITERAL_CSTRING("Content children already destroyed"));
|
|
}
|
|
#endif
|
|
CloseIfUnused();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GMPParent::MarkForDeletion()
|
|
{
|
|
mDeleteProcessOnlyOnUnload = true;
|
|
mIsBlockingDeletion = true;
|
|
}
|
|
|
|
bool
|
|
GMPParent::IsMarkedForDeletion()
|
|
{
|
|
return mIsBlockingDeletion;
|
|
}
|
|
|
|
void
|
|
GMPParent::Shutdown()
|
|
{
|
|
LOGD("%s", __FUNCTION__);
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
|
|
MOZ_ASSERT(!mAsyncShutdownTimeout, "Should have canceled shutdown timeout");
|
|
|
|
if (mAbnormalShutdownInProgress) {
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(!IsUsed());
|
|
if (mState == GMPStateNotLoaded || mState == GMPStateClosing) {
|
|
return;
|
|
}
|
|
|
|
RefPtr<GMPParent> self(this);
|
|
DeleteProcess();
|
|
|
|
// XXX Get rid of mDeleteProcessOnlyOnUnload and this code when
|
|
// Bug 1043671 is fixed
|
|
if (!mDeleteProcessOnlyOnUnload) {
|
|
// Destroy ourselves and rise from the fire to save memory
|
|
mService->ReAddOnGMPThread(self);
|
|
} // else we've been asked to die and stay dead
|
|
MOZ_ASSERT(mState == GMPStateNotLoaded);
|
|
}
|
|
|
|
class NotifyGMPShutdownTask : public nsRunnable {
|
|
public:
|
|
explicit NotifyGMPShutdownTask(const nsAString& aNodeId)
|
|
: mNodeId(aNodeId)
|
|
{
|
|
}
|
|
NS_IMETHOD Run() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
|
|
MOZ_ASSERT(obsService);
|
|
if (obsService) {
|
|
obsService->NotifyObservers(nullptr, "gmp-shutdown", mNodeId.get());
|
|
}
|
|
return NS_OK;
|
|
}
|
|
nsString mNodeId;
|
|
};
|
|
|
|
void
|
|
GMPParent::ChildTerminated()
|
|
{
|
|
RefPtr<GMPParent> self(this);
|
|
nsIThread* gmpThread = GMPThread();
|
|
|
|
if (!gmpThread) {
|
|
// Bug 1163239 - this can happen on shutdown.
|
|
// PluginTerminated removes the GMP from the GMPService.
|
|
// On shutdown we can have this case where it is already been
|
|
// removed so there is no harm in not trying to remove it again.
|
|
LOGD("%s::%s: GMPThread() returned nullptr.", __CLASS__, __FUNCTION__);
|
|
} else {
|
|
gmpThread->Dispatch(NS_NewRunnableMethodWithArg<RefPtr<GMPParent>>(
|
|
mService,
|
|
&GeckoMediaPluginServiceParent::PluginTerminated,
|
|
self),
|
|
NS_DISPATCH_NORMAL);
|
|
}
|
|
}
|
|
|
|
void
|
|
GMPParent::DeleteProcess()
|
|
{
|
|
LOGD("%s", __FUNCTION__);
|
|
|
|
if (mState != GMPStateClosing) {
|
|
// Don't Close() twice!
|
|
// Probably remove when bug 1043671 is resolved
|
|
mState = GMPStateClosing;
|
|
Close();
|
|
}
|
|
mProcess->Delete(NS_NewRunnableMethod(this, &GMPParent::ChildTerminated));
|
|
LOGD("%s: Shut down process", __FUNCTION__);
|
|
mProcess = nullptr;
|
|
mState = GMPStateNotLoaded;
|
|
|
|
NS_DispatchToMainThread(
|
|
new NotifyGMPShutdownTask(NS_ConvertUTF8toUTF16(mNodeId)),
|
|
NS_DISPATCH_NORMAL);
|
|
|
|
if (mHoldingSelfRef) {
|
|
Release();
|
|
mHoldingSelfRef = false;
|
|
}
|
|
}
|
|
|
|
GMPState
|
|
GMPParent::State() const
|
|
{
|
|
return mState;
|
|
}
|
|
|
|
// Not changing to use mService since we'll be removing it
|
|
nsIThread*
|
|
GMPParent::GMPThread()
|
|
{
|
|
if (!mGMPThread) {
|
|
nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
|
MOZ_ASSERT(mps);
|
|
if (!mps) {
|
|
return nullptr;
|
|
}
|
|
// Not really safe if we just grab to the mGMPThread, as we don't know
|
|
// what thread we're running on and other threads may be trying to
|
|
// access this without locks! However, debug only, and primary failure
|
|
// mode outside of compiler-helped TSAN is a leak. But better would be
|
|
// to use swap() under a lock.
|
|
mps->GetThread(getter_AddRefs(mGMPThread));
|
|
MOZ_ASSERT(mGMPThread);
|
|
}
|
|
|
|
return mGMPThread;
|
|
}
|
|
|
|
bool
|
|
GMPParent::SupportsAPI(const nsCString& aAPI, const nsCString& aTag)
|
|
{
|
|
for (uint32_t i = 0; i < mCapabilities.Length(); i++) {
|
|
if (!mCapabilities[i]->mAPIName.Equals(aAPI)) {
|
|
continue;
|
|
}
|
|
nsTArray<nsCString>& tags = mCapabilities[i]->mAPITags;
|
|
for (uint32_t j = 0; j < tags.Length(); j++) {
|
|
if (tags[j].Equals(aTag)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
GMPParent::EnsureProcessLoaded()
|
|
{
|
|
if (mState == GMPStateLoaded) {
|
|
return true;
|
|
}
|
|
if (mState == GMPStateClosing ||
|
|
mState == GMPStateUnloading) {
|
|
return false;
|
|
}
|
|
|
|
nsresult rv = LoadProcess();
|
|
|
|
return NS_SUCCEEDED(rv);
|
|
}
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
void
|
|
GMPParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
|
|
{
|
|
notes.Put(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1"));
|
|
notes.Put(NS_LITERAL_CSTRING("PluginFilename"),
|
|
NS_ConvertUTF16toUTF8(mName));
|
|
notes.Put(NS_LITERAL_CSTRING("PluginName"), mDisplayName);
|
|
notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mVersion);
|
|
}
|
|
|
|
void
|
|
GMPParent::GetCrashID(nsString& aResult)
|
|
{
|
|
CrashReporterParent* cr =
|
|
static_cast<CrashReporterParent*>(LoneManagedOrNullAsserts(ManagedPCrashReporterParent()));
|
|
if (NS_WARN_IF(!cr)) {
|
|
return;
|
|
}
|
|
|
|
AnnotationTable notes(4);
|
|
WriteExtraDataForMinidump(notes);
|
|
nsCOMPtr<nsIFile> dumpFile;
|
|
TakeMinidump(getter_AddRefs(dumpFile), nullptr);
|
|
if (!dumpFile) {
|
|
NS_WARNING("GMP crash without crash report");
|
|
aResult = mName;
|
|
aResult += '-';
|
|
AppendUTF8toUTF16(mVersion, aResult);
|
|
return;
|
|
}
|
|
GetIDFromMinidump(dumpFile, aResult);
|
|
cr->GenerateCrashReportForMinidump(dumpFile, ¬es);
|
|
}
|
|
|
|
static void
|
|
GMPNotifyObservers(const uint32_t aPluginID, const nsACString& aPluginName, const nsAString& aPluginDumpID)
|
|
{
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
nsCOMPtr<nsIWritablePropertyBag2> propbag =
|
|
do_CreateInstance("@mozilla.org/hash-property-bag;1");
|
|
if (obs && propbag) {
|
|
propbag->SetPropertyAsUint32(NS_LITERAL_STRING("pluginID"), aPluginID);
|
|
propbag->SetPropertyAsACString(NS_LITERAL_STRING("pluginName"), aPluginName);
|
|
propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"), aPluginDumpID);
|
|
obs->NotifyObservers(propbag, "gmp-plugin-crash", nullptr);
|
|
}
|
|
|
|
RefPtr<gmp::GeckoMediaPluginService> service =
|
|
gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
|
|
if (service) {
|
|
service->RunPluginCrashCallbacks(aPluginID, aPluginName);
|
|
}
|
|
}
|
|
#endif
|
|
void
|
|
GMPParent::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
LOGD("%s: (%d)", __FUNCTION__, (int)aWhy);
|
|
#ifdef MOZ_CRASHREPORTER
|
|
if (AbnormalShutdown == aWhy) {
|
|
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
|
|
NS_LITERAL_CSTRING("gmplugin"), 1);
|
|
nsString dumpID;
|
|
GetCrashID(dumpID);
|
|
|
|
// NotifyObservers is mainthread-only
|
|
NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers,
|
|
mPluginId, mDisplayName, dumpID),
|
|
NS_DISPATCH_NORMAL);
|
|
}
|
|
#endif
|
|
// warn us off trying to close again
|
|
mState = GMPStateClosing;
|
|
mAbnormalShutdownInProgress = true;
|
|
CloseActive(false);
|
|
|
|
// Normal Shutdown() will delete the process on unwind.
|
|
if (AbnormalShutdown == aWhy) {
|
|
RefPtr<GMPParent> self(this);
|
|
if (mAsyncShutdownRequired) {
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'M',
|
|
NS_LITERAL_CSTRING("Actor destroyed"));
|
|
}
|
|
#endif
|
|
mService->AsyncShutdownComplete(this);
|
|
mAsyncShutdownRequired = false;
|
|
}
|
|
// Must not call Close() again in DeleteProcess(), as we'll recurse
|
|
// infinitely if we do.
|
|
MOZ_ASSERT(mState == GMPStateClosing);
|
|
DeleteProcess();
|
|
// Note: final destruction will be Dispatched to ourself
|
|
mService->ReAddOnGMPThread(self);
|
|
}
|
|
}
|
|
|
|
mozilla::dom::PCrashReporterParent*
|
|
GMPParent::AllocPCrashReporterParent(const NativeThreadId& aThread)
|
|
{
|
|
#ifndef MOZ_CRASHREPORTER
|
|
MOZ_ASSERT(false, "Should only be sent if crash reporting is enabled.");
|
|
#endif
|
|
CrashReporterParent* cr = new CrashReporterParent();
|
|
cr->SetChildData(aThread, GeckoProcessType_GMPlugin);
|
|
return cr;
|
|
}
|
|
|
|
bool
|
|
GMPParent::DeallocPCrashReporterParent(PCrashReporterParent* aCrashReporter)
|
|
{
|
|
delete aCrashReporter;
|
|
return true;
|
|
}
|
|
|
|
PGMPStorageParent*
|
|
GMPParent::AllocPGMPStorageParent()
|
|
{
|
|
GMPStorageParent* p = new GMPStorageParent(mNodeId, this);
|
|
mStorage.AppendElement(p); // Addrefs, released in DeallocPGMPStorageParent.
|
|
return p;
|
|
}
|
|
|
|
bool
|
|
GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor)
|
|
{
|
|
GMPStorageParent* p = static_cast<GMPStorageParent*>(aActor);
|
|
p->Shutdown();
|
|
mStorage.RemoveElement(p);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* aActor)
|
|
{
|
|
GMPStorageParent* p = (GMPStorageParent*)aActor;
|
|
if (NS_WARN_IF(NS_FAILED(p->Init()))) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
PGMPTimerParent*
|
|
GMPParent::AllocPGMPTimerParent()
|
|
{
|
|
GMPTimerParent* p = new GMPTimerParent(GMPThread());
|
|
mTimers.AppendElement(p); // Released in DeallocPGMPTimerParent, or on shutdown.
|
|
return p;
|
|
}
|
|
|
|
bool
|
|
GMPParent::DeallocPGMPTimerParent(PGMPTimerParent* aActor)
|
|
{
|
|
GMPTimerParent* p = static_cast<GMPTimerParent*>(aActor);
|
|
p->Shutdown();
|
|
mTimers.RemoveElement(p);
|
|
return true;
|
|
}
|
|
|
|
nsresult
|
|
ParseNextRecord(nsILineInputStream* aLineInputStream,
|
|
const nsCString& aPrefix,
|
|
nsCString& aResult,
|
|
bool& aMoreLines)
|
|
{
|
|
nsAutoCString record;
|
|
nsresult rv = aLineInputStream->ReadLine(record, &aMoreLines);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
if (record.Length() <= aPrefix.Length() ||
|
|
!Substring(record, 0, aPrefix.Length()).Equals(aPrefix)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
aResult = Substring(record, aPrefix.Length());
|
|
aResult.Trim("\b\t\r\n ");
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GMPParent::ReadGMPMetaData()
|
|
{
|
|
MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
|
|
MOZ_ASSERT(!mName.IsEmpty(), "Plugin mName cannot be empty!");
|
|
|
|
nsCOMPtr<nsIFile> infoFile;
|
|
nsresult rv = mDirectory->Clone(getter_AddRefs(infoFile));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
infoFile->AppendRelativePath(mName + NS_LITERAL_STRING(".info"));
|
|
|
|
nsCOMPtr<nsIInputStream> inputStream;
|
|
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), infoFile);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(inputStream, &rv);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
nsCString value;
|
|
bool moreLines = false;
|
|
|
|
// 'Name:' record
|
|
nsCString prefix = NS_LITERAL_CSTRING("Name:");
|
|
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
if (value.IsEmpty()) {
|
|
// Not OK for name to be empty. Must have one non-whitespace character.
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
mDisplayName = value;
|
|
|
|
// 'Description:' record
|
|
if (!moreLines) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
prefix = NS_LITERAL_CSTRING("Description:");
|
|
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
mDescription = value;
|
|
|
|
// 'Version:' record
|
|
if (!moreLines) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
prefix = NS_LITERAL_CSTRING("Version:");
|
|
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
mVersion = value;
|
|
|
|
// 'Capability:' record
|
|
if (!moreLines) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
prefix = NS_LITERAL_CSTRING("APIs:");
|
|
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
nsCCharSeparatedTokenizer apiTokens(value, ',');
|
|
while (apiTokens.hasMoreTokens()) {
|
|
nsAutoCString api(apiTokens.nextToken());
|
|
api.StripWhitespace();
|
|
if (api.IsEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
int32_t tagsStart = api.FindChar('[');
|
|
if (tagsStart == 0) {
|
|
// Not allowed to be the first character.
|
|
// API name must be at least one character.
|
|
continue;
|
|
}
|
|
|
|
auto cap = new GMPCapability();
|
|
if (tagsStart == -1) {
|
|
// No tags.
|
|
cap->mAPIName.Assign(api);
|
|
} else {
|
|
auto tagsEnd = api.FindChar(']');
|
|
if (tagsEnd == -1 || tagsEnd < tagsStart) {
|
|
// Invalid syntax, skip whole capability.
|
|
delete cap;
|
|
continue;
|
|
}
|
|
|
|
cap->mAPIName.Assign(Substring(api, 0, tagsStart));
|
|
|
|
if ((tagsEnd - tagsStart) > 1) {
|
|
const nsDependentCSubstring ts(Substring(api, tagsStart + 1, tagsEnd - tagsStart - 1));
|
|
nsCCharSeparatedTokenizer tagTokens(ts, ':');
|
|
while (tagTokens.hasMoreTokens()) {
|
|
const nsDependentCSubstring tag(tagTokens.nextToken());
|
|
cap->mAPITags.AppendElement(tag);
|
|
}
|
|
}
|
|
}
|
|
|
|
// We support the current GMPDecryptor version, and the previous.
|
|
// We Adapt the previous to the current in the GMPContentChild.
|
|
if (cap->mAPIName.EqualsLiteral(GMP_API_DECRYPTOR_BACKWARDS_COMPAT)) {
|
|
cap->mAPIName.AssignLiteral(GMP_API_DECRYPTOR);
|
|
}
|
|
|
|
if (cap->mAPIName.EqualsLiteral(GMP_API_DECRYPTOR)) {
|
|
mCanDecrypt = true;
|
|
|
|
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
|
if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
|
|
printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
|
|
" but this system can't sandbox it; not loading.\n",
|
|
mDisplayName.get());
|
|
delete cap;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
mCapabilities.AppendElement(cap);
|
|
}
|
|
|
|
if (mCapabilities.IsEmpty()) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
GMPParent::CanBeSharedCrossNodeIds() const
|
|
{
|
|
return !mAsyncShutdownInProgress &&
|
|
mNodeId.IsEmpty() &&
|
|
// XXX bug 1159300 hack -- maybe remove after openh264 1.4
|
|
// We don't want to use CDM decoders for non-encrypted playback
|
|
// just yet; especially not for WebRTC. Don't allow CDMs to be used
|
|
// without a node ID.
|
|
!mCanDecrypt;
|
|
}
|
|
|
|
bool
|
|
GMPParent::CanBeUsedFrom(const nsACString& aNodeId) const
|
|
{
|
|
return !mAsyncShutdownInProgress &&
|
|
((mNodeId.IsEmpty() && State() == GMPStateNotLoaded) ||
|
|
mNodeId == aNodeId);
|
|
}
|
|
|
|
void
|
|
GMPParent::SetNodeId(const nsACString& aNodeId)
|
|
{
|
|
MOZ_ASSERT(!aNodeId.IsEmpty());
|
|
MOZ_ASSERT(CanBeUsedFrom(aNodeId));
|
|
mNodeId = aNodeId;
|
|
}
|
|
|
|
const nsCString&
|
|
GMPParent::GetDisplayName() const
|
|
{
|
|
return mDisplayName;
|
|
}
|
|
|
|
const nsCString&
|
|
GMPParent::GetVersion() const
|
|
{
|
|
return mVersion;
|
|
}
|
|
|
|
uint32_t
|
|
GMPParent::GetPluginId() const
|
|
{
|
|
return mPluginId;
|
|
}
|
|
|
|
bool
|
|
GMPParent::RecvAsyncShutdownRequired()
|
|
{
|
|
LOGD("%s", __FUNCTION__);
|
|
if (mAsyncShutdownRequired) {
|
|
NS_WARNING("Received AsyncShutdownRequired message more than once!");
|
|
return true;
|
|
}
|
|
mAsyncShutdownRequired = true;
|
|
mService->AsyncShutdownNeeded(this);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
GMPParent::RecvAsyncShutdownComplete()
|
|
{
|
|
LOGD("%s", __FUNCTION__);
|
|
|
|
MOZ_ASSERT(mAsyncShutdownRequired);
|
|
#if defined(MOZ_CRASHREPORTER)
|
|
if (mService) {
|
|
mService->SetAsyncShutdownPluginState(this, 'L',
|
|
NS_LITERAL_CSTRING("Received AsyncShutdownComplete"));
|
|
}
|
|
#endif
|
|
AbortAsyncShutdown();
|
|
return true;
|
|
}
|
|
|
|
class RunCreateContentParentCallbacks : public nsRunnable
|
|
{
|
|
public:
|
|
explicit RunCreateContentParentCallbacks(GMPContentParent* aGMPContentParent)
|
|
: mGMPContentParent(aGMPContentParent)
|
|
{
|
|
}
|
|
|
|
void TakeCallbacks(nsTArray<UniquePtr<GetGMPContentParentCallback>>& aCallbacks)
|
|
{
|
|
mCallbacks.SwapElements(aCallbacks);
|
|
}
|
|
|
|
NS_IMETHOD
|
|
Run()
|
|
{
|
|
for (uint32_t i = 0, length = mCallbacks.Length(); i < length; ++i) {
|
|
mCallbacks[i]->Done(mGMPContentParent);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
RefPtr<GMPContentParent> mGMPContentParent;
|
|
nsTArray<UniquePtr<GetGMPContentParentCallback>> mCallbacks;
|
|
};
|
|
|
|
PGMPContentParent*
|
|
GMPParent::AllocPGMPContentParent(Transport* aTransport, ProcessId aOtherPid)
|
|
{
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
MOZ_ASSERT(!mGMPContentParent);
|
|
|
|
mGMPContentParent = new GMPContentParent(this);
|
|
mGMPContentParent->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(),
|
|
ipc::ParentSide);
|
|
|
|
RefPtr<RunCreateContentParentCallbacks> runCallbacks =
|
|
new RunCreateContentParentCallbacks(mGMPContentParent);
|
|
runCallbacks->TakeCallbacks(mCallbacks);
|
|
NS_DispatchToCurrentThread(runCallbacks);
|
|
MOZ_ASSERT(mCallbacks.IsEmpty());
|
|
|
|
return mGMPContentParent;
|
|
}
|
|
|
|
bool
|
|
GMPParent::GetGMPContentParent(UniquePtr<GetGMPContentParentCallback>&& aCallback)
|
|
{
|
|
LOGD("%s %p", __FUNCTION__, this);
|
|
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
|
|
|
if (mGMPContentParent) {
|
|
aCallback->Done(mGMPContentParent);
|
|
} else {
|
|
mCallbacks.AppendElement(Move(aCallback));
|
|
// If we don't have a GMPContentParent and we try to get one for the first
|
|
// time (mCallbacks.Length() == 1) then call PGMPContent::Open. If more
|
|
// calls to GetGMPContentParent happen before mGMPContentParent has been
|
|
// set then we should just store them, so that they get called when we set
|
|
// mGMPContentParent as a result of the PGMPContent::Open call.
|
|
if (mCallbacks.Length() == 1) {
|
|
if (!EnsureProcessLoaded() || !PGMPContent::Open(this)) {
|
|
return false;
|
|
}
|
|
// We want to increment this as soon as possible, to avoid that we'd try
|
|
// to shut down the GMP process while we're still trying to get a
|
|
// PGMPContentParent actor.
|
|
++mGMPContentChildCount;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
already_AddRefed<GMPContentParent>
|
|
GMPParent::ForgetGMPContentParent()
|
|
{
|
|
MOZ_ASSERT(mCallbacks.IsEmpty());
|
|
return Move(mGMPContentParent.forget());
|
|
}
|
|
|
|
bool
|
|
GMPParent::EnsureProcessLoaded(base::ProcessId* aID)
|
|
{
|
|
if (!EnsureProcessLoaded()) {
|
|
return false;
|
|
}
|
|
*aID = OtherPid();
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
GMPParent::Bridge(GMPServiceParent* aGMPServiceParent)
|
|
{
|
|
if (NS_FAILED(PGMPContent::Bridge(aGMPServiceParent, this))) {
|
|
return false;
|
|
}
|
|
++mGMPContentChildCount;
|
|
return true;
|
|
}
|
|
|
|
nsString
|
|
GMPParent::GetPluginBaseName() const
|
|
{
|
|
return NS_LITERAL_STRING("gmp-") + mName;
|
|
}
|
|
|
|
} // namespace gmp
|
|
} // namespace mozilla
|
|
|
|
#undef LOG
|
|
#undef LOGD
|