Bug 581341 - Part 1: Make crash report annotation work OOP and subsume existing workarounds. r=cjones

This commit is contained in:
Josh Matthews 2011-06-08 15:56:31 -04:00
parent e8ff002072
commit 03205986fb
21 changed files with 531 additions and 169 deletions

View File

@ -265,8 +265,12 @@ ContentChild::Init(MessageLoop* aIOLoop,
Open(aChannel, aParentHandle, aIOLoop);
sSingleton = this;
#if defined(ANDROID) && defined(MOZ_CRASHREPORTER)
PCrashReporterChild* crashreporter = SendPCrashReporterConstructor();
#ifdef MOZ_CRASHREPORTER
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
XRE_GetProcessType());
#if defined(ANDROID)
PCrashReporterChild* crashreporter = ManagedPCrashReporter()[0];
InfallibleTArray<Mapping> mappings;
const struct mapping_info *info = getLibraryMapping();
while (info && info->name) {
@ -278,6 +282,7 @@ ContentChild::Init(MessageLoop* aIOLoop,
info++;
}
crashreporter->SendAddLibraryMappings(mappings);
#endif
#endif
return true;
@ -418,9 +423,14 @@ ContentChild::DeallocPBrowser(PBrowserChild* iframe)
}
PCrashReporterChild*
ContentChild::AllocPCrashReporter()
ContentChild::AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
const PRUint32& processType)
{
#ifdef MOZ_CRASHREPORTER
return new CrashReporterChild();
#else
return nsnull;
#endif
}
bool

View File

@ -80,8 +80,11 @@ public:
virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags);
virtual bool DeallocPBrowser(PBrowserChild*);
virtual PCrashReporterChild* AllocPCrashReporter();
virtual bool DeallocPCrashReporter(PCrashReporterChild*);
virtual PCrashReporterChild*
AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
const PRUint32& processType);
virtual bool
DeallocPCrashReporter(PCrashReporterChild*);
virtual PMemoryReportRequestChild*
AllocPMemoryReportRequest();

View File

@ -355,27 +355,14 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), PR_TRUE);
#ifdef MOZ_CRASHREPORTER
nsAutoString dumpID;
nsCOMPtr<nsILocalFile> crashDump;
TakeMinidump(getter_AddRefs(crashDump)) &&
CrashReporter::GetIDFromMinidump(crashDump, dumpID);
MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
CrashReporterParent* crashReporter =
static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
crashReporter->GenerateCrashReport(this, NULL);
nsAutoString dumpID(crashReporter->ChildDumpID());
props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
if (!dumpID.IsEmpty()) {
CrashReporter::AnnotationTable notes;
notes.Init();
notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("content"));
char startTime[32];
sprintf(startTime, "%lld", static_cast<long long>(mProcessStartTime));
notes.Put(NS_LITERAL_CSTRING("StartupTime"),
nsDependentCString(startTime));
// TODO: Additional per-process annotations.
CrashReporter::AppendExtraData(dumpID, notes);
}
#endif
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nsnull);
@ -420,7 +407,6 @@ ContentParent::ContentParent()
, mRunToCompletionDepth(0)
, mShouldCallUnblockChild(false)
, mIsAlive(true)
, mProcessStartTime(time(NULL))
, mSendPermissionUpdates(false)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -791,9 +777,23 @@ ContentParent::DeallocPBrowser(PBrowserParent* frame)
}
PCrashReporterParent*
ContentParent::AllocPCrashReporter()
ContentParent::AllocPCrashReporter(const NativeThreadId& tid,
const PRUint32& processType)
{
#ifdef MOZ_CRASHREPORTER
return new CrashReporterParent();
#else
return nsnull;
#endif
}
bool
ContentParent::RecvPCrashReporterConstructor(PCrashReporterParent* actor,
const NativeThreadId& tid,
const PRUint32& processType)
{
static_cast<CrashReporterParent*>(actor)->SetChildData(tid, processType);
return true;
}
bool

View File

