gecko-dev/ipc/glue/BackgroundChildImpl.cpp
Gabriele Svelto aa43fa218e Bug 1831092 - Use the new pull-based API for all crash annotations and remove the global annotations table r=jgilbert,necko-reviewers,media-playback-reviewers,profiler-reviewers,win-reviewers,padenot,handyman,afranchuk,valentin,alwu,sotaro
This changes comes with several different refactorings all rolled into one,
unfotunately I couldn't find a way to pull them apart:
- First of all annotations now can either recorded (that is, we copy the value
  and have the crash reporting code own the copy) or registered. Several
  annotations are changed to use this functionality so that we don't need to
  update them as their value change.
- The code in the exception handler is modified to read the annotations from
  the mozannotation_client crate. This has the unfortunate side-effect that
  we need three different bits of code to serialize them: one for annotations
  read from a child process, one for reading annotations from the main process
  outside of the exception handler and one for reading annotations from the
  main process within the exception handler. As we move to fully
  out-of-process crash reporting the last two methods will go away.
- The mozannotation_client crate now doesn't record annotation types anymore.
  I realized as I was working on this that storing types at runtime has two
  issues: the first one is that buggy code might change the type of an
  annotation (that is record it under two different types at two different
  moments), the second issue is that types might become corrupt during a
  crash, so better enforce them at annotation-writing time. The end result is
  that the mozannotation_* crates now only store byte buffers, track the
  format the data is stored in (null-terminated string, fixed size buffer,
  etc...) but not the type of data each annotation is supposed to contain.
- Which brings us to the next change: concrete types for annotations are now
  enforced when they're written out. If an annotation doesn't match the
  expected type it's skipped. Storing an annotation with the wrong type will
  also trigger an assertion in debug builds.

Differential Revision: https://phabricator.services.mozilla.com/D195248
2024-03-04 10:24:43 +00:00

