Files
palemoon27/dom/media/gtest/TestGMPRemoveAndDelete.cpp
T
roytam1 f632bc6ab3 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1267186 - Split lookup of WebIDL DOM class names from lookup of DOMCI DOM class names. r=bz. (1cb4c3698e)
- Bug 1206637: P1. Add MediaPrefs convenience class. r=cpearce (d352b9ca0b)
- Bug 1254378 - Make new 'speech-synth-started' component service category. r=smaug (ece851540b)
- Bug 1206637: P2. Replace all cached preferences with MediaPrefs ones. r=cpearce (1492083f62)
- Bug 1216407 - Use mozilla/Endian.h for NfcService. r=yoshi (b2a508186d)
- Bug 1237493 - [NFC] Separate Gecko and Gonk layers for accessing Androids properties. r=yoshi (062e468bed)
- Bug 1272135, part 1 - Fix leading tab usage in ipc/chromium. r=billm (cf29df6977)
- Bug 1272135, part 2 - Delete two weird modelines in ipc/chromium. r=billm (da4cdafc7c)
- Bug 1272135, part 3 - Fix mode lines in ipc/chromium/. r=billm (040b11738e)
- Bug 1273307 - Remove copy constructor/assignment operator for Message/Pickle (r=froydnj) (b53e6d3470)
- Bug 1262671 - Remove unused TrimWriteData (r=froydnj) (8fbcefde63)
- Bug 1267438 - Group ScrollMetadata's optional clip rect and mask layer index into a LayerClip structure. r=mstange (dcd01e3bce)
- Bug 1267438 - Use IntersectMaybeRects() in Layer::GetCombinedClipRect(). r=mstange (5ec2d68aac)
- Bug 1262937 - part 1 - don't include the protocol name in Clone error messages; r=jld (3e23610fb1)
- Bug 1191452 - Limit IPDL-generated Move()s to Recv methods. r=billm (991cc733b6)
- Bug 1262937 - part 2 - don't include the message name when complaining about handler failure; r=jld (b8abbc5c8b)
- Bug 1262937 - part 3 - move quoting out of checkedRead; r=jld (16d36ae02a)
- Bug 1262937 - part 4 - publically inherit from MessageListener in IProtocol; r=jld (b89aaa7347)
- Bug 1262937 - part 5 - factor out actor reading code to a common base class; r=jld (702388bce7)
- Bug 1262937 - part 7 - factor out union type deserialization errors; r=jld (dcdf428efc)
- Bug 1262937 - part 6 - enable custom error message for ipdl.py's checkedRead; r=jld (5cf11d5d24)
- Bug 1262937 - part 8 - factor out array length deserialization errors; r=jld (d1149cc120)
- Bug 1271601: If a child process fails to duplicate a TransportDescriptor pipe handle then send it anyway and get the target to duplicate. r=gabor (d578cd0c85)
- Bug 1270247 - Crash in ParamTraits<mozilla::net::NetAddr>::Write if the family is unknown. r=hurley (3ed49495c0)
- Bug 1267474 - cache-control: immutable tests 3/3 r=mayhemer (ba0bc6e71a)
- bug 1188100 - fold PSM's test_client_cert.js into necko's test_tls_server.js r=mcmanus (a2b93abbbb)
- Bug 669259 - Expose original header received from a peer. r=mcmanus (cf53cad7ac)
- Bug 386743 - Set default event bubbling/cancelable flags in the WidgetEvent constructor. r=smaug (1c68cfffd2)
- Bug 1259661 part.1 Rename WidgetMouseEvent::reasonType to WidgetMouseEvent::Reason r=smaug (0edd107b56)
- Bug 1259661 part.2 Rename WidgetMouseEvent::context to WidgetMouseEvent::ContextMenuTrigger r=smaug (0049757099)
- Bug 1259661 part.3 Rename WidgetMouseEvent::exitType to WidgetMouseEvent::ExitFrom r=smaug (5ffd3f41b1)
- Bug 1259661 part.4 Rename WidgetMouseEvent::reason to WidgetMouseEvent::mReason r=smaug (5605ce8fd0)
- Bug 1259661 part.5 Rename WidgetMouseEvent::context to WidgetMouseEvent::mContextMenuTrigger r=smaug (4dd92f0066)
- Bug 1259661 part.6 Rename WidgetMouseEvent::exit to WidgetMouseEvent::mExitFrom r=smaug (c46f5fe1bc)
- Bug 1259661 part.7 Get rid of WidgetMouseEvent::acceptActivation because of unused r=smaug (4867aaf1a7)
- Bug 1259661 part.8 Rename WidgetMouseEvent::ignoreRootScrollFrame to WidgetMouseEvent::mIgnoreRootScrollFrame r=smaug (c829c446fd)
- Bug 1259661 part.9 Rename WidgetMouseEvent::clickCount to WidgetMouseEvent::mClickCount r=smaug (2fa015c006)
- Bug 1259661 part.10 Clean up some nits of WidgetMouseEvent definition r=smaug (58d3a0cb2c)
- Bug 1179346 - Add strings and accesskeys for Microsoft Edge. r=mak (b97f5e7ab4)
- Bug 931445 part 1 - Remove unused code from pointerlock_utils.js. r=smaug (e1b9c15569)
- Bug 931445 part 2 - Use util code from fullscreen tests to improve robustness of pointerlock tests. r=smaug (3c7b47751e)
- Bug 931445 part 3 - Reset synth centering pointer when unlocking pointer. r=smaug (e272fec9c7)
- Bug 1263389 NativeKey should initialize WidgetKeyboardEvent::mKeyValue of WM_KEYDOWN of VK_PACKET with following char message r=m_kato (e56a31bd4b)
- Bug 1261880 NativeKey should decide printable KeyboardEvent.key value of keydown and keypress events with following WM_CHAR message of WM_KEYDOWN r=m_kato (7208001852)
- Bug 1254755 part.1 Rename WidgetKeyboardEvent::keyCode to WidgetKeyboardEvent::mKeyCode r=smaug (97ebefa314)
- put back some XP/2003 code, as well as crash/debug (73b3147e58)
- Bug 1259679 - Space key shouldn't work as a space key if it's assigned to a function key. r=masayuki (db422c248b)
- Bug 1101975, handle access keys in content process before menus, r=masayuki (760213b62e)
- Bug 1254755 part.2 Rename WidgetKeyboardEvent::charCode to WidgetKeyboardEvent::mCharCode r=smaug (6cef6114a5)
- Bug 1254755 part.3 Rename WidgetKeyboardEvent::alternativeCharCodes to WidgetKeyboardEvent::mAlternativeCharCodes r=smaug (9d23a113fd)
- Bug 1254755 part.4 Rename WidgetKeyboardEvent::location to WidgetKeyboardEvent::mLocation r=smaug (f44e0212a6)
- Bug 1254755 part.5 Rename WidgetKeyboardEvent::isChar to WidgetKeyboardEvent::mIsChar r=smaug (a713d9903c)
- Bug 1254755 part.6 Reorder the members of WidgetKeyboardEvent for reducing its instance size r=smaug (39a14a7d4f)
- Bug 1262671 - void** -> PickleIterator (r=froydnj) (716a88b499)
2024-10-08 21:42:19 +08:00