@ -99,6 +99,10 @@ public:
void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
GeckoChildProcessHost* Process() {
return mSubprocess;
}
bool NeedsPermissionsUpdate() {
return mSendPermissionUpdates;
}
@ -123,8 +127,12 @@ private:
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags);
virtual bool DeallocPBrowser(PBrowserParent* frame);
virtual PCrashReporterParent* AllocPCrashReporter();
virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
const PRUint32& processType);
virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
virtual bool RecvPCrashReporterConstructor(PCrashReporterParent* actor,
const NativeThreadId& tid,
const PRUint32& processType);
virtual PMemoryReportRequestParent* AllocPMemoryReportRequest();
virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
@ -230,11 +238,12 @@ private:
bool mIsAlive;
nsCOMPtr<nsIPrefServiceInternal> mPrefService;
time_t mProcessStartTime;
bool mSendPermissionUpdates;
nsRefPtr<nsFrameMessageManager> mMessageManager;
friend class CrashReporterParent;
};
} // namespace dom

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set sw=4 ts=8 et tw=80 :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Crash Reporter.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Josh Matthews <josh@joshmatthews.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/plugins/PluginModuleChild.h"
#include "ContentChild.h"
#include "CrashReporterChild.h"
#include "nsXULAppAPI.h"
using mozilla::plugins::PluginModuleChild;
namespace mozilla {
namespace dom {
/*static*/
PCrashReporterChild*
CrashReporterChild::GetCrashReporter()
{
const InfallibleTArray<PCrashReporterChild*>* reporters = nsnull;
switch (XRE_GetProcessType()) {
case GeckoProcessType_Content: {
ContentChild* child = ContentChild::GetSingleton();
reporters = &child->ManagedPCrashReporterChild();
break;
}
case GeckoProcessType_Plugin: {
PluginModuleChild* child = PluginModuleChild::current();
reporters = &child->ManagedPCrashReporterChild();
break;
}
default:
break;
}
if (reporters && reporters->Length() > 0) {
return reporters->ElementAt(0);
}
return nsnull;
}
}
}

View File

