Bug 1352924 - Block creation of new GMPs once parent process begins shutdown. r=gerald
This ensures that when we've started shutdown we don't try to start up new
GMPs. Doing so would create more connections from the content process to the
main process, and the main process can't shutdown until all such connections
are shut down.
MozReview-Commit-ID: KE8nCoLXjdd
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -288,16 +288,23 @@ GeckoMediaPluginServiceChild::UpdateGMPC
// requests waiting on a CDM to download will retry.
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
MOZ_ASSERT(obsService);
if (obsService) {
obsService->NotifyObservers(nullptr, "gmp-changed", nullptr);
}
}
+void
+GeckoMediaPluginServiceChild::BeginShutdown()
+{
+ MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+ mShuttingDownOnGMPThread = true;
+}
+
NS_IMETHODIMP
GeckoMediaPluginServiceChild::HasPluginForAPI(const nsACString& aAPI,
nsTArray<nsCString>* aTags,
bool* aHasPlugin)
{
StaticMutexAutoLock lock(sGMPCapabilitiesMutex);
if (!sGMPCapabilities) {
*aHasPlugin = false;
@@ -369,16 +376,23 @@ GeckoMediaPluginServiceChild::Observe(ns
}
RefPtr<GeckoMediaPluginServiceChild::GetServiceChildPromise>
GeckoMediaPluginServiceChild::GetServiceChild()
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
if (!mServiceChild) {
+ if (mShuttingDownOnGMPThread) {
+ // We have begun shutdown. Don't allow a new connection to the main
+ // process to be instantiated. This also prevents new plugins being
+ // instantiated.
+ return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ }
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
if (!contentChild) {
return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
MozPromiseHolder<GetServiceChildPromise>* holder = mGetServiceChildPromises.AppendElement();
RefPtr<GetServiceChildPromise> promise = holder->Ensure(__func__);
if (mGetServiceChildPromises.Length() == 1) {
nsCOMPtr<nsIRunnable> r = WrapRunnable(
@@ -510,10 +524,28 @@ GMPServiceChild::Create(Endpoint<PGMPSer
NS_ENSURE_SUCCESS(rv, false);
rv = gmpThread->Dispatch(new OpenPGMPServiceChild(Move(serviceChild),
Move(aGMPService)),
NS_DISPATCH_NORMAL);
return NS_SUCCEEDED(rv);
}
+ipc::IPCResult
+GMPServiceChild::RecvBeginShutdown()
+{
+ RefPtr<GeckoMediaPluginServiceChild> service =
+ GeckoMediaPluginServiceChild::GetSingleton();
+ MOZ_ASSERT(service && service->mServiceChild.get() == this);
+ if (service) {
+ service->BeginShutdown();
+ }
+ return IPC_OK();
+}
+
+bool
+GMPServiceChild::HaveContentParents() const
+{
+ return mContentParents.Count() > 0;
+}
+
} // namespace gmp
} // namespace mozilla
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -37,16 +37,18 @@ public:
NS_DECL_NSIOBSERVER
void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
static void UpdateGMPCapabilities(nsTArray<mozilla::dom::GMPCapabilityData>&& aCapabilities);
+ void BeginShutdown();
+
protected:
void InitializePlugins(AbstractThread*) override
{
// Nothing to do here.
}
virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
GMPCrashHelper* aHelper,
@@ -80,16 +82,20 @@ public:
ipc::Endpoint<PGMPContentParent>&& endpoint);
void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
void GetAlreadyBridgedTo(nsTArray<ProcessId>& aAlreadyBridgedTo);
static bool Create(Endpoint<PGMPServiceChild>&& aGMPService);
+ ipc::IPCResult RecvBeginShutdown() override;
+
+ bool HaveContentParents() const;
+
private:
nsRefPtrHashtable<nsUint64HashKey, GMPContentParent> mContentParents;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPServiceChild_h_
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -463,16 +463,20 @@ GeckoMediaPluginServiceParent::UnloadPlu
mShuttingDownOnGMPThread = true;
nsTArray<RefPtr<GMPParent>> plugins;
{
MutexAutoLock lock(mMutex);
// Move all plugins references to a local array. This way mMutex won't be
// locked when calling CloseActive (to avoid inter-locking).
Swap(plugins, mPlugins);
+
+ for (GMPServiceParent* parent : mServiceParents) {
+ Unused << parent->SendBeginShutdown();
+ }
}
LOGD(("%s::%s plugins:%" PRIuSIZE, __CLASS__, __FUNCTION__,
plugins.Length()));
#ifdef DEBUG
for (const auto& plugin : plugins) {
LOGD(("%s::%s plugin: '%s'", __CLASS__, __FUNCTION__,
plugin->GetDisplayName().get()));
--- a/dom/media/gmp/PGMPService.ipdl
+++ b/dom/media/gmp/PGMPService.ipdl
@@ -31,12 +31,14 @@ parent:
returns (uint32_t pluginId,
ProcessId id,
nsCString displayName,
Endpoint<PGMPContentParent> endpoint,
nsresult aResult);
sync GetGMPNodeId(nsString origin, nsString topLevelOrigin, nsString gmpName)
returns (nsCString id);
+child:
+ async BeginShutdown();
};
} // namespace gmp
} // namespace mozilla