/* -*- 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(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(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 actor = dont_AddRef(static_cast(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 actor = new mozilla::dom::IPCBlobInputStreamChild(aID, aSize); return actor.forget().take(); } bool BackgroundChildImpl::DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor) { RefPtr actor = dont_AddRef(static_cast(aActor)); return true; } PFileDescriptorSetChild* BackgroundChildImpl::AllocPFileDescriptorSetChild( const FileDescriptor& aFileDescriptor) { return new FileDescriptorSetChild(aFileDescriptor); } bool BackgroundChildImpl::DeallocPFileDescriptorSetChild( PFileDescriptorSetChild* aActor) { MOZ_ASSERT(aActor); delete static_cast(aActor); return true; } BackgroundChildImpl::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() { RefPtr 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 actor = dont_AddRef(static_cast(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(child); p->ReleaseIPDLReference(); return true; } // ----------------------------------------------------------------------------- // BroadcastChannel API // ----------------------------------------------------------------------------- dom::PBroadcastChannelChild* BackgroundChildImpl::AllocPBroadcastChannelChild(const PrincipalInfo& aPrincipalInfo, const nsCString& aOrigin, const nsString& aChannel) { RefPtr agent = new dom::BroadcastChannelChild(aOrigin); return agent.forget().take(); } bool BackgroundChildImpl::DeallocPBroadcastChannelChild( PBroadcastChannelChild* aActor) { RefPtr child = dont_AddRef(static_cast(aActor)); MOZ_ASSERT(child); return true; } camera::PCamerasChild* BackgroundChildImpl::AllocPCamerasChild() { #ifdef MOZ_WEBRTC RefPtr agent = new camera::CamerasChild(); return agent.forget().take(); #else return nullptr; #endif } bool BackgroundChildImpl::DeallocPCamerasChild(camera::PCamerasChild *aActor) { #ifdef MOZ_WEBRTC RefPtr child = dont_AddRef(static_cast(aActor)); MOZ_ASSERT(aActor); #endif return true; } // ----------------------------------------------------------------------------- // ServiceWorkerManager // ----------------------------------------------------------------------------- dom::PServiceWorkerManagerChild* BackgroundChildImpl::AllocPServiceWorkerManagerChild() { RefPtr agent = new dom::workers::ServiceWorkerManagerChild(); return agent.forget().take(); } bool BackgroundChildImpl::DeallocPServiceWorkerManagerChild( PServiceWorkerManagerChild* aActor) { RefPtr child = dont_AddRef(static_cast(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 agent = new dom::MessagePortChild(); return agent.forget().take(); } bool BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor) { RefPtr child = dont_AddRef(static_cast(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 child = dont_AddRef(static_cast(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(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(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 child = dont_AddRef(static_cast(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 child = dont_AddRef(static_cast(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 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(); }