491 lines
13 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "GMPService.h"
#include "GMPTestMonitor.h"
#include "gmp-api/gmp-video-host.h"
#include "gtest/gtest.h"
#include "mozilla/Services.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIObserverService.h"
#include "GMPVideoDecoderProxy.h"
#include "GMPServiceParent.h"
#include "GMPService.h"
#include "GMPUtils.h"
#include "mozilla/StaticPtr.h"
#include "MediaPrefs.h"
#define GMP_DIR_NAME NS_LITERAL_STRING("gmp-fakeopenh264")
#define GMP_OLD_VERSION NS_LITERAL_STRING("1.0")
#define GMP_NEW_VERSION NS_LITERAL_STRING("1.1")
#define GMP_DELETED_TOPIC "gmp-directory-deleted"
#define EXPECT_OK(X) EXPECT_TRUE(NS_SUCCEEDED(X))
using namespace mozilla;
using namespace mozilla::gmp;
class GMPRemoveTest : public nsIObserver
, public GMPVideoDecoderCallbackProxy
{
public:
GMPRemoveTest();
NS_DECL_THREADSAFE_ISUPPORTS
// Called when a GMP plugin directory has been successfully deleted.
// |aData| will contain the directory path.
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override;
// Create a new GMP plugin directory that we can trash and add it to the GMP
// service. Remove the original plugin directory. Original plugin directory
// gets re-added at destruction.
void Setup();
bool CreateVideoDecoder(nsCString aNodeId = EmptyCString());
void CloseVideoDecoder();
void DeletePluginDirectory(bool aCanDefer);
// Decode a dummy frame.
GMPErr Decode();
// Wait until TestMonitor has been signaled.
void Wait();
// Did we get a Terminated() callback from the plugin?
bool IsTerminated();
// From GMPVideoDecoderCallbackProxy
// Set mDecodeResult; unblock TestMonitor.
virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) override;
virtual void Error(GMPErr aError) override;
// From GMPVideoDecoderCallbackProxy
// We expect this to be called when a plugin has been forcibly closed.
virtual void Terminated() override;
// Ignored GMPVideoDecoderCallbackProxy members
virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) override {}
virtual void ReceivedDecodedFrame(const uint64_t aPictureId) override {}
virtual void InputDataExhausted() override {}
virtual void DrainComplete() override {}
virtual void ResetComplete() override {}
private:
virtual ~GMPRemoveTest();
void gmp_Decode();
void gmp_GetVideoDecoder(nsCString aNodeId,
GMPVideoDecoderProxy** aOutDecoder,
GMPVideoHost** aOutHost);
void GeneratePlugin();
GMPTestMonitor mTestMonitor;
nsCOMPtr<nsIThread> mGMPThread;
bool mIsTerminated;
// Path to the cloned GMP we have created.
nsString mTmpPath;
nsCOMPtr<nsIFile> mTmpDir;
// Path to the original GMP. Store so that we can re-add it after we're done
// testing.
nsString mOriginalPath;
GMPVideoDecoderProxy* mDecoder;
GMPVideoHost* mHost;
GMPErr mDecodeResult;
};
/*
* Simple test that the plugin is deleted when forcibly removed and deleted.
*/
TEST(GeckoMediaPlugins, RemoveAndDeleteForcedSimple)
{
RefPtr<GMPRemoveTest> test(new GMPRemoveTest());
test->Setup();
test->DeletePluginDirectory(false /* force immediate */);
test->Wait();
}
/*
* Simple test that the plugin is deleted when deferred deletion is allowed.
*/
TEST(GeckoMediaPlugins, RemoveAndDeleteDeferredSimple)
{
RefPtr<GMPRemoveTest> test(new GMPRemoveTest());
test->Setup();
test->DeletePluginDirectory(true /* can defer */);
test->Wait();
}
/*
* Test that the plugin is unavailable immediately after a forced
* RemoveAndDelete, and that the plugin is deleted afterwards.
*/
TEST(GeckoMediaPlugins, RemoveAndDeleteForcedInUse)
{
RefPtr<GMPRemoveTest> test(new GMPRemoveTest());
test->Setup();
EXPECT_TRUE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin")));
// Test that we can decode a frame.
GMPErr err = test->Decode();
EXPECT_EQ(err, GMPNoErr);
test->DeletePluginDirectory(false /* force immediate */);
test->Wait();
// Test that the VideoDecoder is no longer available.
EXPECT_FALSE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin")));
// Test that we were notified of the plugin's destruction.
EXPECT_TRUE(test->IsTerminated());
}
/*
* Test that the plugin is still usable after a deferred RemoveAndDelete, and
* that the plugin is deleted afterwards.
*/
TEST(GeckoMediaPlugins, RemoveAndDeleteDeferredInUse)
{
RefPtr<GMPRemoveTest> test(new GMPRemoveTest());
test->Setup();
EXPECT_TRUE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin")));
// Make sure decoding works before we do anything.
GMPErr err = test->Decode();
EXPECT_EQ(err, GMPNoErr);
test->DeletePluginDirectory(true /* can defer */);
// Test that decoding still works.
err = test->Decode();
EXPECT_EQ(err, GMPNoErr);
// Test that this origin is still able to fetch the video decoder.
EXPECT_TRUE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin")));
test->CloseVideoDecoder();
test->Wait();
}
static StaticRefPtr<GeckoMediaPluginService> gService;
static StaticRefPtr<GeckoMediaPluginServiceParent> gServiceParent;
static GeckoMediaPluginService*
GetService()
{
if (!gService) {
RefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
gService = service;
}
return gService.get();
}
static GeckoMediaPluginServiceParent*
GetServiceParent()
{
if (!gServiceParent) {
RefPtr<GeckoMediaPluginServiceParent> parent =
GeckoMediaPluginServiceParent::GetSingleton();
gServiceParent = parent;
}
return gServiceParent.get();
}
NS_IMPL_ISUPPORTS(GMPRemoveTest, nsIObserver)
GMPRemoveTest::GMPRemoveTest()
: mIsTerminated(false)
, mDecoder(nullptr)
, mHost(nullptr)
{
}
GMPRemoveTest::~GMPRemoveTest()
{
bool exists;
EXPECT_TRUE(NS_SUCCEEDED(mTmpDir->Exists(&exists)) && !exists);
EXPECT_OK(GetServiceParent()->AddPluginDirectory(mOriginalPath));
}
void
GMPRemoveTest::Setup()
{
// Initialize media preferences.
MediaPrefs::GetSingleton();
GeneratePlugin();
GetService()->GetThread(getter_AddRefs(mGMPThread));
// Spin the event loop until the GMP service has had a chance to complete
// adding GMPs from MOZ_GMP_PATH. Otherwise, the RemovePluginDirectory()
// below may complete before we're finished adding GMPs from MOZ_GMP_PATH,
// and we'll end up not removing the GMP, and the test will fail.
RefPtr<AbstractThread> thread(GetServiceParent()->GetAbstractGMPThread());
GMPTestMonitor* mon = &mTestMonitor;
GetServiceParent()->EnsureInitialized()->Then(thread, __func__,
[mon]() { mon->SetFinished(); },
[mon]() { mon->SetFinished(); }
);
mTestMonitor.AwaitFinished();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(this, GMP_DELETED_TOPIC, false /* strong ref */);
EXPECT_OK(GetServiceParent()->RemovePluginDirectory(mOriginalPath));
GetServiceParent()->AsyncAddPluginDirectory(mTmpPath)->Then(thread, __func__,
[mon]() { mon->SetFinished(); },
[mon]() { mon->SetFinished(); }
);
mTestMonitor.AwaitFinished();
}
bool
GMPRemoveTest::CreateVideoDecoder(nsCString aNodeId)
{
GMPVideoHost* host;
GMPVideoDecoderProxy* decoder = nullptr;
mGMPThread->Dispatch(
NewNonOwningRunnableMethod<nsCString, GMPVideoDecoderProxy**, GMPVideoHost**>(
this, &GMPRemoveTest::gmp_GetVideoDecoder, aNodeId, &decoder, &host),
NS_DISPATCH_NORMAL);
mTestMonitor.AwaitFinished();
if (!decoder) {
return false;
}
GMPVideoCodec codec;
memset(&codec, 0, sizeof(codec));
codec.mGMPApiVersion = 33;
nsTArray<uint8_t> empty;
mGMPThread->Dispatch(
NewNonOwningRunnableMethod<const GMPVideoCodec&, const nsTArray<uint8_t>&, GMPVideoDecoderCallbackProxy*, int32_t>(
decoder, &GMPVideoDecoderProxy::InitDecode,
codec, empty, this, 1 /* core count */),
NS_DISPATCH_SYNC);
if (mDecoder) {
CloseVideoDecoder();
}
mDecoder = decoder;
mHost = host;
return true;
}
void
GMPRemoveTest::gmp_GetVideoDecoder(nsCString aNodeId,
GMPVideoDecoderProxy** aOutDecoder,
GMPVideoHost** aOutHost)
{
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
tags.AppendElement(NS_LITERAL_CSTRING("fake"));
class Callback : public GetGMPVideoDecoderCallback
{
public:
Callback(GMPTestMonitor* aMonitor, GMPVideoDecoderProxy** aDecoder, GMPVideoHost** aHost)
: mMonitor(aMonitor), mDecoder(aDecoder), mHost(aHost) { }
virtual void Done(GMPVideoDecoderProxy* aDecoder, GMPVideoHost* aHost) override {
*mDecoder = aDecoder;
*mHost = aHost;
mMonitor->SetFinished();
}
private:
GMPTestMonitor* mMonitor;
GMPVideoDecoderProxy** mDecoder;
GMPVideoHost** mHost;
};
UniquePtr<GetGMPVideoDecoderCallback>
cb(new Callback(&mTestMonitor, aOutDecoder, aOutHost));
if (NS_FAILED(GetService()->GetGMPVideoDecoder(&tags, aNodeId, Move(cb)))) {
mTestMonitor.SetFinished();
}
}
void
GMPRemoveTest::CloseVideoDecoder()
{
mGMPThread->Dispatch(
NewNonOwningRunnableMethod(mDecoder, &GMPVideoDecoderProxy::Close),
NS_DISPATCH_SYNC);
mDecoder = nullptr;
mHost = nullptr;
}
void
GMPRemoveTest::DeletePluginDirectory(bool aCanDefer)
{
GetServiceParent()->RemoveAndDeletePluginDirectory(mTmpPath, aCanDefer);
}
GMPErr
GMPRemoveTest::Decode()
{
mGMPThread->Dispatch(
NewNonOwningRunnableMethod(this, &GMPRemoveTest::gmp_Decode),
NS_DISPATCH_NORMAL);
mTestMonitor.AwaitFinished();
return mDecodeResult;
}
void
GMPRemoveTest::gmp_Decode()
{
// from gmp-fake.cpp
struct EncodedFrame {
uint32_t length_;
uint8_t h264_compat_;
uint32_t magic_;
uint32_t width_;
uint32_t height_;
uint8_t y_;
uint8_t u_;
uint8_t v_;
uint32_t timestamp_;
};
GMPVideoFrame* absFrame;
GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &absFrame);
EXPECT_EQ(err, GMPNoErr);
GMPUniquePtr<GMPVideoEncodedFrame>
frame(static_cast<GMPVideoEncodedFrame*>(absFrame));
err = frame->CreateEmptyFrame(sizeof(EncodedFrame) /* size */);
EXPECT_EQ(err, GMPNoErr);
EncodedFrame* frameData = reinterpret_cast<EncodedFrame*>(frame->Buffer());
frameData->magic_ = 0x4652414d;
frameData->width_ = frameData->height_ = 16;
nsTArray<uint8_t> empty;
nsresult rv = mDecoder->Decode(Move(frame), false /* aMissingFrames */, empty);
EXPECT_OK(rv);
}
void
GMPRemoveTest::Wait()
{
mTestMonitor.AwaitFinished();
}
bool
GMPRemoveTest::IsTerminated()
{
return mIsTerminated;
}
// nsIObserver
NS_IMETHODIMP
GMPRemoveTest::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
EXPECT_TRUE(!strcmp(GMP_DELETED_TOPIC, aTopic));
nsString data(aData);
if (mTmpPath.Equals(data)) {
mTestMonitor.SetFinished();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, GMP_DELETED_TOPIC);
}
return NS_OK;
}
// GMPVideoDecoderCallbackProxy
void
GMPRemoveTest::Decoded(GMPVideoi420Frame* aDecodedFrame)
{
aDecodedFrame->Destroy();
mDecodeResult = GMPNoErr;
mTestMonitor.SetFinished();
}
// GMPVideoDecoderCallbackProxy
void
GMPRemoveTest::Error(GMPErr aError)
{
mDecodeResult = aError;
mTestMonitor.SetFinished();
}
// GMPVideoDecoderCallbackProxy
void
GMPRemoveTest::Terminated()
{
mIsTerminated = true;
if (mDecoder) {
mDecoder->Close();
mDecoder = nullptr;
}
}
void
GMPRemoveTest::GeneratePlugin()
{
nsresult rv;
nsCOMPtr<nsIFile> gmpDir;
nsCOMPtr<nsIFile> origDir;
nsCOMPtr<nsIFile> tmpDir;
rv = NS_GetSpecialDirectory(NS_GRE_DIR,
getter_AddRefs(gmpDir));
EXPECT_OK(rv);
rv = gmpDir->Append(GMP_DIR_NAME);
EXPECT_OK(rv);
rv = gmpDir->Clone(getter_AddRefs(origDir));
EXPECT_OK(rv);
rv = origDir->Append(GMP_OLD_VERSION);
EXPECT_OK(rv);
rv = gmpDir->Clone(getter_AddRefs(tmpDir));
EXPECT_OK(rv);
rv = tmpDir->Append(GMP_NEW_VERSION);
EXPECT_OK(rv);
bool exists = false;
rv = tmpDir->Exists(&exists);
EXPECT_OK(rv);
if (exists) {
rv = tmpDir->Remove(true);
EXPECT_OK(rv);
}
rv = origDir->CopyTo(gmpDir, GMP_NEW_VERSION);
EXPECT_OK(rv);
rv = gmpDir->Clone(getter_AddRefs(tmpDir));
EXPECT_OK(rv);
rv = tmpDir->Append(GMP_NEW_VERSION);
EXPECT_OK(rv);
EXPECT_OK(origDir->GetPath(mOriginalPath));
EXPECT_OK(tmpDir->GetPath(mTmpPath));
mTmpDir = tmpDir;
}