1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_ipc_CrashReporterHost_h 8 #define mozilla_ipc_CrashReporterHost_h 9 10 #include <functional> 11 12 #include "mozilla/UniquePtr.h" 13 #include "mozilla/ipc/Shmem.h" 14 #include "base/process.h" 15 #include "nsExceptionHandler.h" 16 #include "nsThreadUtils.h" 17 18 namespace mozilla { 19 namespace ipc { 20 21 class GeckoChildProcessHost; 22 23 // This is the newer replacement for CrashReporterParent. It is created in 24 // response to a InitCrashReporter message on a top-level actor, and simply 25 // holds the metadata shmem alive until the process ends. When the process 26 // terminates abnormally, the top-level should call GenerateCrashReport to 27 // automatically integrate metadata. 28 class CrashReporterHost { 29 typedef mozilla::ipc::Shmem Shmem; 30 typedef CrashReporter::AnnotationTable AnnotationTable; 31 typedef CrashReporter::ThreadId ThreadId; 32 33 public: 34 template <typename T> 35 class CallbackWrapper { 36 public: Init(std::function<void (T)> && aCallback,bool aAsync)37 void Init(std::function<void(T)>&& aCallback, bool aAsync) { 38 mCallback = Move(aCallback); 39 mAsync = aAsync; 40 if (IsAsync()) { 41 // Don't call do_GetCurrentThread() if this is called synchronously 42 // because 1. it's unnecessary, and 2. more importantly, it might create 43 // one if called from a native thread, and the thread will be leaked. 44 mTargetThread = do_GetCurrentThread(); 45 } 46 } 47 IsEmpty()48 bool IsEmpty() { return !mCallback; } 49 IsAsync()50 bool IsAsync() { return mAsync; } 51 Invoke(T aResult)52 void Invoke(T aResult) { 53 if (IsAsync()) { 54 decltype(mCallback) callback = Move(mCallback); 55 mTargetThread->Dispatch( 56 NS_NewRunnableFunction( 57 "ipc::CrashReporterHost::CallbackWrapper::Invoke", 58 [callback, aResult]() { callback(aResult); }), 59 NS_DISPATCH_NORMAL); 60 } else { 61 MOZ_ASSERT(!mTargetThread); 62 mCallback(aResult); 63 } 64 65 Clear(); 66 } 67 68 private: Clear()69 void Clear() { 70 mCallback = nullptr; 71 mTargetThread = nullptr; 72 mAsync = false; 73 } 74 75 bool mAsync; 76 std::function<void(T)> mCallback; 77 nsCOMPtr<nsIThread> mTargetThread; 78 }; 79 80 CrashReporterHost(GeckoProcessType aProcessType, const Shmem& aShmem, 81 ThreadId aThreadId); 82 83 // Helper function for generating a crash report for a process that probably 84 // crashed (i.e., had an AbnormalShutdown in ActorDestroy). Returns true if 85 // the process has a minidump attached and we were able to generate a report. 86 bool GenerateCrashReport(base::ProcessId aPid); 87 88 // Given an existing minidump for a crashed child process, take ownership of 89 // it from IPDL. After this, FinalizeCrashReport may be called. 90 RefPtr<nsIFile> TakeCrashedChildMinidump(base::ProcessId aPid, 91 uint32_t* aOutSequence); 92 93 // Replace the stored minidump with a new one. After this, 94 // FinalizeCrashReport may be called. 95 bool AdoptMinidump(nsIFile* aFile); 96 97 // If a minidump was already captured (e.g. via the hang reporter), this 98 // finalizes the existing report by attaching metadata and notifying the 99 // crash service. 100 bool FinalizeCrashReport(); 101 102 // Generate a paired minidump. This does not take the crash report, as 103 // GenerateCrashReport does. After this, FinalizeCrashReport may be called. 104 // Minidump(s) can be generated synchronously or asynchronously, specified in 105 // argument aAsync. When the operation completes, aCallback is invoked, where 106 // the callback argument denotes whether the operation succeeded. 107 void GenerateMinidumpAndPair(GeckoChildProcessHost* aChildProcess, 108 nsIFile* aMinidumpToPair, 109 const nsACString& aPairName, 110 std::function<void(bool)>&& aCallback, 111 bool aAsync); 112 113 // This is a static helper function to notify the crash service that a 114 // crash has occurred. When PCrashReporter is removed, we can make this 115 // a member function. This can be called from any thread, and if not 116 // called from the main thread, will post a synchronous message to the 117 // main thread. 118 static void NotifyCrashService(GeckoProcessType aProcessType, 119 const nsString& aChildDumpID, 120 const AnnotationTable* aNotes); 121 122 void AddNote(const nsCString& aKey, const nsCString& aValue); 123 HasMinidump()124 bool HasMinidump() const { return !mDumpID.IsEmpty(); } MinidumpID()125 const nsString& MinidumpID() const { 126 MOZ_ASSERT(HasMinidump()); 127 return mDumpID; 128 } 129 130 private: 131 static void AsyncAddCrash(int32_t aProcessType, int32_t aCrashType, 132 const nsString& aChildDumpID); 133 134 private: 135 CallbackWrapper<bool> mCreateMinidumpCallback; 136 GeckoProcessType mProcessType; 137 Shmem mShmem; 138 ThreadId mThreadId; 139 time_t mStartTime; 140 AnnotationTable mExtraNotes; 141 nsString mDumpID; 142 bool mFinalized; 143 nsCOMPtr<nsIFile> mTargetDump; 144 }; 145 146 } // namespace ipc 147 } // namespace mozilla 148 149 #endif // mozilla_ipc_CrashReporterHost_h 150