summaryrefslogtreecommitdiff
path: root/gfx/src/gfxCrashReporterUtils.cpp
blob: 757c15527aac259d4feff010ef6977477374bf28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "gfxCrashReporterUtils.h"

#ifdef MOZ_GFXFEATUREREPORTER
#include "gfxCrashReporterUtils.h"
#include <string.h>                     // for strcmp
#include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
#include "mozilla/Services.h"           // for GetObserverService
#include "mozilla/StaticMutex.h"
#include "mozilla/mozalloc.h"           // for operator new, etc
#include "mozilla/RefPtr.h"             // for RefPtr
#include "nsCOMPtr.h"                   // for nsCOMPtr
#include "nsError.h"                    // for NS_OK, NS_FAILED, nsresult
#include "nsExceptionHandler.h"         // for AppendAppNotesToCrashReport
#include "nsID.h"
#include "nsIEventTarget.h"             // for NS_DISPATCH_NORMAL
#include "nsIObserver.h"                // for nsIObserver, etc
#include "nsIObserverService.h"         // for nsIObserverService
#include "nsIRunnable.h"                // for nsIRunnable
#include "nsISupports.h"
#include "nsTArray.h"                   // for nsTArray
#include "nsThreadUtils.h"              // for NS_DispatchToMainThread, etc
#include "nscore.h"                     // for NS_IMETHOD, NS_IMETHODIMP, etc

namespace mozilla {

static nsTArray<nsCString> *gFeaturesAlreadyReported = nullptr;
static StaticMutex gFeaturesAlreadyReportedMutex;

class ObserverToDestroyFeaturesAlreadyReported final : public nsIObserver
{

public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIOBSERVER

  ObserverToDestroyFeaturesAlreadyReported() {}
private:
  virtual ~ObserverToDestroyFeaturesAlreadyReported() {}
};

NS_IMPL_ISUPPORTS(ObserverToDestroyFeaturesAlreadyReported,
                  nsIObserver)

NS_IMETHODIMP
ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject,
                                                  const char* aTopic,
                                                  const char16_t* aData)
{
  if (!strcmp(aTopic, "xpcom-shutdown")) {
    StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex);
    if (gFeaturesAlreadyReported) {
      delete gFeaturesAlreadyReported;
      gFeaturesAlreadyReported = nullptr;
    }
  }
  return NS_OK;
}

class RegisterObserverRunnable : public Runnable {
public:
  NS_IMETHOD Run() override {
    // LeakLog made me do this. Basically, I just wanted gFeaturesAlreadyReported to be a static nsTArray<nsCString>,
    // and LeakLog was complaining about leaks like this:
    //    leaked 1 instance of nsTArray_base with size 8 bytes
    //    leaked 7 instances of nsStringBuffer with size 8 bytes each (56 bytes total)
    // So this is a work-around using a pointer, and using a nsIObserver to deallocate on xpcom shutdown.
    // Yay for fighting bloat.
    nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
    if (!observerService)
      return NS_OK;
    RefPtr<ObserverToDestroyFeaturesAlreadyReported> observer = new ObserverToDestroyFeaturesAlreadyReported;
    observerService->AddObserver(observer, "xpcom-shutdown", false);
    return NS_OK;
  }
};

class AppendAppNotesRunnable : public CancelableRunnable {
public:
  explicit AppendAppNotesRunnable(const nsACString& aFeatureStr)
    : mFeatureString(aFeatureStr)
  {
  }

  NS_IMETHOD Run() override {
    CrashReporter::AppendAppNotesToCrashReport(mFeatureString);
    return NS_OK;
  }

private:
  nsAutoCString mFeatureString;
};

void
ScopedGfxFeatureReporter::WriteAppNote(char statusChar)
{
  StaticMutexAutoLock al(gFeaturesAlreadyReportedMutex);

  if (!gFeaturesAlreadyReported) {
    gFeaturesAlreadyReported = new nsTArray<nsCString>;
    nsCOMPtr<nsIRunnable> r = new RegisterObserverRunnable();
    NS_DispatchToMainThread(r);
  }

  nsAutoCString featureString;
  featureString.AppendPrintf("%s%c ",
                             mFeature,
                             statusChar);

  if (!gFeaturesAlreadyReported->Contains(featureString)) {
    gFeaturesAlreadyReported->AppendElement(featureString);
    AppNote(featureString);
  }
}

void
ScopedGfxFeatureReporter::AppNote(const nsACString& aMessage)
{
  if (NS_IsMainThread()) {
    CrashReporter::AppendAppNotesToCrashReport(aMessage);
  } else {
    nsCOMPtr<nsIRunnable> r = new AppendAppNotesRunnable(aMessage);
    NS_DispatchToMainThread(r);
  }
}
  
} // end namespace mozilla

#else

namespace mozilla {
void ScopedGfxFeatureReporter::WriteAppNote(char) {}
void ScopedGfxFeatureReporter::AppNote(const nsACString&) {}
  
} // namespace mozilla

#endif