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