mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	If SendChromiumCDMConstructor fails, then the diagnostic assert in ChromiumCDMDestroyed will fail because we have yet to add the ChromiumCDMParent to the array. Now in this patch we just add the parent right away, and rely upon the ActorDestroy machinery to remove it as in all other cases. Differential Revision: https://phabricator.services.mozilla.com/D188963
		
			
				
	
	
		
			223 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "GMPContentParent.h"
 | 
						|
#include "GMPLog.h"
 | 
						|
#include "GMPParent.h"
 | 
						|
#include "GMPServiceChild.h"
 | 
						|
#include "GMPVideoDecoderParent.h"
 | 
						|
#include "GMPVideoEncoderParent.h"
 | 
						|
#include "ChromiumCDMParent.h"
 | 
						|
#include "mozIGeckoMediaPluginService.h"
 | 
						|
#include "mozilla/Logging.h"
 | 
						|
#include "mozilla/Unused.h"
 | 
						|
#include "base/task.h"
 | 
						|
 | 
						|
namespace mozilla::gmp {
 | 
						|
 | 
						|
static const char* GetBoolString(bool aBool) {
 | 
						|
  return aBool ? "true" : "false";
 | 
						|
}
 | 
						|
 | 
						|
GMPContentParent::GMPContentParent(GMPParent* aParent)
 | 
						|
    : mParent(aParent), mPluginId(0) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::GMPContentParent(this=%p), aParent=%p", this,
 | 
						|
                aParent);
 | 
						|
  if (mParent) {
 | 
						|
    SetDisplayName(mParent->GetDisplayName());
 | 
						|
    SetPluginId(mParent->GetPluginId());
 | 
						|
    SetPluginType(mParent->GetPluginType());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
GMPContentParent::~GMPContentParent() {
 | 
						|
  GMP_LOG_DEBUG(
 | 
						|
      "GMPContentParent::~GMPContentParent(this=%p) mVideoDecoders.IsEmpty=%s, "
 | 
						|
      "mVideoEncoders.IsEmpty=%s, mChromiumCDMs.IsEmpty=%s, "
 | 
						|
      "mCloseBlockerCount=%" PRIu32,
 | 
						|
      this, GetBoolString(mVideoDecoders.IsEmpty()),
 | 
						|
      GetBoolString(mVideoEncoders.IsEmpty()),
 | 
						|
      GetBoolString(mChromiumCDMs.IsEmpty()), mCloseBlockerCount);
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::ActorDestroy(ActorDestroyReason aWhy) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::ActorDestroy(this=%p, aWhy=%d)", this,
 | 
						|
                static_cast<int>(aWhy));
 | 
						|
  MOZ_ASSERT(mVideoDecoders.IsEmpty() && mVideoEncoders.IsEmpty() &&
 | 
						|
             mChromiumCDMs.IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::CheckThread() {
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::ChromiumCDMDestroyed(ChromiumCDMParent* aCDM) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::ChromiumCDMDestroyed(this=%p, aCDM=%p)",
 | 
						|
                this, aCDM);
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
 | 
						|
  MOZ_ALWAYS_TRUE(mChromiumCDMs.RemoveElement(aCDM));
 | 
						|
  CloseIfUnused();
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::VideoDecoderDestroyed(this=%p, aDecoder=%p)",
 | 
						|
                this, aDecoder);
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
 | 
						|
  // If the constructor fails, we'll get called before it's added
 | 
						|
  Unused << NS_WARN_IF(!mVideoDecoders.RemoveElement(aDecoder));
 | 
						|
  CloseIfUnused();
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::VideoEncoderDestroyed(this=%p, aEncoder=%p)",
 | 
						|
                this, aEncoder);
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
 | 
						|
  // If the constructor fails, we'll get called before it's added
 | 
						|
  Unused << NS_WARN_IF(!mVideoEncoders.RemoveElement(aEncoder));
 | 
						|
  CloseIfUnused();
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::AddCloseBlocker() {
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
  ++mCloseBlockerCount;
 | 
						|
  GMP_LOG_DEBUG(
 | 
						|
      "GMPContentParent::AddCloseBlocker(this=%p) mCloseBlockerCount=%" PRIu32,
 | 
						|
      this, mCloseBlockerCount);
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::RemoveCloseBlocker() {
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
  --mCloseBlockerCount;
 | 
						|
  GMP_LOG_DEBUG(
 | 
						|
      "GMPContentParent::RemoveCloseBlocker(this=%p) "
 | 
						|
      "mCloseBlockerCount=%" PRIu32,
 | 
						|
      this, mCloseBlockerCount);
 | 
						|
  CloseIfUnused();
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParent::CloseIfUnused() {
 | 
						|
  MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
 | 
						|
  GMP_LOG_DEBUG(
 | 
						|
      "GMPContentParent::CloseIfUnused(this=%p) mVideoDecoders.IsEmpty=%s, "
 | 
						|
      "mVideoEncoders.IsEmpty=%s, mChromiumCDMs.IsEmpty=%s, "
 | 
						|
      "mCloseBlockerCount=%" PRIu32,
 | 
						|
      this, GetBoolString(mVideoDecoders.IsEmpty()),
 | 
						|
      GetBoolString(mVideoEncoders.IsEmpty()),
 | 
						|
      GetBoolString(mChromiumCDMs.IsEmpty()), mCloseBlockerCount);
 | 
						|
  if (mVideoDecoders.IsEmpty() && mVideoEncoders.IsEmpty() &&
 | 
						|
      mChromiumCDMs.IsEmpty() && mCloseBlockerCount == 0) {
 | 
						|
    RefPtr<GMPContentParent> toClose;
 | 
						|
    if (mParent) {
 | 
						|
      toClose = mParent->ForgetGMPContentParent();
 | 
						|
    } else {
 | 
						|
      toClose = this;
 | 
						|
      RefPtr<GeckoMediaPluginServiceChild> gmp(
 | 
						|
          GeckoMediaPluginServiceChild::GetSingleton());
 | 
						|
      if (gmp) {
 | 
						|
        gmp->RemoveGMPContentParent(toClose);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    NS_DispatchToCurrentThread(NewRunnableMethod(
 | 
						|
        "gmp::GMPContentParent::Close", toClose, &GMPContentParent::Close));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
nsCOMPtr<nsISerialEventTarget> GMPContentParent::GMPEventTarget() {
 | 
						|
  if (!mGMPEventTarget) {
 | 
						|
    GMP_LOG_DEBUG("GMPContentParent::GMPEventTarget(this=%p)", this);
 | 
						|
    nsCOMPtr<mozIGeckoMediaPluginService> mps =
 | 
						|
        do_GetService("@mozilla.org/gecko-media-plugin-service;1");
 | 
						|
    MOZ_ASSERT(mps);
 | 
						|
    if (!mps) {
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
    // Not really safe if we just grab to the mGMPEventTarget, as we don't know
 | 
						|
    // what thread we're running on and other threads may be trying to
 | 
						|
    // access this without locks!  However, debug only, and primary failure
 | 
						|
    // mode outside of compiler-helped TSAN is a leak.  But better would be
 | 
						|
    // to use swap() under a lock.
 | 
						|
    nsCOMPtr<nsIThread> gmpThread;
 | 
						|
    mps->GetThread(getter_AddRefs(gmpThread));
 | 
						|
    MOZ_ASSERT(gmpThread);
 | 
						|
 | 
						|
    mGMPEventTarget = gmpThread;
 | 
						|
  }
 | 
						|
 | 
						|
  return mGMPEventTarget;
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<ChromiumCDMParent> GMPContentParent::GetChromiumCDM(
 | 
						|
    const nsCString& aKeySystem) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::GetChromiumCDM(this=%p aKeySystem=%s)", this,
 | 
						|
                aKeySystem.get());
 | 
						|
 | 
						|
  RefPtr<ChromiumCDMParent> parent = new ChromiumCDMParent(this, GetPluginId());
 | 
						|
  // TODO: Remove parent from mChromiumCDMs in ChromiumCDMParent::Destroy().
 | 
						|
  mChromiumCDMs.AppendElement(parent);
 | 
						|
 | 
						|
  if (!SendPChromiumCDMConstructor(parent, aKeySystem)) {
 | 
						|
    MOZ_ASSERT(!mChromiumCDMs.Contains(parent));
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return parent.forget();
 | 
						|
}
 | 
						|
 | 
						|
nsresult GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::GetGMPVideoDecoder(this=%p)", this);
 | 
						|
 | 
						|
  RefPtr<GMPVideoDecoderParent> vdp = new GMPVideoDecoderParent(this);
 | 
						|
  if (!SendPGMPVideoDecoderConstructor(vdp)) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  // This addref corresponds to the Proxy pointer the consumer is returned.
 | 
						|
  // It's dropped by calling Close() on the interface.
 | 
						|
  vdp.get()->AddRef();
 | 
						|
  *aGMPVD = vdp;
 | 
						|
  mVideoDecoders.AppendElement(vdp);
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
nsresult GMPContentParent::GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE) {
 | 
						|
  GMP_LOG_DEBUG("GMPContentParent::GetGMPVideoEncoder(this=%p)", this);
 | 
						|
 | 
						|
  RefPtr<GMPVideoEncoderParent> vep = new GMPVideoEncoderParent(this);
 | 
						|
  if (!SendPGMPVideoEncoderConstructor(vep)) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  // This addref corresponds to the Proxy pointer the consumer is returned.
 | 
						|
  // It's dropped by calling Close() on the interface.
 | 
						|
  vep.get()->AddRef();
 | 
						|
  *aGMPVE = vep;
 | 
						|
  mVideoEncoders.AppendElement(vep);
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void GMPContentParentCloseBlocker::Destroy() {
 | 
						|
  MOZ_ASSERT(mParent);
 | 
						|
  MOZ_ASSERT(mEventTarget);
 | 
						|
 | 
						|
  if (!mEventTarget->IsOnCurrentThread()) {
 | 
						|
    mEventTarget->Dispatch(NS_NewRunnableFunction(
 | 
						|
        __func__, [parent = std::move(mParent), eventTarget = mEventTarget]() {
 | 
						|
          parent->RemoveCloseBlocker();
 | 
						|
        }));
 | 
						|
    mEventTarget = nullptr;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mParent->RemoveCloseBlocker();
 | 
						|
  mParent = nullptr;
 | 
						|
  mEventTarget = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla::gmp
 |