gfxCrashReporterUtils.cpp (4654B)
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 #include "gfxCrashReporterUtils.h" 8 #include <string.h> // for strcmp 9 #include "mozilla/SchedulerGroup.h" // for SchedulerGroup 10 #include "mozilla/Services.h" // for GetObserverService 11 #include "mozilla/StaticMutex.h" 12 #include "mozilla/mozalloc.h" // for operator new, etc 13 #include "mozilla/RefPtr.h" // for RefPtr 14 #include "MainThreadUtils.h" // for NS_IsMainThread 15 #include "nsCOMPtr.h" // for nsCOMPtr 16 #include "nsError.h" // for NS_OK, NS_FAILED, nsresult 17 #include "nsExceptionHandler.h" // for AppendAppNotesToCrashReport 18 #include "nsIObserver.h" // for nsIObserver, etc 19 #include "nsIObserverService.h" // for nsIObserverService 20 #include "nsIRunnable.h" // for nsIRunnable 21 #include "nsISupports.h" 22 #include "nsThreadUtils.h" // for Runnable 23 #include "nsTArray.h" // for nsTArray 24 #include "nscore.h" // for NS_IMETHOD, NS_IMETHODIMP, etc 25 26 namespace mozilla { 27 28 static nsTArray<nsCString>* gFeaturesAlreadyReported = nullptr; 29 static StaticMutex gFeaturesAlreadyReportedMutex MOZ_UNANNOTATED; 30 31 class ObserverToDestroyFeaturesAlreadyReported final : public nsIObserver { 32 public: 33 NS_DECL_ISUPPORTS 34 NS_DECL_NSIOBSERVER 35 36 ObserverToDestroyFeaturesAlreadyReported() = default; 37 38 private: 39 virtual ~ObserverToDestroyFeaturesAlreadyReported() = default; 40 }; 41 42 NS_IMPL_ISUPPORTS(ObserverToDestroyFeaturesAlreadyReported, nsIObserver) 43 44 NS_IMETHODIMP 45 ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject, 46 const char* aTopic, 47 const char16_t* aData) { 48 if (!strcmp(aTopic, "xpcom-shutdown")) { 49 StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex); 50 if (gFeaturesAlreadyReported) { 51 delete gFeaturesAlreadyReported; 52 gFeaturesAlreadyReported = nullptr; 53 } 54 } 55 return NS_OK; 56 } 57 58 class RegisterObserverRunnable : public Runnable { 59 public: 60 RegisterObserverRunnable() : Runnable("RegisterObserverRunnable") {} 61 NS_IMETHOD Run() override { 62 // LeakLog made me do this. Basically, I just wanted 63 // gFeaturesAlreadyReported to be a static nsTArray<nsCString>, and LeakLog 64 // was complaining about leaks like this: 65 // leaked 1 instance of nsTArray_base with size 8 bytes 66 // leaked 7 instances of nsStringBuffer with size 8 bytes each (56 bytes 67 // total) 68 // So this is a work-around using a pointer, and using a nsIObserver to 69 // deallocate on xpcom shutdown. Yay for fighting bloat. 70 nsCOMPtr<nsIObserverService> observerService = 71 mozilla::services::GetObserverService(); 72 if (!observerService) return NS_OK; 73 RefPtr<ObserverToDestroyFeaturesAlreadyReported> observer = 74 new ObserverToDestroyFeaturesAlreadyReported; 75 observerService->AddObserver(observer, "xpcom-shutdown", false); 76 return NS_OK; 77 } 78 }; 79 80 class AppendAppNotesRunnable : public Runnable { 81 public: 82 explicit AppendAppNotesRunnable(const nsACString& aFeatureStr) 83 : Runnable("AppendAppNotesRunnable"), mFeatureString(aFeatureStr) {} 84 85 NS_IMETHOD Run() override { 86 CrashReporter::AppendAppNotesToCrashReport(mFeatureString); 87 return NS_OK; 88 } 89 90 private: 91 nsAutoCString mFeatureString; 92 }; 93 94 void ScopedGfxFeatureReporter::WriteAppNote(char statusChar, 95 int32_t statusNumber) { 96 StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex); 97 98 if (!gFeaturesAlreadyReported) { 99 gFeaturesAlreadyReported = new nsTArray<nsCString>; 100 nsCOMPtr<nsIRunnable> r = new RegisterObserverRunnable(); 101 SchedulerGroup::Dispatch(r.forget()); 102 } 103 104 nsAutoCString featureString; 105 if (statusNumber == 0) { 106 featureString.AppendPrintf("%s%c ", mFeature, statusChar); 107 } else { 108 featureString.AppendPrintf("%s%c%d ", mFeature, statusChar, statusNumber); 109 } 110 111 if (!gFeaturesAlreadyReported->Contains(featureString)) { 112 gFeaturesAlreadyReported->AppendElement(featureString); 113 AppNote(featureString); 114 } 115 } 116 117 void ScopedGfxFeatureReporter::AppNote(const nsACString& aMessage) { 118 if (NS_IsMainThread()) { 119 CrashReporter::AppendAppNotesToCrashReport(aMessage); 120 } else { 121 nsCOMPtr<nsIRunnable> r = new AppendAppNotesRunnable(aMessage); 122 NS_DispatchToMainThread(r.forget()); 123 } 124 } 125 126 } // end namespace mozilla