458 lines
14 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 "BroadcastChannelChild.h"
#ifdef MOZ_WEBRTC
# include "CamerasChild.h"
#endif
#include "mozilla/Assertions.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/dom/ClientManagerActors.h"
#include "mozilla/dom/FileCreatorChild.h"
#include "mozilla/dom/PBackgroundLSDatabaseChild.h"
#include "mozilla/dom/PBackgroundLSObserverChild.h"
#include "mozilla/dom/PBackgroundLSRequestChild.h"
#include "mozilla/dom/PBackgroundLSSimpleRequestChild.h"
#include "mozilla/dom/PBackgroundSDBConnectionChild.h"
#include "mozilla/dom/PFileSystemRequestChild.h"
#include "mozilla/dom/EndpointForReportChild.h"
#include "mozilla/dom/PVsync.h"
#include "mozilla/dom/TemporaryIPCBlobChild.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
#include "mozilla/dom/indexedDB/ThreadLocal.h"
#include "mozilla/dom/quota/PQuotaChild.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerControllerChild.h"
#include "mozilla/dom/RemoteWorkerServiceChild.h"
#include "mozilla/dom/ServiceWorkerChild.h"
#include "mozilla/dom/SharedWorkerChild.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/MessagePortChild.h"
#include "mozilla/dom/ServiceWorkerContainerChild.h"
#include "mozilla/dom/ServiceWorkerManagerChild.h"
#include "mozilla/ipc/PBackgroundTestChild.h"
#include "mozilla/net/PUDPSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "mozilla/dom/WebAuthnTransactionChild.h"
#include "mozilla/dom/MIDIPortChild.h"
#include "mozilla/dom/MIDIManagerChild.h"
#include "nsID.h"
namespace {
class TestChild final : public mozilla::ipc::PBackgroundTestChild {
friend class mozilla::ipc::BackgroundChildImpl;
nsCString mTestArg;
explicit TestChild(const nsACString& aTestArg) : mTestArg(aTestArg) {
MOZ_COUNT_CTOR(TestChild);
}
protected:
~TestChild() override { MOZ_COUNT_DTOR(TestChild); }
public:
mozilla::ipc::IPCResult Recv__delete__(const nsACString& aTestArg) override;
};
} // namespace
namespace mozilla::ipc {
using mozilla::dom::UDPSocketChild;
using mozilla::net::PUDPSocketChild;
using mozilla::dom::PRemoteWorkerChild;
using mozilla::dom::PServiceWorkerChild;
using mozilla::dom::PServiceWorkerContainerChild;
using mozilla::dom::PServiceWorkerRegistrationChild;
using mozilla::dom::RemoteWorkerChild;
using mozilla::dom::StorageDBChild;
using mozilla::dom::cache::PCacheChild;
using mozilla::dom::cache::PCacheStreamControlChild;
using mozilla::dom::WebAuthnTransactionChild;
using mozilla::dom::PMIDIManagerChild;
using mozilla::dom::PMIDIPortChild;
// -----------------------------------------------------------------------------
// 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) {
case MsgDropped:
return;
#define HANDLE_CASE(_result) \
case _result: \
abortMessage.AssignLiteral(#_result); \
break
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!");
}
CrashReporter::RecordAnnotationCString(
CrashReporter::Annotation::ipc_channel_error, aReason);
MOZ_CRASH_UNSAFE_PRINTF("%s: %s", abortMessage.get(), aReason);
}
void BackgroundChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
// May happen on any thread!
}
PBackgroundTestChild* BackgroundChildImpl::AllocPBackgroundTestChild(
const nsACString& aTestArg) {
return new TestChild(aTestArg);
}
bool BackgroundChildImpl::DeallocPBackgroundTestChild(
PBackgroundTestChild* aActor) {
MOZ_ASSERT(aActor);
delete static_cast<TestChild*>(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::PBackgroundLSObserverChild*
BackgroundChildImpl::AllocPBackgroundLSObserverChild(
const uint64_t& aObserverId) {
MOZ_CRASH("PBackgroundLSObserverChild actor should be manually constructed!");
}
bool BackgroundChildImpl::DeallocPBackgroundLSObserverChild(
PBackgroundLSObserverChild* aActor) {
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundLSRequestChild*
BackgroundChildImpl::AllocPBackgroundLSRequestChild(
const LSRequestParams& aParams) {
MOZ_CRASH("PBackgroundLSRequestChild actor should be manually constructed!");
}
bool BackgroundChildImpl::DeallocPBackgroundLSRequestChild(
PBackgroundLSRequestChild* aActor) {
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundLocalStorageCacheChild*
BackgroundChildImpl::AllocPBackgroundLocalStorageCacheChild(
const PrincipalInfo& aPrincipalInfo, const nsACString& aOriginKey,
const uint32_t& aPrivateBrowsingId) {
MOZ_CRASH(
"PBackgroundLocalStorageChild actors should be manually "
"constructed!");
}
bool BackgroundChildImpl::DeallocPBackgroundLocalStorageCacheChild(
PBackgroundLocalStorageCacheChild* aActor) {
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundLSSimpleRequestChild*
BackgroundChildImpl::AllocPBackgroundLSSimpleRequestChild(
const LSSimpleRequestParams& aParams) {
MOZ_CRASH(
"PBackgroundLSSimpleRequestChild actor should be manually "
"constructed!");
}
bool BackgroundChildImpl::DeallocPBackgroundLSSimpleRequestChild(
PBackgroundLSSimpleRequestChild* aActor) {
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundStorageChild*
BackgroundChildImpl::AllocPBackgroundStorageChild(
const nsAString& aProfilePath, const uint32_t& aPrivateBrowsingId) {
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;
}
already_AddRefed<PRemoteWorkerChild>
BackgroundChildImpl::AllocPRemoteWorkerChild(const RemoteWorkerData& aData) {
return MakeAndAddRef<RemoteWorkerChild>(aData);
}
IPCResult BackgroundChildImpl::RecvPRemoteWorkerConstructor(
PRemoteWorkerChild* aActor, const RemoteWorkerData& aData) {
dom::RemoteWorkerChild* actor = static_cast<dom::RemoteWorkerChild*>(aActor);
actor->ExecWorker(aData);
return IPC_OK();
}
dom::PSharedWorkerChild* BackgroundChildImpl::AllocPSharedWorkerChild(
const dom::RemoteWorkerData& aData, const uint64_t& aWindowID,
const dom::MessagePortIdentifier& aPortIdentifier) {
RefPtr<dom::SharedWorkerChild> agent = new dom::SharedWorkerChild();
return agent.forget().take();
}
bool BackgroundChildImpl::DeallocPSharedWorkerChild(
dom::PSharedWorkerChild* aActor) {
RefPtr<dom::SharedWorkerChild> actor =
dont_AddRef(static_cast<dom::SharedWorkerChild*>(aActor));
return true;
}
dom::PTemporaryIPCBlobChild*
BackgroundChildImpl::AllocPTemporaryIPCBlobChild() {
MOZ_CRASH("This is not supposed to be called.");
return nullptr;
}
bool BackgroundChildImpl::DeallocPTemporaryIPCBlobChild(
dom::PTemporaryIPCBlobChild* aActor) {
RefPtr<dom::TemporaryIPCBlobChild> actor =
dont_AddRef(static_cast<dom::TemporaryIPCBlobChild*>(aActor));
return true;
}
dom::PFileCreatorChild* BackgroundChildImpl::AllocPFileCreatorChild(
const nsAString& aFullPath, const nsAString& aType, const nsAString& aName,
const Maybe<int64_t>& aLastModified, const bool& aExistenceCheck,
const bool& aIsFromNsIFile) {
return new dom::FileCreatorChild();
}
bool BackgroundChildImpl::DeallocPFileCreatorChild(PFileCreatorChild* aActor) {
delete static_cast<dom::FileCreatorChild*>(aActor);
return true;
}
PUDPSocketChild* BackgroundChildImpl::AllocPUDPSocketChild(
const Maybe<PrincipalInfo>& aPrincipalInfo, const nsACString& 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 nsACString& aOrigin,
const nsAString& aChannel) {
RefPtr<dom::BroadcastChannelChild> agent = new dom::BroadcastChannelChild();
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);
camera::Shutdown();
#endif
return true;
}
// -----------------------------------------------------------------------------
// ServiceWorkerManager
// -----------------------------------------------------------------------------
dom::PServiceWorkerManagerChild*
BackgroundChildImpl::AllocPServiceWorkerManagerChild() {
RefPtr<dom::ServiceWorkerManagerChild> agent =
new dom::ServiceWorkerManagerChild();
return agent.forget().take();
}
bool BackgroundChildImpl::DeallocPServiceWorkerManagerChild(
PServiceWorkerManagerChild* aActor) {
RefPtr<dom::ServiceWorkerManagerChild> child =
dont_AddRef(static_cast<dom::ServiceWorkerManagerChild*>(aActor));
MOZ_ASSERT(child);
return true;
}
// -----------------------------------------------------------------------------
// Cache API
// -----------------------------------------------------------------------------
already_AddRefed<PCacheChild> BackgroundChildImpl::AllocPCacheChild() {
return dom::cache::AllocPCacheChild();
}
already_AddRefed<PCacheStreamControlChild>
BackgroundChildImpl::AllocPCacheStreamControlChild() {
return dom::cache::AllocPCacheStreamControlChild();
}
// -----------------------------------------------------------------------------
// 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;
}
dom::PWebAuthnTransactionChild*
BackgroundChildImpl::AllocPWebAuthnTransactionChild() {
MOZ_CRASH("PWebAuthnTransaction actor should be manually constructed!");
return nullptr;
}
bool BackgroundChildImpl::DeallocPWebAuthnTransactionChild(
PWebAuthnTransactionChild* aActor) {
MOZ_ASSERT(aActor);
RefPtr<dom::WebAuthnTransactionChild> child =
dont_AddRef(static_cast<dom::WebAuthnTransactionChild*>(aActor));
return true;
}
already_AddRefed<PServiceWorkerChild>
BackgroundChildImpl::AllocPServiceWorkerChild(
const IPCServiceWorkerDescriptor&) {
MOZ_CRASH("Shouldn't be called.");
return {};
}
already_AddRefed<PServiceWorkerContainerChild>
BackgroundChildImpl::AllocPServiceWorkerContainerChild() {
return mozilla::dom::ServiceWorkerContainerChild::Create();
}
already_AddRefed<PServiceWorkerRegistrationChild>
BackgroundChildImpl::AllocPServiceWorkerRegistrationChild(
const IPCServiceWorkerRegistrationDescriptor&) {
MOZ_CRASH("Shouldn't be called.");
return {};
}
dom::PEndpointForReportChild* BackgroundChildImpl::AllocPEndpointForReportChild(
const nsAString& aGroupName, const PrincipalInfo& aPrincipalInfo) {
return new dom::EndpointForReportChild();
}
bool BackgroundChildImpl::DeallocPEndpointForReportChild(
PEndpointForReportChild* aActor) {
MOZ_ASSERT(aActor);
delete static_cast<dom::EndpointForReportChild*>(aActor);
return true;
}
} // namespace mozilla::ipc
mozilla::ipc::IPCResult TestChild::Recv__delete__(const nsACString& aTestArg) {
MOZ_RELEASE_ASSERT(aTestArg == mTestArg,
"BackgroundTest message was corrupted!");
return IPC_OK();
}