зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1279612 - Block xpcom-will-shutdown before GMPServiceParent instances are shut down. r=gerald
MozReview-Commit-ID: HdF1RDxVXv1 --HG-- extra : rebase_source : caf2279eb5aa57a74a035c45d81fcb4ee29ef42f
This commit is contained in:
Родитель
d220ab5953
Коммит
4cbbce3d03
|
@ -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,37 @@ 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);
|
||||
auto task = NewNonOwningRunnableMethod<Monitor*, bool*>(this,
|
||||
&GMPServiceParent::CloseTransport,
|
||||
&monitor,
|
||||
&completed);
|
||||
XRE_GetIOMessageLoop()->PostTask(Move(task));
|
||||
|
||||
while (!completed) {
|
||||
lock.Wait();
|
||||
}
|
||||
|
||||
NS_DispatchToCurrentThread(new DeleteGMPServiceParent(this));
|
||||
}
|
||||
|
||||
|
@ -2017,12 +2107,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,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче