Bug 1352924 - Keep list of GMPServiceParents in GeckoMediaPluginServiceParent. r=gerald
This will allow us to broadcast a notification to the GMPServices running in
the content processes when they need to shutdown.
MozReview-Commit-ID: FviFDgNMnUV
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -88,17 +88,16 @@ NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPl
nsIAsyncShutdownBlocker)
GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
: mShuttingDown(false)
, mScannedPluginOnDisk(false)
, mWaitingForPluginsSyncShutdown(false)
, mInitPromiseMonitor("GeckoMediaPluginServiceParent::mInitPromiseMonitor")
, mLoadPluginsFromDiskComplete(false)
- , mServiceUserCount(0)
, mMainThread(SystemGroup::AbstractMainThreadFor(TaskCategory::Other))
{
MOZ_ASSERT(NS_IsMainThread());
mInitPromise.SetMonitor(&mInitPromiseMonitor);
}
GeckoMediaPluginServiceParent::~GeckoMediaPluginServiceParent()
{
@@ -1627,32 +1626,41 @@ GeckoMediaPluginServiceParent::GetState(
NS_IMETHODIMP
GeckoMediaPluginServiceParent::BlockShutdown(nsIAsyncShutdownClient*)
{
return NS_OK;
}
void
-GeckoMediaPluginServiceParent::ServiceUserCreated()
+GeckoMediaPluginServiceParent::ServiceUserCreated(
+ GMPServiceParent* aServiceParent)
{
- MOZ_ASSERT(mServiceUserCount >= 0);
- if (++mServiceUserCount == 1) {
+ MOZ_ASSERT(NS_IsMainThread());
+ MutexAutoLock lock(mMutex);
+ MOZ_ASSERT(!mServiceParents.Contains(aServiceParent));
+ mServiceParents.AppendElement(aServiceParent);
+ if (mServiceParents.Length() == 1) {
nsresult rv = GetShutdownBarrier()->AddBlocker(
this, NS_LITERAL_STRING(__FILE__), __LINE__,
NS_LITERAL_STRING("GeckoMediaPluginServiceParent shutdown"));
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
}
void
-GeckoMediaPluginServiceParent::ServiceUserDestroyed()
+GeckoMediaPluginServiceParent::ServiceUserDestroyed(
+ GMPServiceParent* aServiceParent)
{
- MOZ_ASSERT(mServiceUserCount > 0);
- if (--mServiceUserCount == 0) {
+ MOZ_ASSERT(NS_IsMainThread());
+ MutexAutoLock lock(mMutex);
+ MOZ_ASSERT(mServiceParents.Length() > 0);
+ MOZ_ASSERT(mServiceParents.Contains(aServiceParent));
+ mServiceParents.RemoveElement(aServiceParent);
+ if (mServiceParents.IsEmpty()) {
nsresult rv = GetShutdownBarrier()->RemoveBlocker(this);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
}
void
GeckoMediaPluginServiceParent::ClearStorage()
{
@@ -1687,22 +1695,27 @@ GeckoMediaPluginServiceParent::GetById(u
for (const RefPtr<GMPParent>& gmp : mPlugins) {
if (gmp->GetPluginId() == aPluginId) {
return do_AddRef(gmp);
}
}
return nullptr;
}
+GMPServiceParent::GMPServiceParent(GeckoMediaPluginServiceParent* aService)
+ : mService(aService)
+{
+ MOZ_ASSERT(mService);
+ mService->ServiceUserCreated(this);
+}
+
GMPServiceParent::~GMPServiceParent()
{
- nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
- "GeckoMediaPluginServiceParent::ServiceUserDestroyed",
- mService.get(), &GeckoMediaPluginServiceParent::ServiceUserDestroyed);
- mService->MainThread()->Dispatch(task.forget());
+ MOZ_ASSERT(mService);
+ mService->ServiceUserDestroyed(this);
}
mozilla::ipc::IPCResult
GMPServiceParent::RecvLaunchGMP(const nsCString& aNodeId,
const nsCString& aAPI,
nsTArray<nsCString>&& aTags,
nsTArray<ProcessId>&& aAlreadyBridgedTo,
uint32_t* aOutPluginId,
@@ -1845,17 +1858,26 @@ GMPServiceParent::ActorDestroy(ActorDest
&monitor,
&completed);
XRE_GetIOMessageLoop()->PostTask(Move(task.forget()));
while (!completed) {
lock.Wait();
}
- NS_DispatchToCurrentThread(new DeleteGMPServiceParent(this));
+ // Dispatch a task to the current thread to ensure we don't delete the
+ // GMPServiceParent until the current calling context is finished with
+ // the object.
+ GMPServiceParent* self = this;
+ NS_DispatchToCurrentThread(NS_NewRunnableFunction([self]() {
+ // The GMPServiceParent must be destroyed on the main thread.
+ NS_DispatchToMainThread(NS_NewRunnableFunction([self]() {
+ delete self;
+ }));
+ }));
}
class OpenPGMPServiceParent : public mozilla::Runnable
{
public:
OpenPGMPServiceParent(GMPServiceParent* aGMPServiceParent,
ipc::Endpoint<PGMPServiceParent>&& aEndpoint,
bool* aResult)
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -18,16 +18,17 @@
#include "GMPStorage.h"
template <class> struct already_AddRefed;
namespace mozilla {
namespace gmp {
class GMPParent;
+class GMPServiceParent;
class GeckoMediaPluginServiceParent final : public GeckoMediaPluginService
, public mozIGeckoMediaPluginChromeService
, public nsIAsyncShutdownBlocker
{
public:
static already_AddRefed<GeckoMediaPluginServiceParent> GetSingleton();
@@ -55,18 +56,18 @@ public:
// GMP thread access only
bool IsShuttingDown();
already_AddRefed<GMPStorage> GetMemoryStorageFor(const nsACString& aNodeId);
nsresult ForgetThisSiteNative(const nsAString& aSite,
const mozilla::OriginAttributesPattern& aPattern);
// Notifies that some user of this class is created/destroyed.
- void ServiceUserCreated();
- void ServiceUserDestroyed();
+ void ServiceUserCreated(GMPServiceParent* aServiceParent);
+ void ServiceUserDestroyed(GMPServiceParent* aServiceParent);
void UpdateContentProcessGMPCapabilities();
AbstractThread* MainThread() const { return mMainThread; }
private:
friend class GMPServiceParent;
@@ -202,36 +203,33 @@ private:
// MOZ_GMP_PATH before allowing GetContentParentFrom() to proceed.
Monitor mInitPromiseMonitor;
MozPromiseHolder<GenericPromise> mInitPromise;
bool mLoadPluginsFromDiskComplete;
// Hashes nodeId to the hashtable of storage for that nodeId.
nsRefPtrHashtable<nsCStringHashKey, GMPStorage> mTempGMPStorage;
- // Tracks how many users are running (on the GMP thread). Only when this count
- // drops to 0 can we safely shut down the thread.
- MainThreadOnly<int32_t> mServiceUserCount;
+ // Tracks how many IPC connections to GMPServices running in content
+ // processes we have. When this is empty we can safely shut down.
+ // Synchronized across thread via mMutex in base class.
+ nsTArray<GMPServiceParent*> mServiceParents;
const RefPtr<AbstractThread> mMainThread;
};
nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData);
bool MatchOrigin(nsIFile* aPath,
const nsACString& aSite,
const mozilla::OriginAttributesPattern& aPattern);
class GMPServiceParent final : public PGMPServiceParent
{
public:
- explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService)
- : mService(aService)
- {
- mService->ServiceUserCreated();
- }
+ explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService);
virtual ~GMPServiceParent();
ipc::IPCResult RecvGetGMPNodeId(const nsString& aOrigin,
const nsString& aTopLevelOrigin,
const nsString& aGMPName,
nsCString* aID) override;
void ActorDestroy(ActorDestroyReason aWhy) override;