Bug 1901197: do synchronous Content Analysis for clipboard operations on a background thread r=dlp-reviewers,ipc-reviewers,handyman

Differential Revision: https://phabricator.services.mozilla.com/D215457
This commit is contained in:
Greg Stoll 2024-07-04 01:24:53 +00:00
Родитель 7d29658155
Коммит 6ba11a66b8
14 изменённых файлов: 402 добавлений и 9 удалений

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

@ -20,6 +20,9 @@
# Used by `nsUpdateProcessor` to check for updates. May also be used for polling
# the update process.
UpdateProcessor
# Used by `BackgroundClipboardContentAnalysisParent` to handle clipboard requests
# from content processes.
BkgrndClipboard
######
# Thunderbird-only thread names

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

@ -24,6 +24,7 @@
#include "imgLoader.h"
#include "ScrollingMetrics.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClipboardContentAnalysisChild.h"
#include "mozilla/ClipboardReadRequestChild.h"
#include "mozilla/Components.h"
#include "mozilla/HangDetails.h"
@ -1544,6 +1545,14 @@ mozilla::ipc::IPCResult ContentChild::RecvInitGMPService(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvInitClipboardContentAnalysis(
Endpoint<PClipboardContentAnalysisChild>&& aEndpoint) {
if (!ClipboardContentAnalysisChild::Create(std::move(aEndpoint))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvInitProfiler(
Endpoint<PProfilerChild>&& aEndpoint) {
mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));

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

@ -160,6 +160,9 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvInitProfiler(
Endpoint<PProfilerChild>&& aEndpoint);
mozilla::ipc::IPCResult RecvInitClipboardContentAnalysis(
Endpoint<PClipboardContentAnalysisChild>&& aEndpoint);
mozilla::ipc::IPCResult RecvGMPsChanged(
nsTArray<GMPCapabilityData>&& capabilities);

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

@ -47,6 +47,7 @@
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/ClipboardContentAnalysisParent.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/BenchmarkStorageParent.h"
#include "mozilla/Casting.h"
@ -1114,6 +1115,65 @@ static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
return docShell;
}
mozilla::ipc::IPCResult ContentParent::RecvCreateClipboardContentAnalysis() {
Endpoint<PClipboardContentAnalysisParent> parentEndpoint;
Endpoint<PClipboardContentAnalysisChild> childEndpoint;
if (mClipboardContentAnalysisCreated) {
return IPC_FAIL(this, "ClipboardContentAnalysisParent already created");
}
nsresult rv;
rv = PClipboardContentAnalysis::CreateEndpoints(
base::GetCurrentProcId(), OtherPid(), &parentEndpoint, &childEndpoint);
if (NS_FAILED(rv)) {
return IPC_FAIL(this, "CreateEndpoints failed");
}
if (!mClipboardContentAnalysisThread) {
rv = NS_NewNamedThread("BkgrndClipboard",
getter_AddRefs(mClipboardContentAnalysisThread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL(this, "NS_NewNamedThread failed");
}
}
RefPtr<ContentParent> contentParent = this;
// Bind the new endpoint to the backgroundClipboardContentAnalysis thread,
// then send them from the main thread.
rv = NS_DispatchToThreadQueue(
NS_NewRunnableFunction(
"Create ClipboardContentAnalysisParent",
[contentParent = std::move(contentParent),
parentEndpoint = std::move(parentEndpoint),
childEndpoint = std::move(childEndpoint)]() mutable {
RefPtr<ClipboardContentAnalysisParent> parentActor =
new ClipboardContentAnalysisParent();
parentEndpoint.Bind(parentActor, nullptr);
DebugOnly<nsresult> rv = NS_DispatchToMainThread(
NS_NewRunnableFunction(
"SendInitClipboardContentAnalysis",
[contentParent = std::move(contentParent),
childEndpoint = std::move(childEndpoint)]() mutable {
DebugOnly<bool> success =
contentParent->SendInitClipboardContentAnalysis(
std::move(childEndpoint));
MOZ_ASSERT(success,
"SendInitClipboardContentAnalysis failed");
}),
0);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to dispatch "
"SendInitClipboardContentAnalysis");
}),
mClipboardContentAnalysisThread, EventQueuePriority::Normal);
if (NS_FAILED(rv)) {
return IPC_FAIL(this, "NS_DispatchToThreadQueue failed");
}
mClipboardContentAnalysisCreated = true;
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() {
Endpoint<PGMPServiceParent> parent;
Endpoint<PGMPServiceChild> child;
@ -2531,6 +2591,7 @@ ContentParent::ContentParent(const nsACString& aRemoteType)
mIsInputPriorityEventEnabled(false),
mIsInPool(false),
mGMPCreated(false),
mClipboardContentAnalysisCreated(false),
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
mBlockShutdownCalled(false),
#endif
@ -3115,10 +3176,8 @@ mozilla::ipc::IPCResult ContentParent::RecvSetClipboard(
return IPC_OK();
}
namespace {
static Result<nsCOMPtr<nsITransferable>, nsresult> CreateTransferable(
const nsTArray<nsCString>& aTypes) {
/* static */ Result<nsCOMPtr<nsITransferable>, nsresult>
ContentParent::CreateClipboardTransferable(const nsTArray<nsCString>& aTypes) {
nsresult rv;
nsCOMPtr<nsITransferable> trans =
do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
@ -3141,8 +3200,6 @@ static Result<nsCOMPtr<nsITransferable>, nsresult> CreateTransferable(
return std::move(trans);
}
} // anonymous namespace
mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
@ -3171,7 +3228,7 @@ mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
}
// Create transferable
auto result = CreateTransferable(aTypes);
auto result = CreateClipboardTransferable(aTypes);
if (result.isErr()) {
*aTransferableDataOrError = result.unwrapErr();
return IPC_OK();

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

@ -30,6 +30,7 @@
#include "mozilla/MemoryReportingProcess.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RecursiveMutex.h"
#include "mozilla/Result.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
@ -44,6 +45,7 @@
#include "nsIInterfaceRequestor.h"
#include "nsIObserver.h"
#include "nsIRemoteTab.h"
#include "nsITransferable.h"
#include "nsIDOMGeoPositionCallback.h"
#include "nsIDOMGeoPositionErrorCallback.h"
#include "nsRefPtrHashtable.h"
@ -228,6 +230,12 @@ class ContentParent final : public PContentParent,
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
bool aPreferUsed = false, uint64_t aBrowserId = 0);
/**
* Create an nsITransferable with the specified data flavor types.
*/
static mozilla::Result<nsCOMPtr<nsITransferable>, nsresult>
CreateClipboardTransferable(const nsTArray<nsCString>& aTypes);
/**
* Asynchronously wait for this content process to finish launching, such that
* the ContentParent actor is ready for IPC.
@ -343,6 +351,7 @@ class ContentParent final : public PContentParent,
// been updated and so full reflows are in order.
static void NotifyUpdatedFonts(bool aFullRebuild);
mozilla::ipc::IPCResult RecvCreateClipboardContentAnalysis();
mozilla::ipc::IPCResult RecvCreateGMPService();
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
@ -1510,6 +1519,9 @@ class ContentParent final : public PContentParent,
// True if we already created a GMP service.
uint8_t mGMPCreated : 1;
// True if we already created the
// ClipboardContentAnalysis actor
uint8_t mClipboardContentAnalysisCreated : 1;
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool mBlockShutdownCalled;
@ -1590,6 +1602,8 @@ class ContentParent final : public PContentParent,
bool mIsSignaledImpendingShutdown = false;
bool mIsNotifiedShutdownSuccess = false;
nsCOMPtr<nsIThread> mClipboardContentAnalysisThread;
};
NS_DEFINE_STATIC_IID_ACCESSOR(ContentParent, NS_CONTENTPARENT_IID)

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

@ -6,6 +6,7 @@
include protocol PBackgroundStarter;
include protocol PBrowser;
include protocol PClipboardContentAnalysis;
include protocol PClipboardReadRequest;
include protocol PClipboardWriteRequest;
include protocol PCompositorManager;
@ -578,6 +579,7 @@ child:
async InitGMPService(Endpoint<PGMPServiceChild> service);
async InitProcessHangMonitor(Endpoint<PProcessHangMonitorChild> hangMonitor);
async InitProfiler(Endpoint<PProfilerChild> aEndpoint);
async InitClipboardContentAnalysis(Endpoint<PClipboardContentAnalysisChild> aEndpoint);
// Give the content process its endpoints to the compositor.
async InitRendering(
@ -1088,6 +1090,8 @@ parent:
async CreateGMPService();
async CreateClipboardContentAnalysis();
async InitStreamFilter(uint64_t channelId, nsString addonId)
returns (Endpoint<PStreamFilterChild> aEndpoint);

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

@ -96,6 +96,8 @@ description = Only used by gtests
description = Only used by gtests
# Clipboard
[PClipboardContentAnalysis::GetClipboard]
description = Legacy synchronous clipboard API
[PContent::GetClipboard]
description = Legacy synchronous clipboard API
[PContent::ClipboardHasType]

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

@ -0,0 +1,14 @@
/* -*- 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 "ClipboardContentAnalysisChild.h"
namespace mozilla {
StaticRefPtr<ClipboardContentAnalysisChild>
ClipboardContentAnalysisChild::sSingleton;
} // namespace mozilla

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

@ -0,0 +1,39 @@
/* -*- 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/. */
#ifndef MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISCHILD_H_
#define MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISCHILD_H_
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/PClipboardContentAnalysisChild.h"
namespace mozilla {
class ClipboardContentAnalysisChild final
: public PClipboardContentAnalysisChild {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ClipboardContentAnalysisChild, override)
static bool Create(Endpoint<PClipboardContentAnalysisChild>&& aEndpoint) {
MOZ_ASSERT(!sSingleton);
sSingleton = new ClipboardContentAnalysisChild();
DebugOnly<bool> success = aEndpoint.Bind(sSingleton);
MOZ_ASSERT(success);
return true;
}
static ClipboardContentAnalysisChild* GetSingleton() { return sSingleton; }
void ActorDestroy(ActorDestroyReason aReason) override final {
// There's only one singleton, so remove our reference to it.
sSingleton = nullptr;
}
private:
friend PClipboardContentAnalysisChild;
ClipboardContentAnalysisChild() { MOZ_ASSERT(XRE_IsContentProcess()); }
~ClipboardContentAnalysisChild() = default;
static StaticRefPtr<ClipboardContentAnalysisChild> sSingleton;
};
} // namespace mozilla
#endif // MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISCHILD_H_

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

@ -0,0 +1,165 @@
/* -*- Mode: C++; tab-width: 8; 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 "ContentAnalysis.h"
#include "mozilla/ClipboardContentAnalysisParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/Maybe.h"
#include "mozilla/Variant.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "nsBaseClipboard.h"
#include "nsIClipboard.h"
#include "nsID.h"
#include "nsITransferable.h"
#include "nsWidgetsCID.h"
namespace mozilla {
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
ipc::IPCResult ClipboardContentAnalysisParent::RecvGetClipboard(
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
const uint64_t& aRequestingWindowContextId,
IPCTransferableDataOrError* aTransferableDataOrError) {
// The whole point of having this actor is that it runs on a background thread
// and so waiting for the content analysis result won't cause the main thread
// to use SpinEventLoopUntil() which can cause a shutdownhang per bug 1901197.
MOZ_ASSERT(!NS_IsMainThread());
RefPtr<nsIThread> actorThread = NS_GetCurrentThread();
NS_ASSERTION(actorThread, "NS_GetCurrentThread() should not fail");
// Ideally this would be a Maybe<Result>, but Result<> doesn't have a way to
// get a reference to the IPCTransferableData inside it which makes it awkward
// to use in this case.
mozilla::Maybe<mozilla::Variant<IPCTransferableData, nsresult>>
maybeTransferableResult;
std::atomic<bool> transferableResultSet = false;
NS_DispatchToMainThread(NS_NewRunnableFunction(
__func__, [actorThread, aTypes = std::move(aTypes), aWhichClipboard,
aRequestingWindowContextId, &maybeTransferableResult,
&transferableResultSet]() {
nsresult rv = NS_OK;
// Make sure we reply to the actor thread on error.
auto sendRv = MakeScopeExit([&]() {
maybeTransferableResult = Some(AsVariant(rv));
transferableResultSet = true;
// Wake up the actor thread so SpinEventLoopUntil() can check its
// condition again.
NS_DispatchToThreadQueue(NS_NewRunnableFunction(__func__, []() {}),
actorThread, EventQueuePriority::Normal);
});
nsCOMPtr<nsIClipboard> clipboard;
RefPtr<dom::WindowGlobalParent> window =
dom::WindowGlobalParent::GetByInnerWindowId(
aRequestingWindowContextId);
// We expect content processes to always pass a non-null window so
// Content Analysis can analyze it. (if Content Analysis is
// active) There may be some cases when a window is closing, etc.,
// in which case returning no clipboard content should not be a
// problem.
if (!window) {
rv = NS_ERROR_FAILURE;
return;
}
if (window->IsDiscarded()) {
NS_WARNING(
"discarded window passed to RecvGetClipboard(); returning "
"no clipboard "
"content");
rv = NS_ERROR_FAILURE;
return;
}
// Retrieve clipboard
clipboard = do_GetService(kCClipboardCID, &rv);
NS_ENSURE_SUCCESS_VOID(rv);
auto transferableToCheck =
dom::ContentParent::CreateClipboardTransferable(aTypes);
if (transferableToCheck.isErr()) {
rv = transferableToCheck.unwrapErr();
return;
}
// Pass nullptr for the window here because we will be doing
// content analysis ourselves asynchronously (so it doesn't block
// main thread we're running on now)
nsCOMPtr transferable = transferableToCheck.unwrap();
rv = clipboard->GetData(transferable, aWhichClipboard, nullptr);
NS_ENSURE_SUCCESS_VOID(rv);
auto contentAnalysisCallback =
mozilla::MakeRefPtr<mozilla::contentanalysis::ContentAnalysis::
SafeContentAnalysisResultCallback>(
[actorThread, transferable, aRequestingWindowContextId,
&maybeTransferableResult, &transferableResultSet](
RefPtr<nsIContentAnalysisResult>&& aResult) {
bool shouldAllow = aResult->GetShouldAllowContent();
if (!shouldAllow) {
maybeTransferableResult =
Some(AsVariant(NS_ERROR_CONTENT_BLOCKED));
} else {
IPCTransferableData transferableData;
RefPtr<dom::WindowGlobalParent> window =
dom::WindowGlobalParent::GetByInnerWindowId(
aRequestingWindowContextId);
if (!window && window->IsDiscarded()) {
maybeTransferableResult =
Some(AsVariant(NS_ERROR_UNEXPECTED));
} else {
maybeTransferableResult =
Some(AsVariant(IPCTransferableData()));
nsContentUtils::TransferableToIPCTransferableData(
transferable,
&(maybeTransferableResult.ref()
.as<IPCTransferableData>()),
true /* aInSyncMessage */,
window->BrowsingContext()->GetContentParent());
}
}
transferableResultSet = true;
// Setting maybeTransferableResult is done on the main thread
// instead of inside the runnable function here because some
// of the objects that can be inside a maybeTransferableResult
// are not thread-safe.
// Wake up the actor thread so SpinEventLoopUntil() can check
// its condition again.
NS_DispatchToThreadQueue(
NS_NewRunnableFunction(__func__, []() {}), actorThread,
EventQueuePriority::Normal);
});
contentanalysis::ContentAnalysis::CheckClipboardContentAnalysis(
static_cast<nsBaseClipboard*>(clipboard.get()), window,
transferable, aWhichClipboard, contentAnalysisCallback);
sendRv.release();
}));
mozilla::SpinEventLoopUntil(
"Waiting for clipboard and content analysis"_ns,
[&transferableResultSet] { return transferableResultSet.load(); });
NS_ASSERTION(maybeTransferableResult.isSome(),
"maybeTransferableResult should be set when "
"transferableResultSet is true!");
auto& transferableResult = *maybeTransferableResult;
if (transferableResult.is<nsresult>()) {
*aTransferableDataOrError = transferableResult.as<nsresult>();
NS_WARNING(
nsPrintfCString("ClipboardContentAnalysisParent::"
"RecvGetClipboard got error %x",
static_cast<int>(transferableResult.as<nsresult>()))
.get());
} else {
*aTransferableDataOrError =
std::move(transferableResult.as<IPCTransferableData>());
}
return IPC_OK();
}
} // namespace mozilla

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