@ -36,7 +36,15 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_CrashReporterChild_h
#define mozilla_dom_CrashReporterChild_h
#include "mozilla/dom/PCrashReporterChild.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#include "nsXULAppAPI.h"
#endif
namespace mozilla {
namespace dom {
@ -45,11 +53,16 @@ class CrashReporterChild :
{
public:
CrashReporterChild() {
MOZ_COUNT_CTOR(CrashReporterChild);
MOZ_COUNT_CTOR(CrashReporterChild);
}
virtual ~CrashReporterChild() {
MOZ_COUNT_DTOR(CrashReporterChild);
~CrashReporterChild() {
MOZ_COUNT_DTOR(CrashReporterChild);
}
static PCrashReporterChild* GetCrashReporter();
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_CrashReporterChild_h

View File

@ -37,12 +37,11 @@
*
* ***** END LICENSE BLOCK ***** */
#include "CrashReporterParent.h"
#if defined(MOZ_CRASHREPORTER)
#include "nsExceptionHandler.h"
#endif
#include "base/process_util.h"
#include <time.h>
using namespace base;
namespace mozilla {
@ -73,9 +72,32 @@ CrashReporterParent::RecvAddLibraryMappings(const InfallibleTArray<Mapping>& map
return true;
}
bool
CrashReporterParent::RecvAnnotateCrashReport(const nsCString& key,
const nsCString& data)
{
#ifdef MOZ_CRASHREPORTER
mNotes.Put(key, data);
#endif
return true;
}
bool
CrashReporterParent::RecvAppendAppNotes(const nsCString& data)
{
mAppNotes.Append(data);
return true;
}
CrashReporterParent::CrashReporterParent()
: mStartTime(time(NULL))
, mInitialized(false)
{
MOZ_COUNT_CTOR(CrashReporterParent);
#ifdef MOZ_CRASHREPORTER
mNotes.Init(4);
#endif
}
CrashReporterParent::~CrashReporterParent()
@ -83,5 +105,67 @@ CrashReporterParent::~CrashReporterParent()
MOZ_COUNT_DTOR(CrashReporterParent);
}
void
CrashReporterParent::SetChildData(const NativeThreadId& tid,
const PRUint32& processType)
{
mInitialized = true;
mMainThread = tid;
mProcessType = processType;
}
#ifdef MOZ_CRASHREPORTER
bool
CrashReporterParent::GenerateHangCrashReport(const AnnotationTable* processNotes)
{
if (mChildDumpID.IsEmpty())
return false;
GenerateChildData(processNotes);
CrashReporter::AnnotationTable notes;
if (!notes.Init(4))
return false;
notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
if (!CrashReporter::AppendExtraData(mParentDumpID, notes))
NS_WARNING("problem appending parent data to .extra");
return true;
}
bool
CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
{
MOZ_ASSERT(mInitialized);
nsCAutoString type;
switch (mProcessType) {
case GeckoProcessType_Content:
type = NS_LITERAL_CSTRING("content");
break;
case GeckoProcessType_Plugin:
type = NS_LITERAL_CSTRING("plugin");
break;
default:
NS_ERROR("unknown process type");
break;
}
mNotes.Put(NS_LITERAL_CSTRING("ProcessType"), type);
char startTime[32];
sprintf(startTime, "%lld", static_cast<PRInt64>(mStartTime));
mNotes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime));
if (!mAppNotes.IsEmpty())
mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes);
bool ret = CrashReporter::AppendExtraData(mChildDumpID, mNotes);
if (ret && processNotes)
ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes);
if (!ret)
NS_WARNING("problem appending child data to .extra");
return ret;
}
#endif
} // namespace dom
} // namespace mozilla

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set sw=4 ts=8 et tw=80 :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -37,21 +37,162 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/dom/PCrashReporterParent.h"
#include "mozilla/dom/TabMessageUtils.h"
#include "nsXULAppAPI.h"
#include "nsILocalFile.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
namespace mozilla {
namespace dom {
class ProcessReporter;
class CrashReporterParent :
public PCrashReporterParent
{
#ifdef MOZ_CRASHREPORTER
typedef CrashReporter::AnnotationTable AnnotationTable;
#endif
public:
CrashReporterParent();
virtual ~CrashReporterParent();
CrashReporterParent();
virtual ~CrashReporterParent();
#ifdef MOZ_CRASHREPORTER
/* Attempt to generate a parent/child pair of minidumps from the given
toplevel actor in the event of a hang. Returns true if successful,
false otherwise.
*/
template<class Toplevel>
bool
GeneratePairedMinidump(Toplevel* t);
/* Attempt to create a bare-bones crash report for a hang, along with extra
process-specific annotations present in the given AnnotationTable. Returns
true if successful, false otherwise.
*/
bool
GenerateHangCrashReport(const AnnotationTable* processNotes);
/* Attempt to create a bare-bones crash report, along with extra process-
specific annotations present in the given AnnotationTable. Returns true if
successful, false otherwise.
*/
template<class Toplevel>
bool
GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
/* Instantiate a new crash reporter actor from a given parent that manages
the protocol.
*/
template<class Toplevel>
static void CreateCrashReporter(Toplevel* actor);
#endif
/* Initialize this reporter with data from the child process */
void
SetChildData(const NativeThreadId& id, const PRUint32& processType);
/* Returns the shared hang ID of a parent/child paired minidump.
GeneratePairedMinidump must be called first.
*/
const nsString& HangID() {
return mHangID;
}
/* Returns the ID of the parent minidump.
GeneratePairedMinidump must be called first.
*/
const nsString& ParentDumpID() {
return mParentDumpID;
}
/* Returns the ID of the child minidump.
GeneratePairedMinidump or GenerateCrashReport must be called first.
*/
const nsString& ChildDumpID() {
return mChildDumpID;
}
protected:
virtual void ActorDestroy(ActorDestroyReason why);
virtual bool
RecvAddLibraryMappings(const InfallibleTArray<Mapping>& m);
virtual bool
RecvAnnotateCrashReport(const nsCString& key, const nsCString& data);
virtual bool
RecvAppendAppNotes(const nsCString& data);
#ifdef MOZ_CRASHREPORTER
bool
GenerateChildData(const AnnotationTable* processNotes);
AnnotationTable mNotes;
#endif
nsCString mAppNotes;
nsString mHangID;
nsString mChildDumpID;
nsString mParentDumpID;
NativeThreadId mMainThread;
time_t mStartTime;
PRUint32 mProcessType;
bool mInitialized;
};
#ifdef MOZ_CRASHREPORTER
template<class Toplevel>
inline bool
CrashReporterParent::GeneratePairedMinidump(Toplevel* t)
{
CrashReporter::ProcessHandle child;
#ifdef XP_MACOSX
child = t->Process()->GetChildTask();
#else
child = t->OtherProcess();
#endif
nsCOMPtr<nsILocalFile> childDump;
nsCOMPtr<nsILocalFile> parentDump;
if (CrashReporter::CreatePairedMinidumps(child,
mMainThread,
&mHangID,
getter_AddRefs(childDump),
getter_AddRefs(parentDump)) &&
CrashReporter::GetIDFromMinidump(childDump, mChildDumpID) &&
CrashReporter::GetIDFromMinidump(parentDump, mParentDumpID)) {
return true;
}
return false;
}
template<class Toplevel>
inline bool
CrashReporterParent::GenerateCrashReport(Toplevel* t,
const AnnotationTable* processNotes)
{
nsCOMPtr<nsILocalFile> crashDump;
if (t->TakeMinidump(getter_AddRefs(crashDump)) &&
CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
return GenerateChildData(processNotes);
}
return false;
}
template<class Toplevel>
/* static */ void
CrashReporterParent::CreateCrashReporter(Toplevel* actor)
{
#ifdef MOZ_CRASHREPORTER
NativeThreadId id;
PRUint32 processType;
PCrashReporterParent* p =
actor->CallPCrashReporterConstructor(&id, &processType);
if (p) {
static_cast<CrashReporterParent*>(p)->SetChildData(id, processType);
} else {
NS_ERROR("Error creating crash reporter actor");
}
#endif
}
#endif
} // namespace dom
} // namespace mozilla

