gecko-dev/ipc/glue/BackgroundChildImpl.cpp

688 строки
19 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 "BackgroundChildImpl.h"
#include "ActorsChild.h" // IndexedDB
#include "BroadcastChannelChild.h"
#include "ServiceWorkerManagerChild.h"
#include "FileDescriptorSetChild.h"
#ifdef MOZ_WEBRTC
#include "CamerasChild.h"
#endif
#include "mozilla/media/MediaChild.h"
#include "mozilla/Assertions.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/dom/ClientManagerActors.h"
#include "mozilla/dom/PFileSystemRequestChild.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
#include "mozilla/dom/ipc/IPCBlobInputStreamChild.h"
#include "mozilla/dom/ipc/PendingIPCBlobChild.h"
#include "mozilla/dom/ipc/TemporaryIPCBlobChild.h"
#include "mozilla/dom/quota/PQuotaChild.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/GamepadEventChannelChild.h"
#include "mozilla/dom/GamepadTestChannelChild.h"
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/MessagePortChild.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabGroup.h"
#include "mozilla/ipc/IPCStreamAlloc.h"
#include "mozilla/ipc/PBackgroundTestChild.h"
#include "mozilla/ipc/PChildToParentStreamChild.h"
#include "mozilla/ipc/PParentToChildStreamChild.h"
#include "mozilla/layout/VsyncChild.h"
#include "mozilla/net/HttpBackgroundChannelChild.h"
#include "mozilla/net/PUDPSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "mozilla/dom/WebAuthnTransactionChildBase.h"
#include "nsID.h"
#include "nsTraceRefcnt.h"
namespace {
class TestChild final : public mozilla::ipc::PBackgroundTestChild
{
friend class mozilla::ipc::BackgroundChildImpl;
nsCString mTestArg;
explicit TestChild(const nsCString& aTestArg)
: mTestArg(aTestArg)
{
MOZ_COUNT_CTOR(TestChild);
}
protected:
~TestChild() override
{
MOZ_COUNT_DTOR(TestChild);
}
public:
mozilla::ipc::IPCResult
Recv__delete__(const nsCString& aTestArg) override;
};
} // namespace
namespace mozilla {
namespace ipc {
using mozilla::dom::UDPSocketChild;
using mozilla::net::PUDPSocketChild;
using mozilla::dom::asmjscache::PAsmJSCacheEntryChild;
using mozilla::dom::cache::PCacheChild;
using mozilla::dom::cache::PCacheStorageChild;
using mozilla::dom::cache::PCacheStreamControlChild;
using mozilla::dom::LocalStorage;
using mozilla::dom::StorageDBChild;
using mozilla::dom::WebAuthnTransactionChildBase;
// -----------------------------------------------------------------------------
// BackgroundChildImpl::ThreadLocal
// -----------------------------------------------------------------------------
BackgroundChildImpl::
ThreadLocal::ThreadLocal()
: mCurrentFileHandle(nullptr)
{
// May happen on any thread!
MOZ_COUNT_CTOR(mozilla::ipc::BackgroundChildImpl::ThreadLocal);
}
BackgroundChildImpl::
ThreadLocal::~ThreadLocal()
{
// May happen on any thread!
MOZ_COUNT_DTOR(mozilla::ipc::BackgroundChildImpl::ThreadLocal);
}
// -----------------------------------------------------------------------------
// BackgroundChildImpl
// -----------------------------------------------------------------------------
BackgroundChildImpl::BackgroundChildImpl()
{
// May happen on any thread!
MOZ_COUNT_CTOR(mozilla::ipc::BackgroundChildImpl);
}
BackgroundChildImpl::~BackgroundChildImpl()
{
// May happen on any thread!
MOZ_COUNT_DTOR(mozilla::ipc::BackgroundChildImpl);
}
void
BackgroundChildImpl::ProcessingError(Result aCode, const char* aReason)
{
// May happen on any thread!
nsAutoCString abortMessage;
switch (aCode) {
#define HANDLE_CASE(_result) \
case _result: \
abortMessage.AssignLiteral(#_result); \
break
HANDLE_CASE(MsgDropped);
HANDLE_CASE(MsgNotKnown);
HANDLE_CASE(MsgNotAllowed);
HANDLE_CASE(MsgPayloadError);
HANDLE_CASE(MsgProcessingError);
HANDLE_CASE(MsgRouteError);
HANDLE_CASE(MsgValueError);
#undef HANDLE_CASE
default:
MOZ_CRASH("Unknown error code!");
}
MOZ_CRASH_UNSAFE_PRINTF("%s: %s", abortMessage.get(), aReason);
}
void
BackgroundChildImpl::ActorDestroy(ActorDestroyReason aWhy)
{
// May happen on any thread!
}
PBackgroundTestChild*
BackgroundChildImpl::AllocPBackgroundTestChild(const nsCString& aTestArg)
{
return new TestChild(aTestArg);
}
bool
BackgroundChildImpl::DeallocPBackgroundTestChild(PBackgroundTestChild* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<TestChild*>(aActor);
return true;
}
BackgroundChildImpl::PBackgroundIDBFactoryChild*
BackgroundChildImpl::AllocPBackgroundIDBFactoryChild(
const LoggingInfo& aLoggingInfo)
{
MOZ_CRASH("PBackgroundIDBFactoryChild actors should be manually "
"constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundIDBFactoryChild(
PBackgroundIDBFactoryChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundIndexedDBUtilsChild*
BackgroundChildImpl::AllocPBackgroundIndexedDBUtilsChild()
{
MOZ_CRASH("PBackgroundIndexedDBUtilsChild actors should be manually "
"constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundIndexedDBUtilsChild(
PBackgroundIndexedDBUtilsChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundStorageChild*
BackgroundChildImpl::AllocPBackgroundStorageChild(const nsString& aProfilePath)
{
MOZ_CRASH("PBackgroundStorageChild actors should be manually constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundStorageChild(
PBackgroundStorageChild* aActor)
{
MOZ_ASSERT(aActor);
StorageDBChild* child = static_cast<StorageDBChild*>(aActor);
child->ReleaseIPDLReference();
return true;
}
PPendingIPCBlobChild*
BackgroundChildImpl::AllocPPendingIPCBlobChild(const IPCBlob& aBlob)
{
return new mozilla::dom::PendingIPCBlobChild(aBlob);
}
bool
BackgroundChildImpl::DeallocPPendingIPCBlobChild(PPendingIPCBlobChild* aActor)
{
delete aActor;
return true;
}
PTemporaryIPCBlobChild*
BackgroundChildImpl::AllocPTemporaryIPCBlobChild()
{
MOZ_CRASH("This is not supposed to be called.");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPTemporaryIPCBlobChild(PTemporaryIPCBlobChild* aActor)
{
RefPtr<mozilla::dom::TemporaryIPCBlobChild> actor =
dont_AddRef(static_cast<mozilla::dom::TemporaryIPCBlobChild*>(aActor));
return true;
}
PIPCBlobInputStreamChild*
BackgroundChildImpl::AllocPIPCBlobInputStreamChild(const nsID& aID,
const uint64_t& aSize)
{
// IPCBlobInputStreamChild is refcounted. Here it's created and in
// DeallocPIPCBlobInputStreamChild is released.
RefPtr<mozilla::dom::IPCBlobInputStreamChild> actor =
new mozilla::dom::IPCBlobInputStreamChild(aID, aSize);
return actor.forget().take();
}
bool
BackgroundChildImpl::DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor)
{
RefPtr<mozilla::dom::IPCBlobInputStreamChild> actor =
dont_AddRef(static_cast<mozilla::dom::IPCBlobInputStreamChild*>(aActor));
return true;
}
PFileDescriptorSetChild*
BackgroundChildImpl::AllocPFileDescriptorSetChild(
const FileDescriptor& aFileDescriptor)
{
return new FileDescriptorSetChild(aFileDescriptor);
}
bool
BackgroundChildImpl::DeallocPFileDescriptorSetChild(
PFileDescriptorSetChild* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<FileDescriptorSetChild*>(aActor);
return true;
}
BackgroundChildImpl::PVsyncChild*
BackgroundChildImpl::AllocPVsyncChild()
{
RefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild();
// There still has one ref-count after return, and it will be released in
// DeallocPVsyncChild().
return actor.forget().take();
}
bool
BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor)
{
MOZ_ASSERT(aActor);
// This actor already has one ref-count. Please check AllocPVsyncChild().
RefPtr<mozilla::layout::VsyncChild> actor =
dont_AddRef(static_cast<mozilla::layout::VsyncChild*>(aActor));
return true;
}
PUDPSocketChild*
BackgroundChildImpl::AllocPUDPSocketChild(const OptionalPrincipalInfo& aPrincipalInfo,
const nsCString& aFilter)
{
MOZ_CRASH("AllocPUDPSocket should not be called");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPUDPSocketChild(PUDPSocketChild* child)
{
UDPSocketChild* p = static_cast<UDPSocketChild*>(child);
p->ReleaseIPDLReference();
return true;
}
// -----------------------------------------------------------------------------
// BroadcastChannel API
// -----------------------------------------------------------------------------
dom::PBroadcastChannelChild*
BackgroundChildImpl::AllocPBroadcastChannelChild(const PrincipalInfo& aPrincipalInfo,
const nsCString& aOrigin,
const nsString& aChannel)
{
RefPtr<dom::BroadcastChannelChild> agent =
new dom::BroadcastChannelChild(aOrigin);
return agent.forget().take();
}
bool
BackgroundChildImpl::DeallocPBroadcastChannelChild(
PBroadcastChannelChild* aActor)
{
RefPtr<dom::BroadcastChannelChild> child =
dont_AddRef(static_cast<dom::BroadcastChannelChild*>(aActor));
MOZ_ASSERT(child);
return true;
}
camera::PCamerasChild*
BackgroundChildImpl::AllocPCamerasChild()
{
#ifdef MOZ_WEBRTC
RefPtr<camera::CamerasChild> agent =
new camera::CamerasChild();
return agent.forget().take();
#else
return nullptr;
#endif
}
bool
BackgroundChildImpl::DeallocPCamerasChild(camera::PCamerasChild *aActor)
{
#ifdef MOZ_WEBRTC
RefPtr<camera::CamerasChild> child =
dont_AddRef(static_cast<camera::CamerasChild*>(aActor));
MOZ_ASSERT(aActor);
#endif
return true;
}
// -----------------------------------------------------------------------------
// ServiceWorkerManager
// -----------------------------------------------------------------------------
dom::PServiceWorkerManagerChild*
BackgroundChildImpl::AllocPServiceWorkerManagerChild()
{
RefPtr<dom::workers::ServiceWorkerManagerChild> agent =
new dom::workers::ServiceWorkerManagerChild();
return agent.forget().take();
}
bool
BackgroundChildImpl::DeallocPServiceWorkerManagerChild(
PServiceWorkerManagerChild* aActor)
{
RefPtr<dom::workers::ServiceWorkerManagerChild> child =
dont_AddRef(static_cast<dom::workers::ServiceWorkerManagerChild*>(aActor));
MOZ_ASSERT(child);
return true;
}
// -----------------------------------------------------------------------------
// Cache API
// -----------------------------------------------------------------------------
PCacheStorageChild*
BackgroundChildImpl::AllocPCacheStorageChild(const Namespace& aNamespace,
const PrincipalInfo& aPrincipalInfo)
{
MOZ_CRASH("CacheStorageChild actor must be provided to PBackground manager");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPCacheStorageChild(PCacheStorageChild* aActor)
{
dom::cache::DeallocPCacheStorageChild(aActor);
return true;
}
PCacheChild*
BackgroundChildImpl::AllocPCacheChild()
{
return dom::cache::AllocPCacheChild();
}
bool
BackgroundChildImpl::DeallocPCacheChild(PCacheChild* aActor)
{
dom::cache::DeallocPCacheChild(aActor);
return true;
}
PCacheStreamControlChild*
BackgroundChildImpl::AllocPCacheStreamControlChild()
{
return dom::cache::AllocPCacheStreamControlChild();
}
bool
BackgroundChildImpl::DeallocPCacheStreamControlChild(PCacheStreamControlChild* aActor)
{
dom::cache::DeallocPCacheStreamControlChild(aActor);
return true;
}
// -----------------------------------------------------------------------------
// MessageChannel/MessagePort API
// -----------------------------------------------------------------------------
dom::PMessagePortChild*
BackgroundChildImpl::AllocPMessagePortChild(const nsID& aUUID,
const nsID& aDestinationUUID,
const uint32_t& aSequenceID)
{
RefPtr<dom::MessagePortChild> agent = new dom::MessagePortChild();
return agent.forget().take();
}
bool
BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor)
{
RefPtr<dom::MessagePortChild> child =
dont_AddRef(static_cast<dom::MessagePortChild*>(aActor));
MOZ_ASSERT(child);
return true;
}
PChildToParentStreamChild*
BackgroundChildImpl::AllocPChildToParentStreamChild()
{
MOZ_CRASH("PChildToParentStreamChild actors should be manually constructed!");
}
bool
BackgroundChildImpl::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
{
delete aActor;
return true;
}
PParentToChildStreamChild*
BackgroundChildImpl::AllocPParentToChildStreamChild()
{
return mozilla::ipc::AllocPParentToChildStreamChild();
}
bool
BackgroundChildImpl::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
{
delete aActor;
return true;
}
PAsmJSCacheEntryChild*
BackgroundChildImpl::AllocPAsmJSCacheEntryChild(
const dom::asmjscache::OpenMode& aOpenMode,
const dom::asmjscache::WriteParams& aWriteParams,
const PrincipalInfo& aPrincipalInfo)
{
MOZ_CRASH("PAsmJSCacheEntryChild actors should be manually constructed!");
}
bool
BackgroundChildImpl::DeallocPAsmJSCacheEntryChild(PAsmJSCacheEntryChild* aActor)
{
MOZ_ASSERT(aActor);
dom::asmjscache::DeallocEntryChild(aActor);
return true;
}
BackgroundChildImpl::PQuotaChild*
BackgroundChildImpl::AllocPQuotaChild()
{
MOZ_CRASH("PQuotaChild actor should be manually constructed!");
}
bool
BackgroundChildImpl::DeallocPQuotaChild(PQuotaChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
dom::PFileSystemRequestChild*
BackgroundChildImpl::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
{
MOZ_CRASH("Should never get here!");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aActor)
{
// The reference is increased in FileSystemTaskBase::Start of
// FileSystemTaskBase.cpp. We should decrease it after IPC.
RefPtr<dom::FileSystemTaskChildBase> child =
dont_AddRef(static_cast<dom::FileSystemTaskChildBase*>(aActor));
return true;
}
// Gamepad API Background IPC
dom::PGamepadEventChannelChild*
BackgroundChildImpl::AllocPGamepadEventChannelChild()
{
MOZ_CRASH("PGamepadEventChannelChild actor should be manually constructed!");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPGamepadEventChannelChild(PGamepadEventChannelChild* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<dom::GamepadEventChannelChild*>(aActor);
return true;
}
dom::PGamepadTestChannelChild*
BackgroundChildImpl::AllocPGamepadTestChannelChild()
{
MOZ_CRASH("PGamepadTestChannelChild actor should be manually constructed!");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPGamepadTestChannelChild(PGamepadTestChannelChild* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<dom::GamepadTestChannelChild*>(aActor);
return true;
}
mozilla::dom::PClientManagerChild*
BackgroundChildImpl::AllocPClientManagerChild()
{
return mozilla::dom::AllocClientManagerChild();
}
bool
BackgroundChildImpl::DeallocPClientManagerChild(mozilla::dom::PClientManagerChild* aActor)
{
return mozilla::dom::DeallocClientManagerChild(aActor);
}
#ifdef EARLY_BETA_OR_EARLIER
void
BackgroundChildImpl::OnChannelReceivedMessage(const Message& aMsg)
{
if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
// Not really necessary to look at the message payload, it will be
// <0.5ms away from TimeStamp::Now()
SchedulerGroup::MarkVsyncReceived();
}
}
#endif
dom::PWebAuthnTransactionChild*
BackgroundChildImpl::AllocPWebAuthnTransactionChild()
{
MOZ_CRASH("PWebAuthnTransaction actor should be manually constructed!");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPWebAuthnTransactionChild(PWebAuthnTransactionChild* aActor)
{
MOZ_ASSERT(aActor);
RefPtr<dom::WebAuthnTransactionChildBase> child =
dont_AddRef(static_cast<dom::WebAuthnTransactionChildBase*>(aActor));
return true;
}
net::PHttpBackgroundChannelChild*
BackgroundChildImpl::AllocPHttpBackgroundChannelChild(const uint64_t& aChannelId)
{
MOZ_CRASH("PHttpBackgroundChannelChild actor should be manually constructed!");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPHttpBackgroundChannelChild(PHttpBackgroundChannelChild* aActor)
{
// The reference is increased in BackgroundChannelCreateCallback::ActorCreated
// of HttpBackgroundChannelChild.cpp. We should decrease it after IPC
// destroyed.
RefPtr<net::HttpBackgroundChannelChild> child =
dont_AddRef(static_cast<net::HttpBackgroundChannelChild*>(aActor));
return true;
}
mozilla::ipc::IPCResult
BackgroundChildImpl::RecvDispatchLocalStorageChange(
const nsString& aDocumentURI,
const nsString& aKey,
const nsString& aOldValue,
const nsString& aNewValue,
const PrincipalInfo& aPrincipalInfo,
const bool& aIsPrivate)
{
if (!NS_IsMainThread()) {
return IPC_OK();
}
nsresult rv;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
LocalStorage::DispatchStorageEvent(aDocumentURI, aKey, aOldValue, aNewValue,
principal, aIsPrivate, nullptr, true);
return IPC_OK();
}
bool
BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
{
if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
MOZ_ASSERT(NS_IsMainThread());
aGroups.Clear();
if (dom::TabChild::HasActiveTabs()) {
for (auto iter = dom::TabChild::GetActiveTabs().ConstIter();
!iter.Done(); iter.Next()) {
aGroups.Put(iter.Get()->GetKey()->TabGroup());
}
}
return true;
}
return false;
}
} // namespace ipc
} // namespace mozilla
mozilla::ipc::IPCResult
TestChild::Recv__delete__(const nsCString& aTestArg)
{
MOZ_RELEASE_ASSERT(aTestArg == mTestArg,
"BackgroundTest message was corrupted!");
return IPC_OK();
}