Bug 1279612 - Block xpcom-will-shutdown before GMPServiceParent instances are shut down. r=gerald

MozReview-Commit-ID: HdF1RDxVXv1

--HG--
extra : rebase_source : f532fd60bd07ab91c6e089822258a0e3d7102a7b
This commit is contained in:
Cervantes Yu 2016-09-08 11:08:27 +08:00
parent dcfea2067d
commit a703779628
2 changed files with 112 additions and 2 deletions

View File

@ -44,6 +44,8 @@
#include <limits>
#include "MediaPrefs.h"
using mozilla::ipc::Transport;
namespace mozilla {
#ifdef LOG
@ -80,7 +82,8 @@ GeckoMediaPluginServiceParent::GetSingleton()
NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPluginServiceParent,
GeckoMediaPluginService,
mozIGeckoMediaPluginChromeService)
mozIGeckoMediaPluginChromeService,
nsIAsyncShutdownBlocker)
GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
: mShuttingDown(false)
@ -91,6 +94,7 @@ GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
, mWaitingForPluginsSyncShutdown(false)
, mInitPromiseMonitor("GeckoMediaPluginServiceParent::mInitPromiseMonitor")
, mLoadPluginsFromDiskComplete(false)
, mServiceUserCount(0)
{
MOZ_ASSERT(NS_IsMainThread());
mInitPromise.SetMonitor(&mInitPromiseMonitor);
@ -1838,6 +1842,61 @@ static bool IsNodeIdValid(GMPParent* aParent) {
return !aParent->GetNodeId().IsEmpty();
}
static nsCOMPtr<nsIAsyncShutdownClient>
GetShutdownBarrier()
{
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
MOZ_RELEASE_ASSERT(svc);
nsCOMPtr<nsIAsyncShutdownClient> barrier;
nsresult rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
MOZ_RELEASE_ASSERT(barrier);
return barrier.forget();
}
NS_IMETHODIMP
GeckoMediaPluginServiceParent::GetName(nsAString& aName)
{
aName = NS_LITERAL_STRING("GeckoMediaPluginServiceParent: shutdown");
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginServiceParent::GetState(nsIPropertyBag**)
{
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginServiceParent::BlockShutdown(nsIAsyncShutdownClient*)
{
return NS_OK;
}
void
GeckoMediaPluginServiceParent::ServiceUserCreated()
{
MOZ_ASSERT(mServiceUserCount >= 0);
if (++mServiceUserCount == 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()
{
MOZ_ASSERT(mServiceUserCount > 0);
if (--mServiceUserCount == 0) {
nsresult rv = GetShutdownBarrier()->RemoveBlocker(this);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
}
void
GeckoMediaPluginServiceParent::ClearStorage()
{
@ -1877,6 +1936,9 @@ GeckoMediaPluginServiceParent::GetById(uint32_t aPluginId)
GMPServiceParent::~GMPServiceParent()
{
NS_DispatchToMainThread(
NewRunnableMethod(mService.get(),
&GeckoMediaPluginServiceParent::ServiceUserDestroyed));
}
bool
@ -1976,9 +2038,38 @@ private:
nsAutoPtr<GMPServiceParent> mToDelete;
};
void GMPServiceParent::CloseTransport(Monitor* aSyncMonitor, bool* aCompleted)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MonitorAutoLock lock(*aSyncMonitor);
// This deletes the transport.
SetTransport(nullptr);
*aCompleted = true;
lock.NotifyAll();
}
void
GMPServiceParent::ActorDestroy(ActorDestroyReason aWhy)
{
Monitor monitor("DeleteGMPServiceParent");
bool completed = false;
// Make sure the IPC channel is closed before destroying mToDelete.
MonitorAutoLock lock(monitor);
RefPtr<Runnable> task =
NewNonOwningRunnableMethod<Monitor*, bool*>(this,
&GMPServiceParent::CloseTransport,
&monitor,
&completed);
XRE_GetIOMessageLoop()->PostTask(Move(task.forget()));
while (!completed) {
lock.Wait();
}
NS_DispatchToCurrentThread(new DeleteGMPServiceParent(this));
}
@ -2017,12 +2108,17 @@ GMPServiceParent::Create(Transport* aTransport, ProcessId aOtherPid)
RefPtr<GeckoMediaPluginServiceParent> gmp =
GeckoMediaPluginServiceParent::GetSingleton();
nsAutoPtr<GMPServiceParent> serviceParent(new GMPServiceParent(gmp));
if (gmp->mShuttingDown) {
// Shutdown is initiated. There is no point creating a new actor.
return nullptr;
}
nsCOMPtr<nsIThread> gmpThread;
nsresult rv = gmp->GetThread(getter_AddRefs(gmpThread));
NS_ENSURE_SUCCESS(rv, nullptr);
nsAutoPtr<GMPServiceParent> serviceParent(new GMPServiceParent(gmp));
bool ok;
rv = gmpThread->Dispatch(new OpenPGMPServiceParent(serviceParent,
aTransport,

View File

@ -12,6 +12,7 @@
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "mozilla/Atomics.h"
#include "nsIAsyncShutdown.h"
#include "nsThreadUtils.h"
#include "mozilla/MozPromise.h"
#include "GMPStorage.h"
@ -25,6 +26,7 @@ class GMPParent;
class GeckoMediaPluginServiceParent final : public GeckoMediaPluginService
, public mozIGeckoMediaPluginChromeService
, public nsIAsyncShutdownBlocker
{
public:
static already_AddRefed<GeckoMediaPluginServiceParent> GetSingleton();
@ -33,6 +35,7 @@ public:
nsresult Init() override;
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
// mozIGeckoMediaPluginService
NS_IMETHOD GetPluginVersionForAPI(const nsACString& aAPI,
@ -65,6 +68,10 @@ public:
nsresult ForgetThisSiteNative(const nsAString& aSite,
const mozilla::OriginAttributesPattern& aPattern);
// Notifies that some user of this class is created/destroyed.
void ServiceUserCreated();
void ServiceUserDestroyed();
private:
friend class GMPServiceParent;
@ -217,6 +224,10 @@ private:
// 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;
};
nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData);
@ -230,6 +241,7 @@ public:
explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService)
: mService(aService)
{
mService->ServiceUserCreated();
}
virtual ~GMPServiceParent();
@ -259,6 +271,8 @@ public:
nsresult* aOutRv) override;
private:
void CloseTransport(Monitor* aSyncMonitor, bool* aCompleted);
RefPtr<GeckoMediaPluginServiceParent> mService;
};