View File

@ -65,6 +65,7 @@ EXPORTS_mozilla/dom = \
CrashReporterParent.h \
TabParent.h \
TabChild.h \
TabMessageUtils.h \
$(NULL)
CPPSRCS = \
@ -72,6 +73,7 @@ CPPSRCS = \
ContentParent.cpp \
ContentChild.cpp \
CrashReporterParent.cpp \
CrashReporterChild.cpp \
TabParent.cpp \
TabChild.cpp \
TabMessageUtils.cpp \
@ -88,7 +90,6 @@ CPPSRCS += \
$(NULL)
endif
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk

View File

@ -47,6 +47,7 @@ include protocol PMemoryReportRequest;
include "mozilla/chrome/RegistryMessageUtils.h";
include "mozilla/net/NeckoMessageUtils.h";
include "mozilla/dom/TabMessageUtils.h";
include "nsGeoPositionIPCSerialiser.h";
include "PPrefTuple.h";
@ -60,6 +61,7 @@ using OverrideMapping;
using IPC::URI;
using IPC::Permission;
using mozilla::null_t;
using mozilla::dom::NativeThreadId;
using gfxIntSize;
namespace mozilla {
@ -143,12 +145,13 @@ child:
parent:
PNecko();
PCrashReporter();
PStorage(StorageConstructData data);
PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
sync PCrashReporter(NativeThreadId tid, PRUint32 processType);
// Services remoting
async StartVisitedQuery(URI uri);

View File

@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */
include protocol PContent;
include protocol PPluginModule;
namespace mozilla {
namespace dom {
@ -51,11 +52,13 @@ struct Mapping {
};
protocol PCrashReporter {
manager PContent;
manager PContent or PPluginModule;
parent:
AddLibraryMappings(Mapping[] m);
AnnotateCrashReport(nsCString key, nsCString data);
AppendAppNotes(nsCString data);
__delete__();
};
}
}
}

View File

@ -43,6 +43,10 @@
#include "nsIPrivateDOMEvent.h"
#include "nsCOMPtr.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
namespace mozilla {
namespace dom {
struct RemoteDOMEvent
@ -53,6 +57,13 @@ struct RemoteDOMEvent
bool ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
mozilla::dom::RemoteDOMEvent* aResult);
#ifdef MOZ_CRASHREPORTER
typedef CrashReporter::ThreadId NativeThreadId;
#else
// unused in this case
typedef int32 NativeThreadId;
#endif
}
}
@ -78,7 +89,6 @@ struct ParamTraits<mozilla::dom::RemoteDOMEvent>
}
};
}

View File

