diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index ad5346759ee..937b5ca7def 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -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 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 diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 09b731f4b01..bb9dab77e36 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -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(); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index d1b2556fbe3..e53c2bf6c9c 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -355,27 +355,14 @@ ContentParent::ActorDestroy(ActorDestroyReason why) props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), PR_TRUE); #ifdef MOZ_CRASHREPORTER - nsAutoString dumpID; - - nsCOMPtr crashDump; - TakeMinidump(getter_AddRefs(crashDump)) && - CrashReporter::GetIDFromMinidump(crashDump, dumpID); + MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0); + CrashReporterParent* crashReporter = + static_cast(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(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(actor)->SetChildData(tid, processType); + return true; } bool diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 4f2c9cf5295..9d608ec96e2 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -99,6 +99,10 @@ public: void SetChildMemoryReporters(const InfallibleTArray& 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 mPrefService; - time_t mProcessStartTime; bool mSendPermissionUpdates; nsRefPtr mMessageManager; + + friend class CrashReporterParent; }; } // namespace dom diff --git a/dom/ipc/CrashReporterChild.cpp b/dom/ipc/CrashReporterChild.cpp new file mode 100644 index 00000000000..a19fa1ac350 --- /dev/null +++ b/dom/ipc/CrashReporterChild.cpp @@ -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 + * + * 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* 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; +} + +} +} diff --git a/dom/ipc/CrashReporterChild.h b/dom/ipc/CrashReporterChild.h index e9b37ac833e..ee91484969d 100644 --- a/dom/ipc/CrashReporterChild.h +++ b/dom/ipc/CrashReporterChild.h @@ -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 diff --git a/dom/ipc/CrashReporterParent.cpp b/dom/ipc/CrashReporterParent.cpp index ea4b1adcf48..0530591bc97 100644 --- a/dom/ipc/CrashReporterParent.cpp +++ b/dom/ipc/CrashReporterParent.cpp @@ -37,12 +37,11 @@ * * ***** END LICENSE BLOCK ***** */ #include "CrashReporterParent.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#endif #include "base/process_util.h" +#include + using namespace base; namespace mozilla { @@ -73,9 +72,32 @@ CrashReporterParent::RecvAddLibraryMappings(const InfallibleTArray& 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(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 diff --git a/dom/ipc/CrashReporterParent.h b/dom/ipc/CrashReporterParent.h index 7c36f099957..9693cca9c3c 100644 --- a/dom/ipc/CrashReporterParent.h +++ b/dom/ipc/CrashReporterParent.h @@ -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 + 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 + bool + GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes); + + /* Instantiate a new crash reporter actor from a given parent that manages + the protocol. + */ + template + 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& 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 +inline bool +CrashReporterParent::GeneratePairedMinidump(Toplevel* t) +{ + CrashReporter::ProcessHandle child; +#ifdef XP_MACOSX + child = t->Process()->GetChildTask(); +#else + child = t->OtherProcess(); +#endif + nsCOMPtr childDump; + nsCOMPtr 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 +inline bool +CrashReporterParent::GenerateCrashReport(Toplevel* t, + const AnnotationTable* processNotes) +{ + nsCOMPtr crashDump; + if (t->TakeMinidump(getter_AddRefs(crashDump)) && + CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) { + return GenerateChildData(processNotes); + } + return false; +} + +template +/* static */ void +CrashReporterParent::CreateCrashReporter(Toplevel* actor) +{ +#ifdef MOZ_CRASHREPORTER + NativeThreadId id; + PRUint32 processType; + PCrashReporterParent* p = + actor->CallPCrashReporterConstructor(&id, &processType); + if (p) { + static_cast(p)->SetChildData(id, processType); + } else { + NS_ERROR("Error creating crash reporter actor"); + } +#endif +} + +#endif + } // namespace dom } // namespace mozilla diff --git a/dom/ipc/Makefile.in b/dom/ipc/Makefile.in index 627109a6db3..4c2dc2f0d13 100644 --- a/dom/ipc/Makefile.in +++ b/dom/ipc/Makefile.in @@ -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 diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 103f23f7554..015830eb8f4 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -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); diff --git a/dom/ipc/PCrashReporter.ipdl b/dom/ipc/PCrashReporter.ipdl index 2dadeeef801..1f249f49b21 100644 --- a/dom/ipc/PCrashReporter.ipdl +++ b/dom/ipc/PCrashReporter.ipdl @@ -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__(); }; } -} \ No newline at end of file +} diff --git a/dom/ipc/TabMessageUtils.h b/dom/ipc/TabMessageUtils.h index 1d36cdee982..0054c046825 100644 --- a/dom/ipc/TabMessageUtils.h +++ b/dom/ipc/TabMessageUtils.h @@ -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 } }; - } diff --git a/dom/plugins/ipc/PPluginModule.ipdl b/dom/plugins/ipc/PPluginModule.ipdl index a0303c44ff2..8fc56c6604b 100644 --- a/dom/plugins/ipc/PPluginModule.ipdl +++ b/dom/plugins/ipc/PPluginModule.ipdl @@ -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, diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h index 32188fc5a51..cc1ab00e9e0 100644 --- a/dom/plugins/ipc/PluginMessageUtils.h +++ b/dom/plugins/ipc/PluginMessageUtils.h @@ -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_ diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index 2139bd6af9b..c117e24794d 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -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 diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h index 2383c387ba1..a146ef6b192 100644 --- a/dom/plugins/ipc/PluginModuleChild.h +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -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); diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index f2628fd1526..1fceef5a97e 100644 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -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(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 pluginDump; - nsCOMPtr 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(ManagedPCrashReporterParent()[0]); +} +#endif + void PluginModuleParent::ActorDestroy(ActorDestroyReason why) { switch (why) { case AbnormalShutdown: { #ifdef MOZ_CRASHREPORTER - nsCOMPtr 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, ¬es)) { + 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(¬es); } 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) { diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 44acb6c54b7..78b70d7564a 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -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 mIdentifiers; nsNPAPIPlugin* mPlugin; - time_t mProcessStartTime; ScopedRunnableMethodFactory 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 diff --git a/dom/plugins/ipc/PluginProcessChild.cpp b/dom/plugins/ipc/PluginProcessChild.cpp index 10ceed13820..d233dbe5d6b 100644 --- a/dom/plugins/ipc/PluginProcessChild.cpp +++ b/dom/plugins/ipc/PluginProcessChild.cpp @@ -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 diff --git a/dom/plugins/ipc/PluginProcessChild.h b/dom/plugins/ipc/PluginProcessChild.h index b334af28e7c..84d96de697d 100644 --- a/dom/plugins/ipc/PluginProcessChild.h +++ b/dom/plugins/ipc/PluginProcessChild.h @@ -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(ProcessChild::current()); diff --git a/toolkit/xre/nsX11ErrorHandler.cpp b/toolkit/xre/nsX11ErrorHandler.cpp index 4ec84081506..24694f13bf9 100644 --- a/toolkit/xre/nsX11ErrorHandler.cpp +++ b/toolkit/xre/nsX11ErrorHandler.cpp @@ -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.