@ -0,0 +1,29 @@
/* -*- 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/. */
#ifndef MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISPARENT_H_
#define MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISPARENT_H_
#include "mozilla/PClipboardContentAnalysisParent.h"
namespace mozilla {
class ClipboardContentAnalysisParent final
: public PClipboardContentAnalysisParent {
public:
NS_INLINE_DECL_REFCOUNTING(ClipboardContentAnalysisParent, override)
private:
~ClipboardContentAnalysisParent() = default;
public:
ipc::IPCResult RecvGetClipboard(
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
const uint64_t& aRequestingWindowContextId,
IPCTransferableDataOrError* aTransferableDataOrError);
};
} // namespace mozilla
#endif // MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISPARENT_H_

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

@ -0,0 +1,24 @@
/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 IPCTransferable;
namespace mozilla {
[ChildProc=Content]
sync protocol PClipboardContentAnalysis
{
parent:
// Given a list of supported types, returns the clipboard data for the
// first type that matches.
// aRequestingWindowContext is the window that is requesting the clipboard,
// which is used for content analysis.
sync GetClipboard(nsCString[] aTypes, int32_t aWhichClipboard,
uint64_t aRequestingWindowContextId)
returns (IPCTransferableDataOrError transferableDataOrError);
};
}

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

