Bug 1746907: GMP cleanup r=bryce

Differential Revision: https://phabricator.services.mozilla.com/D134314
This commit is contained in:
Randell Jesup 2021-12-21 18:51:54 +00:00
Родитель 40c686eb47
Коммит b7ad07ceb9
4 изменённых файлов: 81 добавлений и 46 удалений

Просмотреть файл

@ -210,7 +210,7 @@ nsresult GeckoMediaPluginService::Init() {
RefPtr<GetCDMParentPromise> GeckoMediaPluginService::GetCDM(
const NodeIdParts& aNodeIdParts, const nsACString& aKeySystem,
GMPCrashHelper* aHelper) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
if (mShuttingDownOnGMPThread || aKeySystem.IsEmpty()) {
nsPrintfCString reason(
@ -269,7 +269,7 @@ RefPtr<GetCDMParentPromise> GeckoMediaPluginService::GetCDM(
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
RefPtr<GetGMPContentParentPromise>
GeckoMediaPluginService::GetContentParentForTest() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
nsTArray<nsCString> tags;
tags.AppendElement("fake"_ns);
@ -376,6 +376,15 @@ GeckoMediaPluginService::GetThread(nsIThread** aThread) {
// This can be called from any thread.
MutexAutoLock lock(mMutex);
return GetThreadLocked(aThread);
}
// always call with getter_AddRefs, because it does
nsresult GeckoMediaPluginService::GetThreadLocked(nsIThread** aThread) {
MOZ_ASSERT(aThread);
mMutex.AssertCurrentThreadOwns();
if (!mGMPThread) {
// Don't allow the thread to be created after shutdown has started.
if (mGMPThreadShutdown) {
@ -411,7 +420,7 @@ GeckoMediaPluginService::GetGMPVideoDecoder(
GMPCrashHelper* aHelper, nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoDecoderCallback>&& aCallback) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);
@ -451,7 +460,7 @@ GeckoMediaPluginService::GetGMPVideoEncoder(
GMPCrashHelper* aHelper, nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);

Просмотреть файл

@ -61,6 +61,7 @@ class GeckoMediaPluginService : public mozIGeckoMediaPluginService,
// mozIGeckoMediaPluginService
NS_IMETHOD GetThread(nsIThread** aThread) override;
nsresult GetThreadLocked(nsIThread** aThread);
NS_IMETHOD GetGMPVideoDecoder(
GMPCrashHelper* aHelper, nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
@ -85,6 +86,13 @@ class GeckoMediaPluginService : public mozIGeckoMediaPluginService,
GeckoMediaPluginService();
virtual ~GeckoMediaPluginService();
void AssertOnGMPThread() {
#ifdef DEBUG
MutexAutoLock lock(mMutex);
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
#endif
}
virtual void InitializePlugins(nsISerialEventTarget* aGMPThread) = 0;
virtual RefPtr<GetGMPContentParentPromise> GetContentParent(

Просмотреть файл

@ -87,6 +87,7 @@ GeckoMediaPluginServiceChild::BlockShutdown(nsIAsyncShutdownClient*) {
mXPCOMWillShutdown = true;
MutexAutoLock lock(mMutex);
Unused << NS_WARN_IF(NS_FAILED(mGMPThread->Dispatch(
NewRunnableMethod("GeckoMediaPluginServiceChild::BeginShutdown", this,
&GeckoMediaPluginServiceChild::BeginShutdown))));
@ -102,7 +103,7 @@ RefPtr<GetGMPContentParentPromise>
GeckoMediaPluginServiceChild::GetContentParent(
GMPCrashHelper* aHelper, const NodeIdVariant& aNodeIdVariant,
const nsCString& aAPI, const nsTArray<nsCString>& aTags) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
MOZ_ASSERT(!mShuttingDownOnGMPThread,
"Should not be called if GMPThread is shutting down!");
@ -272,7 +273,7 @@ void GeckoMediaPluginServiceChild::UpdateGMPCapabilities(
}
void GeckoMediaPluginServiceChild::BeginShutdown() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: mServiceChild=%p,", __CLASS__, __FUNCTION__,
mServiceChild.get());
// It's possible this gets called twice if the parent sends us a message to
@ -307,7 +308,7 @@ NS_IMETHODIMP
GeckoMediaPluginServiceChild::GetNodeId(
const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
const nsAString& aGMPName, UniquePtr<GetNodeIdCallback>&& aCallback) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GetNodeIdCallback* rawCallback = aCallback.release();
nsCOMPtr<nsISerialEventTarget> thread(GetGMPThread());
@ -341,6 +342,7 @@ GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject, const char* aTopic,
GMP_LOG_DEBUG("%s::%s: aTopic=%s", __CLASS__, __FUNCTION__, aTopic);
if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
if (mServiceChild) {
MutexAutoLock lock(mMutex);
mozilla::SyncRunnable::DispatchToThread(
mGMPThread,
WrapRunnable(mServiceChild.get(), &PGMPServiceChild::Close));
@ -354,7 +356,7 @@ GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject, const char* aTopic,
RefPtr<GeckoMediaPluginServiceChild::GetServiceChildPromise>
GeckoMediaPluginServiceChild::GetServiceChild() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
if (!mServiceChild) {
if (mShuttingDownOnGMPThread) {
@ -385,7 +387,7 @@ GeckoMediaPluginServiceChild::GetServiceChild() {
void GeckoMediaPluginServiceChild::SetServiceChild(
RefPtr<GMPServiceChild>&& aServiceChild) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
MOZ_ASSERT(!mServiceChild, "Should not already have service child!");
GMP_LOG_DEBUG("%s::%s: aServiceChild=%p", __CLASS__, __FUNCTION__,
aServiceChild.get());
@ -401,7 +403,7 @@ void GeckoMediaPluginServiceChild::SetServiceChild(
void GeckoMediaPluginServiceChild::RemoveGMPContentParent(
GMPContentParent* aGMPContentParent) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG(
"%s::%s: aGMPContentParent=%p, mServiceChild=%p, "
"mShuttingDownOnGMPThread=%s",
@ -436,27 +438,31 @@ nsresult GeckoMediaPluginServiceChild::AddShutdownBlocker() {
}
void GeckoMediaPluginServiceChild::RemoveShutdownBlocker() {
MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
AssertOnGMPThread();
MOZ_ASSERT(mShuttingDownOnGMPThread,
"We should only remove blockers once we're shutting down!");
"We should only remove blockers once we're "
"shutting down!");
GMP_LOG_DEBUG("%s::%s ", __CLASS__, __FUNCTION__);
nsresult rv = mMainThread->Dispatch(NS_NewRunnableFunction(
"GeckoMediaPluginServiceChild::RemoveShutdownBlocker",
"GeckoMediaPluginServiceChild::"
"RemoveShutdownBlocker",
[this, self = RefPtr<GeckoMediaPluginServiceChild>(this)]() {
nsresult rv = GetShutdownBarrier()->RemoveBlocker(this);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}));
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_ASSERT_UNREACHABLE(
"Main thread should always be alive when we call this!");
"Main thread should always be alive when we "
"call this!");
}
}
void GeckoMediaPluginServiceChild::RemoveShutdownBlockerIfNeeded() {
MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG(
"%s::%s mPendingGetContentParents=%" PRIu32
" mServiceChild->HaveContentParents()=%s mShuttingDownOnGMPThread=%s",
" mServiceChild->HaveContentParents()=%s "
"mShuttingDownOnGMPThread=%s",
__CLASS__, __FUNCTION__, mPendingGetContentParents,
mServiceChild && mServiceChild->HaveContentParents() ? "true" : "false",
mShuttingDownOnGMPThread ? "true" : "false");

Просмотреть файл

@ -259,11 +259,15 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject,
mWaitingForPluginsSyncShutdown = true;
nsCOMPtr<nsIThread> gmpThread;
DebugOnly<bool> plugins_empty;
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(!mShuttingDown);
mShuttingDown = true;
gmpThread = mGMPThread;
#ifdef DEBUG
plugins_empty = mPlugins.IsEmpty();
#endif
}
if (gmpThread) {
@ -283,12 +287,17 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject,
[&]() { return !mWaitingForPluginsSyncShutdown; });
} else {
// GMP thread has already shutdown.
MOZ_ASSERT(mPlugins.IsEmpty());
MOZ_ASSERT(plugins_empty);
mWaitingForPluginsSyncShutdown = false;
}
} else if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
MOZ_ASSERT(mShuttingDown);
#ifdef DEBUG
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(mShuttingDown);
}
#endif
ShutdownGMPThread();
} else if (!strcmp(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, aTopic)) {
mXPCOMWillShutdown = true;
@ -336,7 +345,7 @@ RefPtr<GetGMPContentParentPromise>
GeckoMediaPluginServiceParent::GetContentParent(
GMPCrashHelper* aHelper, const NodeIdVariant& aNodeIdVariant,
const nsCString& aAPI, const nsTArray<nsCString>& aTags) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
nsCOMPtr<nsISerialEventTarget> thread(GetGMPThread());
if (!thread) {
@ -416,12 +425,12 @@ void GeckoMediaPluginServiceParent::NotifySyncShutdownComplete() {
}
bool GeckoMediaPluginServiceParent::IsShuttingDown() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
return mShuttingDownOnGMPThread;
}
void GeckoMediaPluginServiceParent::UnloadPlugins() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
MOZ_ASSERT(!mShuttingDownOnGMPThread);
mShuttingDownOnGMPThread = true;
@ -435,16 +444,17 @@ void GeckoMediaPluginServiceParent::UnloadPlugins() {
for (GMPServiceParent* parent : mServiceParents) {
Unused << parent->SendBeginShutdown();
}
GMP_LOG_DEBUG("%s::%s plugins:%zu", __CLASS__, __FUNCTION__,
plugins.Length());
#ifdef DEBUG
for (const auto& plugin : plugins) {
GMP_LOG_DEBUG("%s::%s plugin: '%s'", __CLASS__, __FUNCTION__,
plugin->GetDisplayName().get());
}
#endif
}
GMP_LOG_DEBUG("%s::%s plugins:%zu", __CLASS__, __FUNCTION__,
plugins.Length());
#ifdef DEBUG
for (const auto& plugin : plugins) {
GMP_LOG_DEBUG("%s::%s plugin: '%s'", __CLASS__, __FUNCTION__,
plugin->GetDisplayName().get());
}
#endif
// Note: CloseActive may be async; it could actually finish
// shutting down when all the plugins have unloaded.
for (const auto& plugin : plugins) {
@ -459,7 +469,7 @@ void GeckoMediaPluginServiceParent::UnloadPlugins() {
void GeckoMediaPluginServiceParent::CrashPlugins() {
GMP_LOG_DEBUG("%s::%s", __CLASS__, __FUNCTION__);
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
MutexAutoLock lock(mMutex);
for (size_t i = 0; i < mPlugins.Length(); i++) {
@ -468,7 +478,7 @@ void GeckoMediaPluginServiceParent::CrashPlugins() {
}
RefPtr<GenericPromise> GeckoMediaPluginServiceParent::LoadFromEnvironment() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
nsCOMPtr<nsISerialEventTarget> thread(GetGMPThread());
if (!thread) {
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
@ -715,8 +725,7 @@ already_AddRefed<GMPParent> GeckoMediaPluginServiceParent::FindPluginForAPIFrom(
already_AddRefed<GMPParent> GeckoMediaPluginServiceParent::SelectPluginForAPI(
const nsACString& aNodeId, const nsCString& aAPI,
const nsTArray<nsCString>& aTags) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread(),
"Can't clone GMP plugins on non-GMP threads.");
AssertOnGMPThread();
GMPParent* gmpToClone = nullptr;
{
@ -782,7 +791,7 @@ static already_AddRefed<GMPParent> CreateGMPParent() {
already_AddRefed<GMPParent> GeckoMediaPluginServiceParent::ClonePlugin(
const GMPParent* aOriginal) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
MOZ_ASSERT(aOriginal);
RefPtr<GMPParent> gmp = CreateGMPParent();
@ -805,7 +814,7 @@ RefPtr<GenericPromise> GeckoMediaPluginServiceParent::AddOnGMPThread(
std::replace(aDirectory.BeginWriting(), aDirectory.EndWriting(), '/', '\\');
#endif
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
nsCString dir = NS_ConvertUTF16toUTF8(aDirectory);
nsCOMPtr<nsISerialEventTarget> thread(GetGMPThread());
if (!thread) {
@ -853,7 +862,7 @@ RefPtr<GenericPromise> GeckoMediaPluginServiceParent::AddOnGMPThread(
void GeckoMediaPluginServiceParent::RemoveOnGMPThread(
const nsAString& aDirectory, const bool aDeleteFromDisk,
const bool aCanDefer) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: %s", __CLASS__, __FUNCTION__,
NS_LossyConvertUTF16toASCII(aDirectory).get());
@ -927,7 +936,7 @@ static void Dummy(RefPtr<GMPParent> aOnDeathsDoor) {
void GeckoMediaPluginServiceParent::PluginTerminated(
const RefPtr<GMPParent>& aPlugin) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
if (aPlugin->IsMarkedForDeletion()) {
nsString path;
@ -942,7 +951,7 @@ void GeckoMediaPluginServiceParent::PluginTerminated(
void GeckoMediaPluginServiceParent::ReAddOnGMPThread(
const RefPtr<GMPParent>& aOld) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: %p", __CLASS__, __FUNCTION__, (void*)aOld);
RefPtr<GMPParent> gmp;
@ -1052,7 +1061,7 @@ already_AddRefed<GMPStorage> GeckoMediaPluginServiceParent::GetMemoryStorageFor(
NS_IMETHODIMP
GeckoMediaPluginServiceParent::IsPersistentStorageAllowed(
const nsACString& aNodeId, bool* aOutAllowed) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
NS_ENSURE_ARG(aOutAllowed);
// We disallow persistent storage for the NodeId used for shared GMP
// decoding, to prevent GMP decoding being used to track what a user
@ -1065,7 +1074,7 @@ GeckoMediaPluginServiceParent::IsPersistentStorageAllowed(
nsresult GeckoMediaPluginServiceParent::GetNodeId(
const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
const nsAString& aGMPName, nsACString& aOutId) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: (%s, %s)", __CLASS__, __FUNCTION__,
NS_ConvertUTF16toUTF8(aOrigin).get(),
NS_ConvertUTF16toUTF8(aTopLevelOrigin).get());
@ -1416,7 +1425,7 @@ void GeckoMediaPluginServiceParent::ClearNodeIdAndPlugin(
void GeckoMediaPluginServiceParent::ForgetThisSiteOnGMPThread(
const nsACString& aSite, const mozilla::OriginAttributesPattern& aPattern) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: origin=%s", __CLASS__, __FUNCTION__, aSite.Data());
struct OriginFilter : public DirectoryFilter {
@ -1437,7 +1446,7 @@ void GeckoMediaPluginServiceParent::ForgetThisSiteOnGMPThread(
void GeckoMediaPluginServiceParent::ForgetThisBaseDomainOnGMPThread(
const nsACString& aBaseDomain) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: baseDomain=%s", __CLASS__, __FUNCTION__,
aBaseDomain.Data());
@ -1457,7 +1466,7 @@ void GeckoMediaPluginServiceParent::ForgetThisBaseDomainOnGMPThread(
void GeckoMediaPluginServiceParent::ClearRecentHistoryOnGMPThread(
PRTime aSince) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s: since=%" PRId64, __CLASS__, __FUNCTION__,
(int64_t)aSince);
@ -1582,10 +1591,12 @@ GeckoMediaPluginServiceParent::BlockShutdown(nsIAsyncShutdownClient*) {
return NS_OK;
}
// Called from GMPServiceParent::Create() which holds the lock
void GeckoMediaPluginServiceParent::ServiceUserCreated(
GMPServiceParent* aServiceParent) {
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
mMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(!mServiceParents.Contains(aServiceParent));
mServiceParents.AppendElement(aServiceParent);
if (mServiceParents.Length() == 1) {
@ -1610,7 +1621,7 @@ void GeckoMediaPluginServiceParent::ServiceUserDestroyed(
}
void GeckoMediaPluginServiceParent::ClearStorage() {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
AssertOnGMPThread();
GMP_LOG_DEBUG("%s::%s", __CLASS__, __FUNCTION__);
// Kill plugins with valid nodeIDs.
@ -1762,13 +1773,14 @@ bool GMPServiceParent::Create(Endpoint<PGMPServiceParent>&& aGMPService) {
RefPtr<GeckoMediaPluginServiceParent> gmp =
GeckoMediaPluginServiceParent::GetSingleton();
MutexAutoLock lock(gmp->mMutex);
if (gmp->mShuttingDown) {
// Shutdown is initiated. There is no point creating a new actor.
return false;
}
nsCOMPtr<nsIThread> gmpThread;
nsresult rv = gmp->GetThread(getter_AddRefs(gmpThread));
nsresult rv = gmp->GetThreadLocked(getter_AddRefs(gmpThread));
NS_ENSURE_SUCCESS(rv, false);
RefPtr<GMPServiceParent> serviceParent(new GMPServiceParent(gmp));