зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 2 changesets (bug 1614933) for bc failures at browser_tabicon_after_bg_tab_crash.js.
Backed out changeset 59503d3a702f (bug 1614933) Backed out changeset 578c8ba9598f (bug 1614933)
This commit is contained in:
Родитель
14d6560dd3
Коммит
4646c1f41f
|
@ -3455,9 +3455,9 @@ void ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) {
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvInitCrashReporter(
|
||||
const NativeThreadId& aThreadId) {
|
||||
mCrashReporter =
|
||||
MakeUnique<CrashReporterHost>(GeckoProcessType_Content, aThreadId);
|
||||
Shmem&& aShmem, const NativeThreadId& aThreadId) {
|
||||
mCrashReporter = MakeUnique<CrashReporterHost>(GeckoProcessType_Content,
|
||||
aShmem, aThreadId);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ class ContentParent final
|
|||
virtual void OnChannelError() override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvInitCrashReporter(
|
||||
const NativeThreadId& aThreadId);
|
||||
Shmem&& aShmem, const NativeThreadId& aThreadId);
|
||||
|
||||
PNeckoParent* AllocPNeckoParent();
|
||||
|
||||
|
|
|
@ -889,7 +889,7 @@ parent:
|
|||
|
||||
async PRemoteSpellcheckEngine();
|
||||
|
||||
async InitCrashReporter(NativeThreadId tid);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId tid);
|
||||
|
||||
sync IsSecureURI(uint32_t aType, URIParams aURI, uint32_t aFlags,
|
||||
OriginAttributes aOriginAttributes)
|
||||
|
|
|
@ -18,7 +18,7 @@ intr protocol PGMP
|
|||
manages PGMPStorage;
|
||||
|
||||
parent:
|
||||
async InitCrashReporter(NativeThreadId threadId);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
async PGMPTimer();
|
||||
async PGMPStorage();
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ parent:
|
|||
|
||||
child:
|
||||
|
||||
async InitCrashReporter(NativeThreadId threadId);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
|
||||
async AddMemoryReport(MemoryReport aReport);
|
||||
async FinishMemoryReport(uint32_t aGeneration);
|
||||
|
|
|
@ -88,7 +88,7 @@ child:
|
|||
|
||||
async SetParentHangTimeout(uint32_t seconds);
|
||||
|
||||
intr InitCrashReporter()
|
||||
intr InitCrashReporter(Shmem shmem)
|
||||
returns (NativeThreadId tid);
|
||||
|
||||
async SettingChanged(PluginSettings settings);
|
||||
|
|
|
@ -715,8 +715,8 @@ mozilla::ipc::IPCResult PluginModuleChild::RecvInitPluginFunctionBroker(
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult PluginModuleChild::AnswerInitCrashReporter(
|
||||
mozilla::dom::NativeThreadId* aOutId) {
|
||||
CrashReporterClient::InitSingleton();
|
||||
Shmem&& aShmem, mozilla::dom::NativeThreadId* aOutId) {
|
||||
CrashReporterClient::InitSingletonWithShmem(aShmem);
|
||||
*aOutId = CrashReporter::CurrentThreadId();
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -97,7 +97,7 @@ class PluginModuleChild : public PPluginModuleChild {
|
|||
mozilla::ipc::IPCResult RecvSetParentHangTimeout(const uint32_t& aSeconds);
|
||||
|
||||
mozilla::ipc::IPCResult AnswerInitCrashReporter(
|
||||
mozilla::dom::NativeThreadId* aId);
|
||||
Shmem&& aShmem, mozilla::dom::NativeThreadId* aId);
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
|
|
|
@ -527,15 +527,20 @@ void PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded) {
|
|||
}
|
||||
|
||||
bool PluginModuleChromeParent::InitCrashReporter() {
|
||||
ipc::Shmem shmem;
|
||||
if (!ipc::CrashReporterClient::AllocShmem(this, &shmem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NativeThreadId threadId;
|
||||
if (!CallInitCrashReporter(&threadId)) {
|
||||
if (!CallInitCrashReporter(std::move(shmem), &threadId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mCrashReporterMutex);
|
||||
mCrashReporter =
|
||||
MakeUnique<ipc::CrashReporterHost>(GeckoProcessType_Plugin, threadId);
|
||||
mCrashReporter = MakeUnique<ipc::CrashReporterHost>(GeckoProcessType_Plugin,
|
||||
shmem, threadId);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -120,7 +120,7 @@ child:
|
|||
// Graphics errors, analogous to PContent::GraphicsError
|
||||
async GraphicsError(nsCString aError);
|
||||
|
||||
async InitCrashReporter(NativeThreadId threadId);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
|
||||
async CreateVRProcess();
|
||||
async ShutdownVRProcess();
|
||||
|
|
|
@ -39,7 +39,7 @@ child:
|
|||
async InitComplete();
|
||||
async OpenVRControllerActionPathToParent(nsCString aPath);
|
||||
async OpenVRControllerManifestPathToParent(VRControllerType aType, nsCString aPath);
|
||||
async InitCrashReporter(NativeThreadId threadId);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
async AddMemoryReport(MemoryReport aReport);
|
||||
async FinishMemoryReport(uint32_t aGeneration);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CrashReporterClient.h"
|
||||
#include "CrashReporterMetadataShmem.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -13,7 +14,8 @@ namespace ipc {
|
|||
StaticMutex CrashReporterClient::sLock;
|
||||
StaticRefPtr<CrashReporterClient> CrashReporterClient::sClientSingleton;
|
||||
|
||||
CrashReporterClient::CrashReporterClient() {
|
||||
CrashReporterClient::CrashReporterClient(const Shmem& aShmem)
|
||||
: mMetadata(new CrashReporterMetadataShmem(aShmem)) {
|
||||
MOZ_COUNT_CTOR(CrashReporterClient);
|
||||
}
|
||||
|
||||
|
@ -21,14 +23,27 @@ CrashReporterClient::~CrashReporterClient() {
|
|||
MOZ_COUNT_DTOR(CrashReporterClient);
|
||||
}
|
||||
|
||||
void CrashReporterClient::AnnotateCrashReport(CrashReporter::Annotation aKey,
|
||||
const nsACString& aData) {
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
mMetadata->AnnotateCrashReport(aKey, aData);
|
||||
}
|
||||
|
||||
void CrashReporterClient::AppendAppNotes(const nsACString& aData) {
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
mMetadata->AppendAppNotes(aData);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void CrashReporterClient::InitSingleton() {
|
||||
void CrashReporterClient::InitSingletonWithShmem(const Shmem& aShmem) {
|
||||
{
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
|
||||
MOZ_ASSERT(!sClientSingleton);
|
||||
sClientSingleton = new CrashReporterClient();
|
||||
sClientSingleton = new CrashReporterClient(aShmem);
|
||||
}
|
||||
|
||||
CrashReporter::NotifyCrashReporterClientCreated();
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -11,36 +11,66 @@
|
|||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class CrashReporterMetadataShmem;
|
||||
|
||||
class CrashReporterClient {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrashReporterClient);
|
||||
|
||||
// |aTopLevelProtocol| must have a child-to-parent message:
|
||||
// |aTopLevelProtocol| must be a top-level protocol instance, as sub-actors
|
||||
// do not have AllocUnsafeShmem. It must also have a child-to-parent message:
|
||||
//
|
||||
// async InitCrashReporter(NativeThreadId threadId);
|
||||
// async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
//
|
||||
// The parent-side receive function of this message should save the shmem
|
||||
// somewhere, and when the top-level actor's ActorDestroy runs (or when the
|
||||
// crash reporter needs metadata), the shmem should be parsed.
|
||||
template <typename T>
|
||||
static void InitSingleton(T* aToplevelProtocol) {
|
||||
InitSingleton();
|
||||
Shmem shmem;
|
||||
if (!AllocShmem(aToplevelProtocol, &shmem)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "failed to allocate crash reporter shmem");
|
||||
return;
|
||||
}
|
||||
|
||||
InitSingletonWithShmem(shmem);
|
||||
Unused << aToplevelProtocol->SendInitCrashReporter(
|
||||
CrashReporter::CurrentThreadId());
|
||||
std::move(shmem), CrashReporter::CurrentThreadId());
|
||||
}
|
||||
|
||||
static void InitSingleton();
|
||||
template <typename T>
|
||||
static bool AllocShmem(T* aToplevelProtocol, Shmem* aOutShmem) {
|
||||
// 16KB should be enough for most metadata - see bug 1278717 comment #11.
|
||||
static const size_t kShmemSize = 16 * 1024;
|
||||
|
||||
return aToplevelProtocol->AllocUnsafeShmem(
|
||||
kShmemSize, SharedMemory::TYPE_BASIC, aOutShmem);
|
||||
}
|
||||
|
||||
static void InitSingletonWithShmem(const Shmem& aShmem);
|
||||
|
||||
static void DestroySingleton();
|
||||
static RefPtr<CrashReporterClient> GetSingleton();
|
||||
|
||||
void AnnotateCrashReport(CrashReporter::Annotation aKey,
|
||||
const nsACString& aData);
|
||||
void AppendAppNotes(const nsACString& aData);
|
||||
|
||||
private:
|
||||
explicit CrashReporterClient();
|
||||
explicit CrashReporterClient(const Shmem& aShmem);
|
||||
~CrashReporterClient();
|
||||
|
||||
private:
|
||||
static StaticMutex sLock;
|
||||
static StaticRefPtr<CrashReporterClient> sClientSingleton;
|
||||
|
||||
private:
|
||||
UniquePtr<CrashReporterMetadataShmem> mMetadata;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define mozilla_ipc_CrashReporterHelper_h
|
||||
|
||||
#include "CrashReporterHost.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsICrashService.h"
|
||||
|
@ -18,7 +19,7 @@ namespace ipc {
|
|||
* toplevel protocols representing processes. To use this class, you should:
|
||||
*
|
||||
* 1. Declare a method to initialize the crash reporter in your IPDL:
|
||||
* `async InitCrashReporter(NativeThreadId threadId)`
|
||||
* `async InitCrashReporter(Shmem shmem, NativeThreadId threadId)`
|
||||
*
|
||||
* 2. Inherit from this class, providing the appropriate `GeckoProcessType`
|
||||
* enum value for the template parameter PT.
|
||||
|
@ -32,8 +33,9 @@ template <GeckoProcessType PT>
|
|||
class CrashReporterHelper {
|
||||
public:
|
||||
CrashReporterHelper() : mCrashReporter(nullptr) {}
|
||||
IPCResult RecvInitCrashReporter(const CrashReporter::ThreadId& aThreadId) {
|
||||
mCrashReporter = MakeUnique<ipc::CrashReporterHost>(PT, aThreadId);
|
||||
IPCResult RecvInitCrashReporter(Shmem&& aShmem,
|
||||
const CrashReporter::ThreadId& aThreadId) {
|
||||
mCrashReporter = MakeUnique<ipc::CrashReporterHost>(PT, aShmem, aThreadId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CrashReporterHost.h"
|
||||
#include "CrashReporterMetadataShmem.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
|
@ -57,8 +58,10 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
|
||||
CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
|
||||
const Shmem& aShmem,
|
||||
CrashReporter::ThreadId aThreadId)
|
||||
: mProcessType(aProcessType),
|
||||
mShmem(aShmem),
|
||||
mThreadId(aThreadId),
|
||||
mStartTime(::time(nullptr)),
|
||||
mFinalized(false) {}
|
||||
|
@ -109,14 +112,22 @@ bool CrashReporterHost::FinalizeCrashReport() {
|
|||
MOZ_ASSERT(!mFinalized);
|
||||
MOZ_ASSERT(HasMinidump());
|
||||
|
||||
mExtraAnnotations[CrashReporter::Annotation::ProcessType] =
|
||||
CrashReporter::AnnotationTable annotations;
|
||||
|
||||
annotations[CrashReporter::Annotation::ProcessType] =
|
||||
XRE_ChildProcessTypeToAnnotation(mProcessType);
|
||||
|
||||
char startTime[32];
|
||||
SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
|
||||
mExtraAnnotations[CrashReporter::Annotation::StartupTime] =
|
||||
annotations[CrashReporter::Annotation::StartupTime] =
|
||||
nsDependentCString(startTime);
|
||||
|
||||
// We might not have shmem (for example, when running crashreporter tests).
|
||||
if (mShmem.IsReadable()) {
|
||||
CrashReporterMetadataShmem::ReadAppNotes(mShmem, annotations);
|
||||
}
|
||||
|
||||
MergeCrashAnnotations(mExtraAnnotations, annotations);
|
||||
CrashReporter::WriteExtraFile(mDumpID, mExtraAnnotations);
|
||||
|
||||
RecordCrash(mProcessType, GetCrashType(), mDumpID);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <functional>
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "base/process.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
@ -19,14 +20,16 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
|
||||
// This is the newer replacement for CrashReporterParent. It is created in
|
||||
// response to a InitCrashReporter message on a top-level actor. When the
|
||||
// process terminates abnormally, the top-level should call GenerateCrashReport
|
||||
// to automatically integrate metadata.
|
||||
// response to a InitCrashReporter message on a top-level actor, and simply
|
||||
// holds the metadata shmem alive until the process ends. When the process
|
||||
// terminates abnormally, the top-level should call GenerateCrashReport to
|
||||
// automatically integrate metadata.
|
||||
class CrashReporterHost {
|
||||
typedef mozilla::ipc::Shmem Shmem;
|
||||
typedef CrashReporter::AnnotationTable AnnotationTable;
|
||||
|
||||
public:
|
||||
CrashReporterHost(GeckoProcessType aProcessType,
|
||||
CrashReporterHost(GeckoProcessType aProcessType, const Shmem& aShmem,
|
||||
CrashReporter::ThreadId aThreadId);
|
||||
|
||||
// Helper function for generating a crash report for a process that probably
|
||||
|
@ -118,6 +121,7 @@ class CrashReporterHost {
|
|||
|
||||
private:
|
||||
GeckoProcessType mProcessType;
|
||||
Shmem mShmem;
|
||||
CrashReporter::ThreadId mThreadId;
|
||||
time_t mStartTime;
|
||||
AnnotationTable mExtraAnnotations;
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/* -*- 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 "CrashReporterMetadataShmem.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EnumeratedRange.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
using CrashReporter::Annotation;
|
||||
|
||||
enum class EntryType : uint8_t {
|
||||
None,
|
||||
Annotation,
|
||||
};
|
||||
|
||||
CrashReporterMetadataShmem::CrashReporterMetadataShmem(const Shmem& aShmem)
|
||||
: mShmem(aShmem) {
|
||||
MOZ_COUNT_CTOR(CrashReporterMetadataShmem);
|
||||
}
|
||||
|
||||
CrashReporterMetadataShmem::~CrashReporterMetadataShmem() {
|
||||
MOZ_COUNT_DTOR(CrashReporterMetadataShmem);
|
||||
}
|
||||
|
||||
void CrashReporterMetadataShmem::AnnotateCrashReport(Annotation aKey,
|
||||
const nsACString& aData) {
|
||||
mAnnotations[aKey] = aData;
|
||||
SyncNotesToShmem();
|
||||
}
|
||||
|
||||
void CrashReporterMetadataShmem::AppendAppNotes(const nsACString& aData) {
|
||||
mAppNotes.Append(aData);
|
||||
mAnnotations[Annotation::Notes] = mAppNotes;
|
||||
SyncNotesToShmem();
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS MetadataShmemWriter {
|
||||
public:
|
||||
explicit MetadataShmemWriter(const Shmem& aShmem)
|
||||
: mCursor(aShmem.get<uint8_t>()), mEnd(mCursor + aShmem.Size<uint8_t>()) {
|
||||
*mCursor = uint8_t(EntryType::None);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool WriteAnnotation(Annotation aKey, const nsCString& aValue) {
|
||||
// This shouldn't happen because Commit() guarantees mCursor < mEnd. But
|
||||
// we might as well be safe.
|
||||
if (mCursor >= mEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the current position so we can write the entry type if the entire
|
||||
// entry fits.
|
||||
uint8_t* start = mCursor++;
|
||||
if (!Write(aKey) || !Write(aValue)) {
|
||||
return false;
|
||||
}
|
||||
return Commit(start, EntryType::Annotation);
|
||||
}
|
||||
|
||||
private:
|
||||
// On success, append a new terminal byte. On failure, rollback the cursor.
|
||||
MOZ_MUST_USE bool Commit(uint8_t* aStart, EntryType aType) {
|
||||
MOZ_ASSERT(aStart < mEnd);
|
||||
MOZ_ASSERT(EntryType(*aStart) == EntryType::None);
|
||||
|
||||
if (mCursor >= mEnd) {
|
||||
// No room for a terminating byte - rollback.
|
||||
mCursor = aStart;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Commit the entry and write a new terminal byte.
|
||||
*aStart = uint8_t(aType);
|
||||
*mCursor = uint8_t(EntryType::None);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool Write(const nsCString& aString) {
|
||||
// 32-bit length is okay since our shmems are very small (16K),
|
||||
// a huge write would fail anyway.
|
||||
return Write(static_cast<uint32_t>(aString.Length())) &&
|
||||
Write(aString.get(), aString.Length());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool Write(const T& aT) {
|
||||
return Write(&aT, sizeof(T));
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool Write(const void* aData, size_t aLength) {
|
||||
if (size_t(mEnd - mCursor) < aLength) {
|
||||
return false;
|
||||
}
|
||||
memcpy(mCursor, aData, aLength);
|
||||
mCursor += aLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// The cursor (beginning at start) always points to a single byte
|
||||
// representing the next EntryType. An EntryType is either None,
|
||||
// indicating there are no more entries, or Annotation, meaning
|
||||
// two strings follow.
|
||||
//
|
||||
// Strings are written as a 32-bit length and byte sequence. After each new
|
||||
// entry, a None entry is always appended, and a subsequent entry will
|
||||
// overwrite this byte.
|
||||
uint8_t* mCursor;
|
||||
uint8_t* mEnd;
|
||||
};
|
||||
|
||||
void CrashReporterMetadataShmem::SyncNotesToShmem() {
|
||||
MetadataShmemWriter writer(mShmem);
|
||||
|
||||
for (auto key : MakeEnumeratedRange(Annotation::Count)) {
|
||||
if (!mAnnotations[key].IsEmpty()) {
|
||||
if (!writer.WriteAnnotation(key, mAnnotations[key])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class to iterate over metadata entries encoded in shmem.
|
||||
class MOZ_STACK_CLASS MetadataShmemReader {
|
||||
public:
|
||||
explicit MetadataShmemReader(const Shmem& aShmem)
|
||||
: mEntryType(EntryType::None) {
|
||||
mCursor = aShmem.get<uint8_t>();
|
||||
mEnd = mCursor + aShmem.Size<uint8_t>();
|
||||
|
||||
// Advance to the first item, if any.
|
||||
Next();
|
||||
}
|
||||
|
||||
bool Done() const { return mCursor >= mEnd || Type() == EntryType::None; }
|
||||
EntryType Type() const { return mEntryType; }
|
||||
void Next() {
|
||||
if (mCursor < mEnd) {
|
||||
mEntryType = EntryType(*mCursor++);
|
||||
} else {
|
||||
mEntryType = EntryType::None;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Read(T* aOut) {
|
||||
return Read(aOut, sizeof(T));
|
||||
}
|
||||
|
||||
bool Read(nsCString& aOut) {
|
||||
uint32_t length = 0;
|
||||
if (!Read(&length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* src = Read(length);
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOut.Assign((const char*)src, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Read(void* aOut, size_t aLength) {
|
||||
const uint8_t* src = Read(aLength);
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
memcpy(aOut, src, aLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If buffer has |aLength| bytes, return cursor and then advance it.
|
||||
// Otherwise, return null.
|
||||
const uint8_t* Read(size_t aLength) {
|
||||
if (size_t(mEnd - mCursor) < aLength) {
|
||||
return nullptr;
|
||||
}
|
||||
const uint8_t* result = mCursor;
|
||||
mCursor += aLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t* mCursor;
|
||||
const uint8_t* mEnd;
|
||||
EntryType mEntryType;
|
||||
};
|
||||
|
||||
void CrashReporterMetadataShmem::ReadAppNotes(const Shmem& aShmem,
|
||||
AnnotationTable& aNotes) {
|
||||
for (MetadataShmemReader reader(aShmem); !reader.Done(); reader.Next()) {
|
||||
switch (reader.Type()) {
|
||||
case EntryType::Annotation: {
|
||||
Annotation key;
|
||||
nsCString value;
|
||||
if (!reader.Read(&key) || !reader.Read(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key >= Annotation::Count) {
|
||||
return;
|
||||
}
|
||||
|
||||
aNotes[key] = value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_ASSERTION(false, "Unknown metadata entry type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_CrashReporterMetadataShmem_h
|
||||
#define mozilla_ipc_CrashReporterMetadataShmem_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class CrashReporterMetadataShmem {
|
||||
typedef mozilla::ipc::Shmem Shmem;
|
||||
typedef CrashReporter::AnnotationTable AnnotationTable;
|
||||
|
||||
public:
|
||||
explicit CrashReporterMetadataShmem(const Shmem& aShmem);
|
||||
~CrashReporterMetadataShmem();
|
||||
|
||||
// Metadata writers. These must only be called in child processes.
|
||||
void AnnotateCrashReport(CrashReporter::Annotation aKey,
|
||||
const nsACString& aData);
|
||||
void AppendAppNotes(const nsACString& aData);
|
||||
|
||||
static void ReadAppNotes(const Shmem& aShmem,
|
||||
CrashReporter::AnnotationTable& aNotes);
|
||||
|
||||
private:
|
||||
void SyncNotesToShmem();
|
||||
|
||||
private:
|
||||
Shmem mShmem;
|
||||
|
||||
AnnotationTable mAnnotations;
|
||||
nsCString mAppNotes;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_CrashReporterMetadataShmem_h
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "mozilla/ipc/IdleSchedulerChild.h"
|
||||
#include "mozilla/ipc/IdleSchedulerParent.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/IdlePeriodState.h"
|
||||
#include "BackgroundChild.h"
|
||||
|
|
|
@ -19,6 +19,7 @@ EXPORTS.mozilla.ipc += [
|
|||
'CrashReporterClient.h',
|
||||
'CrashReporterHelper.h',
|
||||
'CrashReporterHost.h',
|
||||
'CrashReporterMetadataShmem.h',
|
||||
'CrossProcessMutex.h',
|
||||
'CrossProcessSemaphore.h',
|
||||
'EnvironmentMap.h',
|
||||
|
@ -151,6 +152,7 @@ UNIFIED_SOURCES += [
|
|||
'BrowserProcessSubThread.cpp',
|
||||
'CrashReporterClient.cpp',
|
||||
'CrashReporterHost.cpp',
|
||||
'CrashReporterMetadataShmem.cpp',
|
||||
'FileDescriptor.cpp',
|
||||
'FileDescriptorUtils.cpp',
|
||||
'IdleSchedulerChild.cpp',
|
||||
|
|
|
@ -50,7 +50,7 @@ protocol PSocketProcess
|
|||
manages PAltSvcTransaction;
|
||||
|
||||
parent:
|
||||
async InitCrashReporter(NativeThreadId threadId);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
async AddMemoryReport(MemoryReport aReport);
|
||||
async FinishMemoryReport(uint32_t aGeneration);
|
||||
// Messages for sending telemetry to parent process.
|
||||
|
|
|
@ -19,6 +19,10 @@ class MemoryReport;
|
|||
class MemoryReportRequestHost;
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
class CrashReporterHost;
|
||||
} // namespace ipc
|
||||
|
||||
namespace net {
|
||||
|
||||
class SocketProcessHost;
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
|
@ -501,14 +500,6 @@ void SandboxEarlyInit() {
|
|||
}
|
||||
}
|
||||
|
||||
static void RunGlibcLazyInitializers() {
|
||||
// Make glibc's lazy initialization of shm_open() run before sandboxing
|
||||
int fd = shm_open("/dummy", O_RDONLY, 0);
|
||||
if (fd > 0) {
|
||||
close(fd); // In the unlikely case we actually opened something
|
||||
}
|
||||
}
|
||||
|
||||
static void SandboxLateInit() {
|
||||
#ifdef NIGHTLY_BUILD
|
||||
gSandboxCrashOnError = true;
|
||||
|
@ -525,8 +516,6 @@ static void SandboxLateInit() {
|
|||
gSandboxCrashOnError = envVar[0] != '0';
|
||||
}
|
||||
}
|
||||
|
||||
RunGlibcLazyInitializers();
|
||||
}
|
||||
|
||||
// Common code for sandbox startup.
|
||||
|
|
|
@ -26,7 +26,7 @@ struct LaunchParameters {
|
|||
intr protocol PRemoteSandboxBroker
|
||||
{
|
||||
parent:
|
||||
async InitCrashReporter(NativeThreadId threadId);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
child:
|
||||
intr LaunchApp(LaunchParameters params)
|
||||
returns (bool ok, uint64_t handle);
|
||||
|
|
|
@ -39,6 +39,8 @@ nsresult SetupExtraData(nsIFile* aAppDataDirectory,
|
|||
|
||||
nsresult UnsetExceptionHandler() { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
void NotifyCrashReporterClientCreated() {}
|
||||
|
||||
nsresult AnnotateCrashReport(Annotation key, bool data) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/ipc/CrashReporterClient.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsThread.h"
|
||||
|
@ -121,6 +122,7 @@ using google_breakpad::kDefaultBuildIdSize;
|
|||
using google_breakpad::PageAllocator;
|
||||
#endif
|
||||
using namespace mozilla;
|
||||
using mozilla::ipc::CrashReporterClient;
|
||||
|
||||
namespace CrashReporter {
|
||||
|
||||
|
@ -310,6 +312,11 @@ class ReportInjectedCrash : public Runnable {
|
|||
};
|
||||
#endif // MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
// If annotations are attempted before the crash reporter is enabled,
|
||||
// they queue up here.
|
||||
class DelayedNote;
|
||||
nsTArray<UniquePtr<DelayedNote> >* gDelayedAnnotations;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// the following are used to prevent other DLLs reverting the last chance
|
||||
// exception handler to the windows default. Any attempt to change the
|
||||
|
@ -1296,21 +1303,16 @@ static void WriteMozCrashReason(AnnotationWriter& aWriter) {
|
|||
}
|
||||
}
|
||||
|
||||
static void WriteAnnotations(AnnotationWriter& writer,
|
||||
const AnnotationTable& aAnnotations) {
|
||||
for (auto key : MakeEnumeratedRange(Annotation::Count)) {
|
||||
const nsCString& value = aAnnotations[key];
|
||||
if (!value.IsEmpty()) {
|
||||
writer.Write(key, value.get(), value.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteAnnotationsForMainProcessCrash(PlatformWriter& pw,
|
||||
const phc::AddrInfo* addrInfo,
|
||||
time_t crashTime) {
|
||||
JSONAnnotationWriter writer(pw);
|
||||
WriteAnnotations(writer, crashReporterAPIData_Table);
|
||||
for (auto key : MakeEnumeratedRange(Annotation::Count)) {
|
||||
const nsCString& value = crashReporterAPIData_Table[key];
|
||||
if (!value.IsEmpty()) {
|
||||
writer.Write(key, value.get(), value.Length());
|
||||
}
|
||||
}
|
||||
|
||||
char crashTimeString[32];
|
||||
XP_TTOA(crashTime, crashTimeString);
|
||||
|
@ -1675,8 +1677,6 @@ static void PrepareChildExceptionTimeAnnotations(
|
|||
}
|
||||
};
|
||||
GetFlatThreadAnnotation(getThreadAnnotationCB, true);
|
||||
|
||||
WriteAnnotations(writer, crashReporterAPIData_Table);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -1830,29 +1830,6 @@ static nsresult LocateExecutable(nsIFile* aXREDirectory,
|
|||
|
||||
#endif // !defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
static void InitializeAnnotationFacilities() {
|
||||
crashReporterAPILock = new Mutex("crashReporterAPILock");
|
||||
notesFieldLock = new Mutex("notesFieldLock");
|
||||
notesField = new nsCString();
|
||||
InitThreadAnnotation();
|
||||
}
|
||||
|
||||
static void TeardownAnnotationFacilities() {
|
||||
std::fill(crashReporterAPIData_Table.begin(),
|
||||
crashReporterAPIData_Table.end(), EmptyCString());
|
||||
|
||||
delete crashReporterAPILock;
|
||||
crashReporterAPILock = nullptr;
|
||||
|
||||
delete notesFieldLock;
|
||||
notesFieldLock = nullptr;
|
||||
|
||||
delete notesField;
|
||||
notesField = nullptr;
|
||||
|
||||
ShutdownThreadAnnotation();
|
||||
}
|
||||
|
||||
nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force /*=false*/) {
|
||||
if (gExceptionHandler) return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
|
@ -1872,7 +1849,13 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force /*=false*/) {
|
|||
// the crash reporter client
|
||||
doReport = ShouldReport();
|
||||
|
||||
InitializeAnnotationFacilities();
|
||||
NS_ASSERTION(!crashReporterAPILock, "Shouldn't have a lock yet");
|
||||
crashReporterAPILock = new Mutex("crashReporterAPILock");
|
||||
NS_ASSERTION(!notesFieldLock, "Shouldn't have a lock yet");
|
||||
notesFieldLock = new Mutex("notesFieldLock");
|
||||
|
||||
notesField = new nsCString();
|
||||
NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
// Locate the crash reporter executable
|
||||
|
@ -2052,6 +2035,8 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force /*=false*/) {
|
|||
|
||||
oldTerminateHandler = std::set_terminate(&TerminateHandler);
|
||||
|
||||
InitThreadAnnotation();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2297,7 +2282,19 @@ nsresult UnsetExceptionHandler() {
|
|||
|
||||
delete gExceptionHandler;
|
||||
|
||||
TeardownAnnotationFacilities();
|
||||
// do this here in the unlikely case that we succeeded in allocating
|
||||
// our strings but failed to allocate gExceptionHandler.
|
||||
std::fill(crashReporterAPIData_Table.begin(),
|
||||
crashReporterAPIData_Table.end(), EmptyCString());
|
||||
|
||||
delete crashReporterAPILock;
|
||||
crashReporterAPILock = nullptr;
|
||||
|
||||
delete notesFieldLock;
|
||||
notesFieldLock = nullptr;
|
||||
|
||||
delete notesField;
|
||||
notesField = nullptr;
|
||||
|
||||
if (pendingDirectory) {
|
||||
free(pendingDirectory);
|
||||
|
@ -2326,6 +2323,8 @@ nsresult UnsetExceptionHandler() {
|
|||
memoryReportPath = nullptr;
|
||||
}
|
||||
|
||||
ShutdownThreadAnnotation();
|
||||
|
||||
if (!gExceptionHandler) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
gExceptionHandler = nullptr;
|
||||
|
@ -2340,6 +2339,45 @@ nsresult UnsetExceptionHandler() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class DelayedNote {
|
||||
public:
|
||||
DelayedNote(Annotation aKey, const nsACString& aData)
|
||||
: mKey(aKey), mData(aData), mType(CrashAnnotation) {}
|
||||
|
||||
explicit DelayedNote(const nsACString& aData)
|
||||
: mData(aData), mType(AppNote) {}
|
||||
|
||||
void Run() {
|
||||
if (mType == CrashAnnotation) {
|
||||
AnnotateCrashReport(mKey, mData);
|
||||
} else {
|
||||
AppendAppNotesToCrashReport(mData);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Annotation mKey;
|
||||
nsCString mData;
|
||||
enum AnnotationType { CrashAnnotation, AppNote } mType;
|
||||
};
|
||||
|
||||
static void EnqueueDelayedNote(DelayedNote* aNote) {
|
||||
if (!gDelayedAnnotations) {
|
||||
gDelayedAnnotations = new nsTArray<UniquePtr<DelayedNote> >();
|
||||
}
|
||||
gDelayedAnnotations->AppendElement(WrapUnique(aNote));
|
||||
}
|
||||
|
||||
void NotifyCrashReporterClientCreated() {
|
||||
if (gDelayedAnnotations) {
|
||||
for (const auto& note : *gDelayedAnnotations) {
|
||||
note->Run();
|
||||
}
|
||||
delete gDelayedAnnotations;
|
||||
gDelayedAnnotations = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult AnnotateCrashReport(Annotation key, bool data) {
|
||||
return AnnotateCrashReport(
|
||||
key, data ? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0"));
|
||||
|
@ -2362,6 +2400,21 @@ nsresult AnnotateCrashReport(Annotation key, unsigned int data) {
|
|||
nsresult AnnotateCrashReport(Annotation key, const nsACString& data) {
|
||||
if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
// The newer CrashReporterClient can be used from any thread.
|
||||
if (RefPtr<CrashReporterClient> client =
|
||||
CrashReporterClient::GetSingleton()) {
|
||||
client->AnnotateCrashReport(key, data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// EnqueueDelayedNote() can only be called on the main thread.
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
EnqueueDelayedNote(new DelayedNote(key, data));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(*crashReporterAPILock);
|
||||
crashReporterAPIData_Table[key] = data;
|
||||
|
||||
|
@ -2383,10 +2436,10 @@ void MergeCrashAnnotations(AnnotationTable& aDst, const AnnotationTable& aSrc) {
|
|||
}
|
||||
}
|
||||
|
||||
static void MergeContentCrashAnnotations(AnnotationTable& aDst) {
|
||||
MutexAutoLock lock(*crashReporterAPILock);
|
||||
static void MergeContentCrashAnnotations(AnnotationTable& aDst,
|
||||
const AnnotationTable& aSrc) {
|
||||
for (auto key : MakeEnumeratedRange(Annotation::Count)) {
|
||||
const nsCString& value = crashReporterAPIData_Table[key];
|
||||
const nsCString& value = aSrc[key];
|
||||
if (value.IsEmpty() || IsAnnotationBlacklistedForContent(key)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2432,6 +2485,20 @@ void SetMinidumpAnalysisAllThreads() {
|
|||
nsresult AppendAppNotesToCrashReport(const nsACString& data) {
|
||||
if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
if (RefPtr<CrashReporterClient> client =
|
||||
CrashReporterClient::GetSingleton()) {
|
||||
client->AppendAppNotes(data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// EnqueueDelayedNote can only be called on the main thread.
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
EnqueueDelayedNote(new DelayedNote(data));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(*notesFieldLock);
|
||||
|
||||
notesField->Append(data);
|
||||
|
@ -3089,7 +3156,12 @@ static bool WriteExtraFile(PlatformWriter pw,
|
|||
}
|
||||
|
||||
JSONAnnotationWriter writer(pw);
|
||||
WriteAnnotations(writer, aAnnotations);
|
||||
for (auto key : MakeEnumeratedRange(Annotation::Count)) {
|
||||
const nsCString& value = aAnnotations[key];
|
||||
if (!value.IsEmpty()) {
|
||||
writer.Write(key, value.get(), value.Length());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3119,14 +3191,19 @@ static void ReadExceptionTimeAnnotations(AnnotationTable& aAnnotations,
|
|||
if (aPid && processToCrashFd.count(aPid)) {
|
||||
PRFileDesc* prFd = processToCrashFd[aPid];
|
||||
processToCrashFd.erase(aPid);
|
||||
ReadAndValidateExceptionTimeAnnotations(prFd, aAnnotations);
|
||||
AnnotationTable exceptionTimeAnnotations;
|
||||
ReadAndValidateExceptionTimeAnnotations(prFd, exceptionTimeAnnotations);
|
||||
MergeCrashAnnotations(aAnnotations, exceptionTimeAnnotations);
|
||||
PR_Close(prFd);
|
||||
}
|
||||
}
|
||||
|
||||
static void PopulateContentProcessAnnotations(AnnotationTable& aAnnotations,
|
||||
uint32_t aPid) {
|
||||
MergeContentCrashAnnotations(aAnnotations);
|
||||
{
|
||||
MutexAutoLock lock(*crashReporterAPILock);
|
||||
MergeContentCrashAnnotations(aAnnotations, crashReporterAPIData_Table);
|
||||
}
|
||||
AddCommonAnnotations(aAnnotations);
|
||||
ReadExceptionTimeAnnotations(aAnnotations, aPid);
|
||||
}
|
||||
|
@ -3435,8 +3512,6 @@ bool SetRemoteExceptionHandler(const char* aCrashPipe,
|
|||
uintptr_t aCrashTimeAnnotationFile) {
|
||||
MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
|
||||
|
||||
InitializeAnnotationFacilities();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
gExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
L"", ChildFPEFilter,
|
||||
|
@ -3472,6 +3547,8 @@ bool SetRemoteExceptionHandler(const char* aCrashPipe,
|
|||
|
||||
oldTerminateHandler = std::set_terminate(&TerminateHandler);
|
||||
|
||||
InitThreadAnnotation();
|
||||
|
||||
// we either do remote or nothing, no fallback to regular crash reporting
|
||||
return gExceptionHandler->IsOutOfProcess();
|
||||
}
|
||||
|
@ -3745,7 +3822,12 @@ bool CreateMinidumpsAndPair(ProcessHandle aTargetPid,
|
|||
DllBlocklist_Shutdown();
|
||||
#endif
|
||||
|
||||
MergeContentCrashAnnotations(aTargetAnnotations);
|
||||
{
|
||||
MutexAutoLock lock(*crashReporterAPILock);
|
||||
MergeContentCrashAnnotations(aTargetAnnotations,
|
||||
crashReporterAPIData_Table);
|
||||
}
|
||||
|
||||
AddCommonAnnotations(aTargetAnnotations);
|
||||
|
||||
targetMinidump.forget(aMainDumpOut);
|
||||
|
@ -3799,8 +3881,7 @@ bool UnsetRemoteExceptionHandler() {
|
|||
delete gExceptionHandler;
|
||||
gExceptionHandler = nullptr;
|
||||
#endif
|
||||
TeardownAnnotationFacilities();
|
||||
|
||||
ShutdownThreadAnnotation();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,10 @@ nsresult AnnotateCrashReport(Annotation key, const nsACString& data);
|
|||
nsresult RemoveCrashReportAnnotation(Annotation key);
|
||||
nsresult AppendAppNotesToCrashReport(const nsACString& data);
|
||||
|
||||
// Called after the crash reporter client has been created in a content
|
||||
// process, allowing annotations to be processed.
|
||||
void NotifyCrashReporterClientCreated();
|
||||
|
||||
void AnnotateOOMAllocationSize(size_t size);
|
||||
void AnnotateTexturesSize(size_t size);
|
||||
nsresult SetGarbageCollecting(bool collecting);
|
||||
|
|
Загрузка…
Ссылка в новой задаче