@ -40,14 +40,16 @@
include protocol PPluginIdentifier;
include protocol PPluginInstance;
include protocol PPluginScriptableObject;
include protocol PCrashReporter;
include "npapi.h";
include "mozilla/plugins/PluginMessageUtils.h";
include "mozilla/dom/TabMessageUtils.h";
using NPError;
using NPNVariable;
using base::FileDescriptor;
using mozilla::plugins::NativeThreadId;
using mozilla::dom::NativeThreadId;
using mac_plugin_interposing::NSCursorInfo;
using nsID;
@ -58,6 +60,7 @@ rpc protocol PPluginModule
{
manages PPluginInstance;
manages PPluginIdentifier;
manages PCrashReporter;
both:
/**
@ -84,9 +87,8 @@ child:
rpc NP_GetEntryPoints()
returns (NPError rv);
// Return the plugin's thread ID, if it can be found.
rpc NP_Initialize()
returns (NativeThreadId tid, NPError rv);
returns (NPError rv);
rpc PPluginInstance(nsCString aMimeType,
uint16_t aMode,
@ -114,6 +116,9 @@ child:
async SetParentHangTimeout(uint32_t seconds);
rpc PCrashReporter()
returns (NativeThreadId tid, PRUint32 processType);
parent:
/**
* This message is only used on X11 platforms.
@ -141,8 +146,6 @@ parent:
// native events, then "livelock" and some other glitches can occur.
rpc ProcessSomeEvents();
sync AppendNotesToCrashReport(nsCString aNotes);
// OS X Specific calls to manage the plugin's window
// when interposing system calls.
async PluginShowWindow(uint32_t aWindowId, bool aModal,

View File

@ -142,13 +142,6 @@ typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
typedef mozilla::null_t WindowsSharedMemoryHandle;
#endif
#ifdef MOZ_CRASHREPORTER
typedef CrashReporter::ThreadId NativeThreadId;
#else
// unused in this case
typedef int32 NativeThreadId;
#endif
// XXX maybe not the best place for these. better one?
#define VARSTR(v_) case v_: return #v_

View File

@ -66,6 +66,7 @@
#include "mozilla/plugins/BrowserStreamChild.h"
#include "mozilla/plugins/PluginStreamChild.h"
#include "PluginIdentifierChild.h"
#include "mozilla/dom/CrashReporterChild.h"
#include "nsNPAPIPlugin.h"
@ -81,6 +82,8 @@
#endif
using namespace mozilla::plugins;
using mozilla::dom::CrashReporterChild;
using mozilla::dom::PCrashReporterChild;
#if defined(XP_WIN)
const PRUnichar * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
@ -592,7 +595,6 @@ PluginModuleChild::InitGraphics()
// Do this after initializing GDK, or GDK will install its own handler.
XRE_InstallX11ErrorHandler();
#endif
return true;
}
@ -705,6 +707,33 @@ PluginModuleChild::QuickExit()
_exit(0);
}
PCrashReporterChild*
PluginModuleChild::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
PRUint32* processType)
{
return new CrashReporterChild();
}
bool
PluginModuleChild::DeallocPCrashReporter(PCrashReporterChild* actor)
{
delete actor;
return true;
}
bool
PluginModuleChild::AnswerPCrashReporterConstructor(
PCrashReporterChild* actor,
mozilla::dom::NativeThreadId* id,
PRUint32* processType)
{
#ifdef MOZ_CRASHREPORTER
*id = CrashReporter::CurrentThreadId();
*processType = XRE_GetProcessType();
#endif
return true;
}
void
PluginModuleChild::ActorDestroy(ActorDestroyReason why)
{
@ -1801,17 +1830,11 @@ PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
}
bool
PluginModuleChild::AnswerNP_Initialize(NativeThreadId* tid, NPError* _retval)
PluginModuleChild::AnswerNP_Initialize(NPError* _retval)
{
PLUGIN_LOG_DEBUG_METHOD;
AssertPluginThread();
#ifdef MOZ_CRASHREPORTER
*tid = CrashReporter::CurrentThreadId();
#else
*tid = 0;
#endif
#ifdef OS_WIN
SetEventHooks();
#endif

View File

@ -91,6 +91,10 @@ typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFun
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
namespace mozilla {
namespace dom {
class PCrashReporterChild;
}
namespace plugins {
#ifdef MOZ_WIDGET_QT
@ -103,6 +107,7 @@ class PluginInstanceChild;
class PluginModuleChild : public PPluginModuleChild
{
typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
protected:
NS_OVERRIDE
virtual mozilla::ipc::RPCChannel::RacyRPCPolicy
@ -116,7 +121,7 @@ protected:
// Implement the PPluginModuleChild interface
virtual bool AnswerNP_GetEntryPoints(NPError* rv);
virtual bool AnswerNP_Initialize(NativeThreadId* tid, NPError* rv);
virtual bool AnswerNP_Initialize(NPError* rv);
virtual PPluginIdentifierChild*
AllocPPluginIdentifier(const nsCString& aString,
@ -174,6 +179,16 @@ protected:
virtual bool
RecvSetParentHangTimeout(const uint32_t& aSeconds);
virtual PCrashReporterChild*
AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
PRUint32* processType);
virtual bool
DeallocPCrashReporter(PCrashReporterChild* actor);
virtual bool
AnswerPCrashReporterConstructor(PCrashReporterChild* actor,
mozilla::dom::NativeThreadId* id,
PRUint32* processType);
virtual void
ActorDestroy(ActorDestroyReason why);

View File

@ -56,12 +56,13 @@
#include "mozilla/ipc/SyncChannel.h"
#include "mozilla/plugins/PluginModuleParent.h"
#include "mozilla/plugins/BrowserStreamParent.h"
#include "mozilla/dom/PCrashReporterParent.h"
#include "PluginIdentifierParent.h"
#include "nsAutoPtr.h"
#include "nsCRT.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#include "mozilla/dom/CrashReporterParent.h"
#endif
#include "nsNPAPIPlugin.h"
#include "nsILocalFile.h"
@ -74,6 +75,8 @@ using base::KillProcess;
using mozilla::PluginLibrary;
using mozilla::ipc::SyncChannel;
using mozilla::dom::PCrashReporterParent;
using mozilla::dom::CrashReporterParent;
using namespace mozilla;
using namespace mozilla::plugins;
@ -111,19 +114,22 @@ PluginModuleParent::LoadModule(const char* aFilePath)
parent->mSubprocess->GetChildProcessHandle());
TimeoutChanged(kChildTimeoutPref, parent);
#ifdef MOZ_CRASHREPORTER
CrashReporterParent::CreateCrashReporter(parent.get());
#endif
return parent.forget();
}
PluginModuleParent::PluginModuleParent(const char* aFilePath)
: mSubprocess(new PluginProcessParent(aFilePath))
, mPluginThread(0)
, mShutdown(false)
, mClearSiteDataSupported(false)
, mGetSitesWithDataSupported(false)
, mNPNIface(NULL)
, mPlugin(NULL)
, mProcessStartTime(time(NULL))
, mTaskFactory(this)
{
NS_ASSERTION(mSubprocess, "Out of memory!");
@ -164,20 +170,10 @@ PluginModuleParent::~PluginModuleParent()
#ifdef MOZ_CRASHREPORTER
void
PluginModuleParent::WritePluginExtraDataForMinidump(const nsAString& id)
PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
{
typedef nsDependentCString CS;
CrashReporter::AnnotationTable notes;
if (!notes.Init(32))
return;
notes.Put(CS("ProcessType"), CS("plugin"));
char startTime[32];
sprintf(startTime, "%lld", static_cast<PRInt64>(mProcessStartTime));
notes.Put(CS("StartupTime"), CS(startTime));
// Get the plugin filename, try to get just the file leafname
const std::string& pluginFile = mSubprocess->GetPluginFilePath();
size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
@ -192,39 +188,12 @@ PluginModuleParent::WritePluginExtraDataForMinidump(const nsAString& id)
notes.Put(CS("PluginName"), CS(""));
notes.Put(CS("PluginVersion"), CS(""));
if (!mCrashNotes.IsEmpty())
notes.Put(CS("Notes"), CS(mCrashNotes.get()));
if (!mHangID.IsEmpty())
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(mHangID));
if (!CrashReporter::AppendExtraData(id, notes))
NS_WARNING("problem appending plugin data to .extra");
}
void
PluginModuleParent::WriteExtraDataForHang()
{
// this writes HangID
WritePluginExtraDataForMinidump(mPluginDumpID);
CrashReporter::AnnotationTable notes;
if (!notes.Init(4))
return;
notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
if (!CrashReporter::AppendExtraData(mBrowserDumpID, notes))
NS_WARNING("problem appending browser data to .extra");
const nsString& hangID = CrashReporter()->HangID();
if (!hangID.IsEmpty())
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
}
#endif // MOZ_CRASHREPORTER
bool
PluginModuleParent::RecvAppendNotesToCrashReport(const nsCString& aNotes)
{
mCrashNotes.Append(aNotes);
return true;
}
int
PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
{
@ -254,29 +223,16 @@ bool
PluginModuleParent::ShouldContinueFromReplyTimeout()
{
#ifdef MOZ_CRASHREPORTER
nsCOMPtr<nsILocalFile> pluginDump;
nsCOMPtr<nsILocalFile> browserDump;
CrashReporter::ProcessHandle child;
#ifdef XP_MACOSX
child = mSubprocess->GetChildTask();
#else
child = OtherProcess();
#endif
if (CrashReporter::CreatePairedMinidumps(child,
mPluginThread,
&mHangID,
getter_AddRefs(pluginDump),
getter_AddRefs(browserDump)) &&
CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID) &&
CrashReporter::GetIDFromMinidump(browserDump, mBrowserDumpID)) {
CrashReporterParent* crashReporter = CrashReporter();
if (crashReporter->GeneratePairedMinidump(this)) {
mBrowserDumpID = crashReporter->ParentDumpID();
mPluginDumpID = crashReporter->ChildDumpID();
PLUGIN_LOG_DEBUG(
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
NS_ConvertUTF16toUTF8(mHangID).get()));
}
else {
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
} else {
NS_WARNING("failed to capture paired minidumps from hang");
}
#endif
@ -294,21 +250,34 @@ PluginModuleParent::ShouldContinueFromReplyTimeout()
return false;
}
#ifdef MOZ_CRASHREPORTER
CrashReporterParent*
PluginModuleParent::CrashReporter()
{
MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
}
#endif
void
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
{
switch (why) {
case AbnormalShutdown: {
#ifdef MOZ_CRASHREPORTER
nsCOMPtr<nsILocalFile> pluginDump;
if (TakeMinidump(getter_AddRefs(pluginDump)) &&
CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID)) {
CrashReporterParent* crashReporter = CrashReporter();
CrashReporter::AnnotationTable notes;
notes.Init(4);
WriteExtraDataForMinidump(notes);
if (crashReporter->GenerateCrashReport(this, &notes)) {
mPluginDumpID = crashReporter->ChildDumpID();
PLUGIN_LOG_DEBUG(("got child minidump: %s",
NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
WritePluginExtraDataForMinidump(mPluginDumpID);
}
else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
WriteExtraDataForHang();
crashReporter->GenerateHangCrashReport(&notes);
}
else {
NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
@ -781,7 +750,7 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs
return NS_ERROR_FAILURE;
}
if (!CallNP_Initialize(&mPluginThread, error)) {
if (!CallNP_Initialize(error)) {
return NS_ERROR_FAILURE;
}
else if (*error != NPERR_NO_ERROR) {
@ -805,7 +774,7 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
return NS_ERROR_FAILURE;
}
if (!CallNP_Initialize(&mPluginThread, error))
if (!CallNP_Initialize(error))
return NS_ERROR_FAILURE;
#if defined XP_WIN && MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
@ -1106,6 +1075,24 @@ PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
#endif
}
PCrashReporterParent*
PluginModuleParent::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
PRUint32* processType)
{
#ifdef MOZ_CRASHREPORTER
return new CrashReporterParent();
#else
return nsnull;
#endif
}
bool
PluginModuleParent::DeallocPCrashReporter(PCrashReporterParent* actor)
{
delete actor;
return true;
}
bool
PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
{

View File

@ -65,6 +65,11 @@
#include "nsITimer.h"
namespace mozilla {
namespace dom {
class PCrashReporterParent;
class CrashReporterParent;
}
namespace plugins {
//-----------------------------------------------------------------------------
@ -85,6 +90,8 @@ class PluginModuleParent : public PPluginModuleParent, PluginLibrary
{
private:
typedef mozilla::PluginLibrary PluginLibrary;
typedef mozilla::dom::PCrashReporterParent PCrashReporterParent;
typedef mozilla::dom::CrashReporterParent CrashReporterParent;
protected:
@ -184,9 +191,6 @@ protected:
NS_OVERRIDE virtual bool
RecvProcessNativeEventsInRPCCall();
virtual bool
RecvAppendNotesToCrashReport(const nsCString& aNotes);
NS_OVERRIDE virtual bool
RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
const int32_t& aX, const int32_t& aY,
@ -195,6 +199,12 @@ protected:
NS_OVERRIDE virtual bool
RecvPluginHideWindow(const uint32_t& aWindowId);
NS_OVERRIDE virtual PCrashReporterParent*
AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
PRUint32* processType);
NS_OVERRIDE virtual bool
DeallocPCrashReporter(PCrashReporterParent* actor);
NS_OVERRIDE virtual bool
RecvSetCursor(const NSCursorInfo& aCursorInfo);
@ -302,13 +312,15 @@ private:
#endif
private:
void WritePluginExtraDataForMinidump(const nsAString& id);
void WriteExtraDataForHang();
CrashReporterParent* CrashReporter();
#ifdef MOZ_CRASHREPORTER
void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
#endif
void CleanupFromTimeout();
static int TimeoutChanged(const char* aPref, void* aModule);
void NotifyPluginCrashed();
nsCString mCrashNotes;
PluginProcessParent* mSubprocess;
// the plugin thread in mSubprocess
NativeThreadId mPluginThread;
@ -318,7 +330,6 @@ private:
const NPNetscapeFuncs* mNPNIface;
nsDataHashtable<nsVoidPtrHashKey, PluginIdentifierParent*> mIdentifiers;
nsNPAPIPlugin* mPlugin;
time_t mProcessStartTime;
ScopedRunnableMethodFactory<PluginModuleParent> mTaskFactory;
nsString mPluginDumpID;
nsString mBrowserDumpID;
@ -334,6 +345,8 @@ private:
// object instead of the plugin process's lifetime
ScopedClose mPluginXSocketFdDup;
#endif
friend class mozilla::dom::CrashReporterParent;
};
} // namespace plugins

View File

@ -175,17 +175,5 @@ PluginProcessChild::CleanUp()
nsRegion::ShutdownStatic();
}
/* static */
void
PluginProcessChild::AppendNotesToCrashReport(const nsCString& aNotes)
{
AssertPluginThread();
PluginProcessChild* p = PluginProcessChild::current();
if (p) {
p->mPlugin.SendAppendNotesToCrashReport(aNotes);
}
}
} // namespace plugins
} // namespace mozilla