@ -166,6 +166,8 @@ EXPORTS += [
EXPORTS.mozilla += [
"BasicEvents.h",
"ClipboardContentAnalysisChild.h",
"ClipboardContentAnalysisParent.h",
"ClipboardReadRequestChild.h",
"ClipboardReadRequestParent.h",
"ClipboardWriteRequestChild.h",
@ -217,6 +219,8 @@ EXPORTS.mozilla.widget += [
]
UNIFIED_SOURCES += [
"ClipboardContentAnalysisChild.cpp",
"ClipboardContentAnalysisParent.cpp",
"ClipboardReadRequestParent.cpp",
"ClipboardWriteRequestChild.cpp",
"ClipboardWriteRequestParent.cpp",
@ -377,6 +381,7 @@ else:
IPDL_SOURCES += [
"LookAndFeelTypes.ipdlh",
"PClipboardContentAnalysis.ipdl",
"PClipboardReadRequest.ipdl",
"PClipboardWriteRequest.ipdl",
]

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

@ -7,15 +7,19 @@
#if defined(ACCESSIBILITY) && defined(XP_WIN)
# include "mozilla/a11y/Compatibility.h"
#endif
#include "mozilla/ClipboardContentAnalysisChild.h"
#include "mozilla/ClipboardReadRequestChild.h"
#include "mozilla/ClipboardWriteRequestChild.h"
#include "mozilla/Components.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/Unused.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "nsArrayUtils.h"
#include "nsBaseClipboard.h"
#include "nsIContentAnalysis.h"
#include "nsISupportsPrimitives.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
@ -73,8 +77,29 @@ nsClipboardProxy::GetData(nsITransferable* aTransferable,
aTransferable->FlavorsTransferableCanImport(types);
IPCTransferableDataOrError transferableOrError;
ContentChild::GetSingleton()->SendGetClipboard(
types, aWhichClipboard, aWindowContext, &transferableOrError);
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
mozilla::components::nsIContentAnalysis::Service();
Unused << NS_WARN_IF(!contentAnalysis);
bool contentAnalysisMightBeActive = false;
if (contentAnalysis) {
contentAnalysis->GetMightBeActive(&contentAnalysisMightBeActive);
}
if (MOZ_UNLIKELY(contentAnalysisMightBeActive)) {
if (!ClipboardContentAnalysisChild::GetSingleton()) {
if (!ContentChild::GetSingleton()->SendCreateClipboardContentAnalysis()) {
return NS_ERROR_FAILURE;
}
mozilla::SpinEventLoopUntil(
"Wait for ClipboardContentAnalysisChild creation"_ns,
[] { return ClipboardContentAnalysisChild::GetSingleton(); });
}
ClipboardContentAnalysisChild::GetSingleton()->SendGetClipboard(
types, aWhichClipboard, aWindowContext->InnerWindowId(),
&transferableOrError);
} else {
ContentChild::GetSingleton()->SendGetClipboard(
types, aWhichClipboard, aWindowContext, &transferableOrError);
}
if (transferableOrError.type() == IPCTransferableDataOrError::Tnsresult) {
MOZ_ASSERT(NS_FAILED(transferableOrError.get_nsresult()));