Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "gfxCrashReporterUtils.h"
7 :
8 : #if defined(MOZ_CRASHREPORTER)
9 : #define MOZ_GFXFEATUREREPORTER 1
10 : #endif
11 :
12 : #ifdef MOZ_GFXFEATUREREPORTER
13 : #include "gfxCrashReporterUtils.h"
14 : #include <string.h> // for strcmp
15 : #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
16 : #include "mozilla/Services.h" // for GetObserverService
17 : #include "mozilla/StaticMutex.h"
18 : #include "mozilla/SystemGroup.h" // for SystemGroup
19 : #include "mozilla/mozalloc.h" // for operator new, etc
20 : #include "mozilla/RefPtr.h" // for RefPtr
21 : #include "MainThreadUtils.h" // for NS_IsMainThread
22 : #include "nsCOMPtr.h" // for nsCOMPtr
23 : #include "nsError.h" // for NS_OK, NS_FAILED, nsresult
24 : #include "nsExceptionHandler.h" // for AppendAppNotesToCrashReport
25 : #include "nsID.h"
26 : #include "nsIEventTarget.h" // for NS_DISPATCH_NORMAL
27 : #include "nsIObserver.h" // for nsIObserver, etc
28 : #include "nsIObserverService.h" // for nsIObserverService
29 : #include "nsIRunnable.h" // for nsIRunnable
30 : #include "nsISupports.h"
31 : #include "nsTArray.h" // for nsTArray
32 : #include "nscore.h" // for NS_IMETHOD, NS_IMETHODIMP, etc
33 :
34 : namespace mozilla {
35 :
36 : static nsTArray<nsCString> *gFeaturesAlreadyReported = nullptr;
37 3 : static StaticMutex gFeaturesAlreadyReportedMutex;
38 :
39 : class ObserverToDestroyFeaturesAlreadyReported final : public nsIObserver
40 : {
41 :
42 : public:
43 : NS_DECL_ISUPPORTS
44 : NS_DECL_NSIOBSERVER
45 :
46 2 : ObserverToDestroyFeaturesAlreadyReported() {}
47 : private:
48 0 : virtual ~ObserverToDestroyFeaturesAlreadyReported() {}
49 : };
50 :
51 6 : NS_IMPL_ISUPPORTS(ObserverToDestroyFeaturesAlreadyReported,
52 : nsIObserver)
53 :
54 : NS_IMETHODIMP
55 0 : ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject,
56 : const char* aTopic,
57 : const char16_t* aData)
58 : {
59 0 : if (!strcmp(aTopic, "xpcom-shutdown")) {
60 0 : StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex);
61 0 : if (gFeaturesAlreadyReported) {
62 0 : delete gFeaturesAlreadyReported;
63 0 : gFeaturesAlreadyReported = nullptr;
64 : }
65 : }
66 0 : return NS_OK;
67 : }
68 :
69 6 : class RegisterObserverRunnable : public Runnable {
70 : public:
71 3 : RegisterObserverRunnable() : Runnable("RegisterObserverRunnable") {}
72 2 : NS_IMETHOD Run() override {
73 : // LeakLog made me do this. Basically, I just wanted gFeaturesAlreadyReported to be a static nsTArray<nsCString>,
74 : // and LeakLog was complaining about leaks like this:
75 : // leaked 1 instance of nsTArray_base with size 8 bytes
76 : // leaked 7 instances of nsStringBuffer with size 8 bytes each (56 bytes total)
77 : // So this is a work-around using a pointer, and using a nsIObserver to deallocate on xpcom shutdown.
78 : // Yay for fighting bloat.
79 4 : nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
80 2 : if (!observerService)
81 0 : return NS_OK;
82 4 : RefPtr<ObserverToDestroyFeaturesAlreadyReported> observer = new ObserverToDestroyFeaturesAlreadyReported;
83 2 : observerService->AddObserver(observer, "xpcom-shutdown", false);
84 2 : return NS_OK;
85 : }
86 : };
87 :
88 0 : class AppendAppNotesRunnable : public CancelableRunnable {
89 : public:
90 0 : explicit AppendAppNotesRunnable(const nsACString& aFeatureStr)
91 0 : : CancelableRunnable("AppendAppNotesRunnable")
92 0 : , mFeatureString(aFeatureStr)
93 : {
94 0 : }
95 :
96 0 : NS_IMETHOD Run() override {
97 0 : CrashReporter::AppendAppNotesToCrashReport(mFeatureString);
98 0 : return NS_OK;
99 : }
100 :
101 : private:
102 : nsAutoCString mFeatureString;
103 : };
104 :
105 : void
106 6 : ScopedGfxFeatureReporter::WriteAppNote(char statusChar)
107 : {
108 12 : StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex);
109 :
110 6 : if (!gFeaturesAlreadyReported) {
111 3 : gFeaturesAlreadyReported = new nsTArray<nsCString>;
112 6 : nsCOMPtr<nsIRunnable> r = new RegisterObserverRunnable();
113 : SystemGroup::Dispatch("ScopedGfxFeatureReporter::RegisterObserverRunnable",
114 3 : TaskCategory::Other, r.forget());
115 : }
116 :
117 12 : nsAutoCString featureString;
118 6 : featureString.AppendPrintf("%s%c ",
119 : mFeature,
120 6 : statusChar);
121 :
122 6 : if (!gFeaturesAlreadyReported->Contains(featureString)) {
123 6 : gFeaturesAlreadyReported->AppendElement(featureString);
124 6 : AppNote(featureString);
125 : }
126 6 : }
127 :
128 : void
129 9 : ScopedGfxFeatureReporter::AppNote(const nsACString& aMessage)
130 : {
131 9 : if (NS_IsMainThread()) {
132 9 : CrashReporter::AppendAppNotesToCrashReport(aMessage);
133 : } else {
134 0 : nsCOMPtr<nsIRunnable> r = new AppendAppNotesRunnable(aMessage);
135 : SystemGroup::Dispatch("ScopedGfxFeatureReporter::AppendAppNotesRunnable",
136 0 : TaskCategory::Other, r.forget());
137 : }
138 9 : }
139 :
140 : } // end namespace mozilla
141 :
142 : #else
143 :
144 : namespace mozilla {
145 : void ScopedGfxFeatureReporter::WriteAppNote(char) {}
146 : void ScopedGfxFeatureReporter::AppNote(const nsACString&) {}
147 :
148 : } // namespace mozilla
149 :
150 : #endif
|