View File

@ -61,9 +61,6 @@ public:
NS_OVERRIDE virtual bool Init();
NS_OVERRIDE virtual void CleanUp();
// For use on the plugin thread.
static void AppendNotesToCrashReport(const nsCString& aNotes);
protected:
static PluginProcessChild* current() {
return static_cast<PluginProcessChild*>(ProcessChild::current());

View File

@ -38,9 +38,6 @@
#include "nsX11ErrorHandler.h"
#include "mozilla/plugins/PluginProcessChild.h"
using mozilla::plugins::PluginProcessChild;
#include "prenv.h"
#include "nsXULAppAPI.h"
#include "nsExceptionHandler.h"
@ -156,15 +153,9 @@ X11Error(Display *display, XErrorEvent *event) {
#ifdef MOZ_CRASHREPORTER
switch (XRE_GetProcessType()) {
case GeckoProcessType_Default:
CrashReporter::AppendAppNotesToCrashReport(notes);
break;
case GeckoProcessType_Plugin:
if (CrashReporter::GetEnabled()) {
// This is assuming that X operations are performed on the plugin
// thread. If plugins are using X on another thread, then we'll need to
// handle that differently.
PluginProcessChild::AppendNotesToCrashReport(notes);
}
case GeckoProcessType_Content:
CrashReporter::AppendAppNotesToCrashReport(notes);
break;
default:
; // crash report notes not supported.