michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfxCrashReporterUtils.h" michael@0: michael@0: #if defined(MOZ_CRASHREPORTER) michael@0: #define MOZ_GFXFEATUREREPORTER 1 michael@0: #endif michael@0: michael@0: #ifdef MOZ_GFXFEATUREREPORTER michael@0: #include "gfxCrashReporterUtils.h" michael@0: #include // for strcmp michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 michael@0: #include "mozilla/Services.h" // for GetObserverService michael@0: #include "mozilla/mozalloc.h" // for operator new, etc michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsCOMPtr.h" // for nsCOMPtr michael@0: #include "nsError.h" // for NS_OK, NS_FAILED, nsresult michael@0: #include "nsExceptionHandler.h" // for AppendAppNotesToCrashReport michael@0: #include "nsID.h" michael@0: #include "nsIEventTarget.h" // for NS_DISPATCH_NORMAL michael@0: #include "nsIObserver.h" // for nsIObserver, etc michael@0: #include "nsIObserverService.h" // for nsIObserverService michael@0: #include "nsIRunnable.h" // for nsIRunnable michael@0: #include "nsISupports.h" michael@0: #include "nsString.h" // for nsAutoCString, nsCString, etc michael@0: #include "nsTArray.h" // for nsTArray michael@0: #include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc michael@0: #include "nscore.h" // for NS_IMETHOD, NS_IMETHODIMP, etc michael@0: michael@0: namespace mozilla { michael@0: michael@0: static nsTArray *gFeaturesAlreadyReported = nullptr; michael@0: michael@0: class ObserverToDestroyFeaturesAlreadyReported : public nsIObserver michael@0: { michael@0: michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: ObserverToDestroyFeaturesAlreadyReported() {} michael@0: virtual ~ObserverToDestroyFeaturesAlreadyReported() {} michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(ObserverToDestroyFeaturesAlreadyReported, michael@0: nsIObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject, michael@0: const char* aTopic, michael@0: const char16_t* aData) michael@0: { michael@0: if (!strcmp(aTopic, "xpcom-shutdown")) { michael@0: if (gFeaturesAlreadyReported) { michael@0: delete gFeaturesAlreadyReported; michael@0: gFeaturesAlreadyReported = nullptr; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: class ScopedGfxFeatureReporter::AppNoteWritingRunnable : public nsRunnable { michael@0: public: michael@0: AppNoteWritingRunnable(char aStatusChar, const char *aFeature) : michael@0: mStatusChar(aStatusChar), mFeature(aFeature) {} michael@0: NS_IMETHOD Run() { michael@0: // LeakLog made me do this. Basically, I just wanted gFeaturesAlreadyReported to be a static nsTArray, michael@0: // and LeakLog was complaining about leaks like this: michael@0: // leaked 1 instance of nsTArray_base with size 8 bytes michael@0: // leaked 7 instances of nsStringBuffer with size 8 bytes each (56 bytes total) michael@0: // So this is a work-around using a pointer, and using a nsIObserver to deallocate on xpcom shutdown. michael@0: // Yay for fighting bloat. michael@0: if (!gFeaturesAlreadyReported) { michael@0: nsCOMPtr observerService = mozilla::services::GetObserverService(); michael@0: if (!observerService) michael@0: return NS_OK; michael@0: nsRefPtr observer = new ObserverToDestroyFeaturesAlreadyReported; michael@0: nsresult rv = observerService->AddObserver(observer, "xpcom-shutdown", false); michael@0: if (NS_FAILED(rv)) { michael@0: observer = nullptr; michael@0: return NS_OK; michael@0: } michael@0: gFeaturesAlreadyReported = new nsTArray; michael@0: } michael@0: michael@0: nsAutoCString featureString; michael@0: featureString.AppendPrintf("%s%c ", michael@0: mFeature, michael@0: mStatusChar); michael@0: michael@0: if (!gFeaturesAlreadyReported->Contains(featureString)) { michael@0: gFeaturesAlreadyReported->AppendElement(featureString); michael@0: CrashReporter::AppendAppNotesToCrashReport(featureString); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: private: michael@0: char mStatusChar; michael@0: const char *mFeature; michael@0: }; michael@0: michael@0: void michael@0: ScopedGfxFeatureReporter::WriteAppNote(char statusChar) michael@0: { michael@0: nsCOMPtr r = new AppNoteWritingRunnable(statusChar, mFeature); michael@0: NS_DispatchToMainThread(r.get(), NS_DISPATCH_NORMAL); michael@0: } michael@0: michael@0: } // end namespace mozilla michael@0: michael@0: #else michael@0: michael@0: namespace mozilla { michael@0: void ScopedGfxFeatureReporter::WriteAppNote(char) {} michael@0: } michael@0: michael@0: #endif