зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1907466 - make some thread-safety changes for clipboard content analysis r=nika,dlp-reviewers,handyman
Differential Revision: https://phabricator.services.mozilla.com/D216608
This commit is contained in:
Родитель
6c9b83a5f7
Коммит
1675fa0d4b
|
@ -1545,14 +1545,6 @@ 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,9 +160,6 @@ 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);
|
||||
|
||||
|
|
|
@ -1115,62 +1115,35 @@ static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
|
|||
return docShell;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvCreateClipboardContentAnalysis() {
|
||||
Endpoint<PClipboardContentAnalysisParent> parentEndpoint;
|
||||
Endpoint<PClipboardContentAnalysisChild> childEndpoint;
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvCreateClipboardContentAnalysis(
|
||||
Endpoint<PClipboardContentAnalysisParent>&& aParentEndpoint) {
|
||||
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");
|
||||
}
|
||||
mClipboardContentAnalysisCreated = true;
|
||||
|
||||
if (!mClipboardContentAnalysisThread) {
|
||||
rv = NS_NewNamedThread("BkgrndClipboard",
|
||||
getter_AddRefs(mClipboardContentAnalysisThread));
|
||||
nsresult 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(
|
||||
// Bind the new endpoint to the backgroundClipboardContentAnalysis thread.
|
||||
mClipboardContentAnalysisThread->Dispatch(
|
||||
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");
|
||||
[threadsafeHandle = RefPtr{ThreadsafeHandle()},
|
||||
parentEndpoint = std::move(aParentEndpoint)]() mutable {
|
||||
// Use a threadsafe handle here, so that it can
|
||||
// be used to validate that the WindowContext comes from the
|
||||
// correct content process.
|
||||
RefPtr<ClipboardContentAnalysisParent> actor =
|
||||
new ClipboardContentAnalysisParent(std::move(threadsafeHandle));
|
||||
parentEndpoint.Bind(actor);
|
||||
}),
|
||||
mClipboardContentAnalysisThread, EventQueuePriority::Normal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_FAIL(this, "NS_DispatchToThreadQueue failed");
|
||||
}
|
||||
mClipboardContentAnalysisCreated = true;
|
||||
NS_DISPATCH_NORMAL);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -351,7 +351,8 @@ 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 RecvCreateClipboardContentAnalysis(
|
||||
Endpoint<PClipboardContentAnalysisParent>&& aParentEndpoint);
|
||||
mozilla::ipc::IPCResult RecvCreateGMPService();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
|
||||
|
|
|
@ -579,7 +579,6 @@ 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(
|
||||
|
@ -1082,7 +1081,7 @@ parent:
|
|||
|
||||
async CreateGMPService();
|
||||
|
||||
async CreateClipboardContentAnalysis();
|
||||
async CreateClipboardContentAnalysis(Endpoint<PClipboardContentAnalysisParent> aParentEndpoint);
|
||||
|
||||
async InitStreamFilter(uint64_t channelId, nsString addonId)
|
||||
returns (Endpoint<PStreamFilterChild> aEndpoint);
|
||||
|
|
|
@ -1048,6 +1048,16 @@ ContentAnalysis::GetMightBeActive(bool* aMightBeActive) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ bool ContentAnalysis::MightBeActive() {
|
||||
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
|
||||
mozilla::components::nsIContentAnalysis::Service();
|
||||
NS_ENSURE_TRUE(contentAnalysis, false);
|
||||
|
||||
bool maybeActive = false;
|
||||
return NS_SUCCEEDED(contentAnalysis->GetMightBeActive(&maybeActive)) &&
|
||||
maybeActive;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentAnalysis::GetIsSetByEnterprisePolicy(bool* aSetByEnterprise) {
|
||||
*aSetByEnterprise = mSetByEnterprise;
|
||||
|
|
|
@ -213,6 +213,7 @@ class ContentAnalysis final : public nsIContentAnalysis {
|
|||
mozilla::MoveOnlyFunction<void(RefPtr<nsIContentAnalysisResult>&&)>
|
||||
mResolver;
|
||||
};
|
||||
static bool MightBeActive();
|
||||
static bool CheckClipboardContentAnalysisSync(
|
||||
nsBaseClipboard* aClipboard, mozilla::dom::WindowGlobalParent* aWindow,
|
||||
const nsCOMPtr<nsITransferable>& trans, int32_t aClipboardType);
|
||||
|
|
|
@ -5,10 +5,31 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ClipboardContentAnalysisChild.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
StaticRefPtr<ClipboardContentAnalysisChild>
|
||||
ClipboardContentAnalysisChild::sSingleton;
|
||||
|
||||
/* static */ ClipboardContentAnalysisChild*
|
||||
ClipboardContentAnalysisChild::GetOrCreate() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
if (!sSingleton) {
|
||||
Endpoint<PClipboardContentAnalysisParent> parentEndpoint;
|
||||
Endpoint<PClipboardContentAnalysisChild> childEndpoint;
|
||||
MOZ_ALWAYS_SUCCEEDS(PClipboardContentAnalysis::CreateEndpoints(
|
||||
&parentEndpoint, &childEndpoint));
|
||||
dom::ContentChild::GetSingleton()->SendCreateClipboardContentAnalysis(
|
||||
std::move(parentEndpoint));
|
||||
|
||||
sSingleton = new ClipboardContentAnalysisChild();
|
||||
childEndpoint.Bind(sSingleton);
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -13,16 +13,10 @@ namespace mozilla {
|
|||
class ClipboardContentAnalysisChild final
|
||||
: public PClipboardContentAnalysisChild {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ClipboardContentAnalysisChild, override)
|
||||
NS_INLINE_DECL_REFCOUNTING(ClipboardContentAnalysisChild, override)
|
||||
|
||||
static ClipboardContentAnalysisChild* GetOrCreate();
|
||||
|
||||
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;
|
||||
|
|
|
@ -8,16 +8,107 @@
|
|||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MozPromise.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);
|
||||
namespace {
|
||||
using ClipboardResultPromise =
|
||||
MozPromise<dom::IPCTransferableData, nsresult, true>;
|
||||
|
||||
static RefPtr<ClipboardResultPromise> GetClipboardImpl(
|
||||
const nsTArray<nsCString>& aTypes, int32_t aWhichClipboard,
|
||||
uint64_t aRequestingWindowContextId,
|
||||
dom::ThreadsafeContentParentHandle* aRequestingContentParent) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
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) {
|
||||
return ClipboardResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
||||
if (window->IsDiscarded()) {
|
||||
NS_WARNING(
|
||||
"discarded window passed to RecvGetClipboard(); returning "
|
||||
"no clipboard "
|
||||
"content");
|
||||
return ClipboardResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
||||
if (aRequestingContentParent->ChildID() != window->ContentParentId()) {
|
||||
NS_WARNING("incorrect content process passing window to GetClipboard");
|
||||
return ClipboardResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
||||
// Retrieve clipboard
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1");
|
||||
if (!clipboard) {
|
||||
return ClipboardResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
||||
auto transferableToCheck =
|
||||
dom::ContentParent::CreateClipboardTransferable(aTypes);
|
||||
if (transferableToCheck.isErr()) {
|
||||
return ClipboardResultPromise::CreateAndReject(
|
||||
transferableToCheck.unwrapErr(), __func__);
|
||||
}
|
||||
|
||||
// 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();
|
||||
// Ideally we would be calling GetDataSnapshot() here to avoid blocking the
|
||||
// main thread (and this would mean we could also pass in the window here so
|
||||
// we wouldn't have to duplicate the Content Analysis code below). See
|
||||
// bug 1908280.
|
||||
nsresult rv = clipboard->GetData(transferable, aWhichClipboard, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return ClipboardResultPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
auto resultPromise = MakeRefPtr<ClipboardResultPromise::Private>(__func__);
|
||||
|
||||
auto contentAnalysisCallback =
|
||||
mozilla::MakeRefPtr<mozilla::contentanalysis::ContentAnalysis::
|
||||
SafeContentAnalysisResultCallback>(
|
||||
[transferable, resultPromise,
|
||||
cpHandle = RefPtr{aRequestingContentParent}](
|
||||
RefPtr<nsIContentAnalysisResult>&& aResult) {
|
||||
// Needed to call cpHandle->GetContentParent()
|
||||
AssertIsOnMainThread();
|
||||
|
||||
bool shouldAllow = aResult->GetShouldAllowContent();
|
||||
if (!shouldAllow) {
|
||||
resultPromise->Reject(NS_ERROR_CONTENT_BLOCKED, __func__);
|
||||
return;
|
||||
}
|
||||
dom::IPCTransferableData transferableData;
|
||||
RefPtr<dom::ContentParent> contentParent =
|
||||
cpHandle->GetContentParent();
|
||||
nsContentUtils::TransferableToIPCTransferableData(
|
||||
transferable, &transferableData, true /* aInSyncMessage */,
|
||||
contentParent);
|
||||
resultPromise->Resolve(std::move(transferableData), __func__);
|
||||
});
|
||||
|
||||
contentanalysis::ContentAnalysis::CheckClipboardContentAnalysis(
|
||||
static_cast<nsBaseClipboard*>(clipboard.get()), window, transferable,
|
||||
aWhichClipboard, contentAnalysisCallback);
|
||||
return resultPromise;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ipc::IPCResult ClipboardContentAnalysisParent::RecvGetClipboard(
|
||||
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
|
||||
|
@ -27,138 +118,44 @@ ipc::IPCResult ClipboardContentAnalysisParent::RecvGetClipboard(
|
|||
// 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;
|
||||
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));
|
||||
// Stop the actor thread's SpinEventLoopUntil().
|
||||
NS_DispatchToThreadQueue(
|
||||
NS_NewRunnableFunction(
|
||||
__func__,
|
||||
[&transferableResultSet]() { transferableResultSet = true; }),
|
||||
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;
|
||||
}
|
||||
Monitor mon("ClipboardContentAnalysisParent::RecvGetClipboard");
|
||||
InvokeAsync(GetMainThreadSerialEventTarget(), __func__,
|
||||
[&]() {
|
||||
return GetClipboardImpl(aTypes, aWhichClipboard,
|
||||
aRequestingWindowContextId,
|
||||
mThreadsafeContentParentHandle);
|
||||
})
|
||||
->Then(GetMainThreadSerialEventTarget(), __func__,
|
||||
[&](ClipboardResultPromise::ResolveOrRejectValue&& aResult) {
|
||||
AssertIsOnMainThread();
|
||||
// Acquire the lock, pass the data back to the background
|
||||
// thread, and notify the background thread that work is
|
||||
// complete.
|
||||
MonitorAutoLock lock(mon);
|
||||
if (aResult.IsResolve()) {
|
||||
*aTransferableDataOrError = std::move(aResult.ResolveValue());
|
||||
} else {
|
||||
*aTransferableDataOrError = aResult.RejectValue();
|
||||
}
|
||||
mon.Notify();
|
||||
});
|
||||
|
||||
if (window->IsDiscarded()) {
|
||||
NS_WARNING(
|
||||
"discarded window passed to RecvGetClipboard(); returning "
|
||||
"no clipboard "
|
||||
"content");
|
||||
rv = NS_ERROR_FAILURE;
|
||||
return;
|
||||
}
|
||||
{
|
||||
MonitorAutoLock lock(mon);
|
||||
while (aTransferableDataOrError->type() ==
|
||||
IPCTransferableDataOrError::T__None) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// We need to set maybeTransferableResult on the main thread
|
||||
// instead of the actor thread because some of the objects
|
||||
// that can be inside a maybeTransferableResult are not
|
||||
// thread-safe.
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the actor thread's SpinEventLoopUntil().
|
||||
NS_DispatchToThreadQueue(
|
||||
NS_NewRunnableFunction(__func__,
|
||||
[&transferableResultSet]() {
|
||||
transferableResultSet = true;
|
||||
}),
|
||||
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; });
|
||||
|
||||
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>());
|
||||
if (aTransferableDataOrError->type() ==
|
||||
IPCTransferableDataOrError::Tnsresult) {
|
||||
NS_WARNING(nsPrintfCString(
|
||||
"ClipboardContentAnalysisParent::"
|
||||
"RecvGetClipboard got error %x",
|
||||
static_cast<int>(aTransferableDataOrError->get_nsresult()))
|
||||
.get());
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISPARENT_H_
|
||||
#define MOZILLA_WIDGET_CLIPBOARDCONTENTANALYSISPARENT_H_
|
||||
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/PClipboardContentAnalysisParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -14,9 +15,15 @@ class ClipboardContentAnalysisParent final
|
|||
: public PClipboardContentAnalysisParent {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(ClipboardContentAnalysisParent, override)
|
||||
explicit ClipboardContentAnalysisParent(
|
||||
RefPtr<dom::ThreadsafeContentParentHandle>&&
|
||||
aThreadsafeContentParentHandle)
|
||||
: mThreadsafeContentParentHandle(
|
||||
std::move(aThreadsafeContentParentHandle)) {}
|
||||
|
||||
private:
|
||||
~ClipboardContentAnalysisParent() = default;
|
||||
RefPtr<dom::ThreadsafeContentParentHandle> mThreadsafeContentParentHandle;
|
||||
|
||||
public:
|
||||
ipc::IPCResult RecvGetClipboard(
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "nsClipboardProxy.h"
|
||||
|
||||
#include "ContentAnalysis.h"
|
||||
#if defined(ACCESSIBILITY) && defined(XP_WIN)
|
||||
# include "mozilla/a11y/Compatibility.h"
|
||||
#endif
|
||||
|
@ -77,28 +78,22 @@ nsClipboardProxy::GetData(nsITransferable* aTransferable,
|
|||
aTransferable->FlavorsTransferableCanImport(types);
|
||||
|
||||
IPCTransferableDataOrError 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(); });
|
||||
if (MOZ_UNLIKELY(contentanalysis::ContentAnalysis::MightBeActive())) {
|
||||
RefPtr<ClipboardContentAnalysisChild> contentAnalysis =
|
||||
ClipboardContentAnalysisChild::GetOrCreate();
|
||||
if (!contentAnalysis) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!contentAnalysis->SendGetClipboard(types, aWhichClipboard,
|
||||
aWindowContext->InnerWindowId(),
|
||||
&transferableOrError)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
ClipboardContentAnalysisChild::GetSingleton()->SendGetClipboard(
|
||||
types, aWhichClipboard, aWindowContext->InnerWindowId(),
|
||||
&transferableOrError);
|
||||
} else {
|
||||
ContentChild::GetSingleton()->SendGetClipboard(
|
||||
types, aWhichClipboard, aWindowContext, &transferableOrError);
|
||||
if (!ContentChild::GetSingleton()->SendGetClipboard(
|
||||
types, aWhichClipboard, aWindowContext, &transferableOrError)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
};
|
||||
}
|
||||
|
||||
if (transferableOrError.type() == IPCTransferableDataOrError::Tnsresult) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче