Bug 1074952 - Part 4. For the critical log, save the first, then circular buffer the rest into the crash annotations. r=bas

This commit is contained in:
Milan Sreckovic 2014-11-17 17:16:55 -05:00
parent 7ece31d5c9
commit d8d778d935
2 changed files with 102 additions and 12 deletions

View File

@ -11,6 +11,7 @@
#include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
#include "prlog.h"
#include "prprf.h"
#include "gfxPlatform.h"
#include "gfxPrefs.h"
@ -152,22 +153,103 @@ public:
NS_DECL_NSIOBSERVER
};
/// This override of the LogForwarder, initially used for the critical graphics
/// errors, is sending the log to the crash annotations as well, but only
/// if the capacity set with the method below is >= 2. We always retain the
/// very first critical message, and the latest capacity-1 messages are
/// rotated through. Note that we don't expect the total number of times
/// this gets called to be large - it is meant for critical errors only.
class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
{
public:
virtual void Log(const std::string& aString) MOZ_OVERRIDE {
if (!NS_IsMainThread()) {
return;
}
#ifdef MOZ_CRASHREPORTER
nsCString reportString(aString.c_str());
CrashReporter::AppendAppNotesToCrashReport(reportString);
#else
printf("GFX ERROR: %s", aString.c_str());
#endif
}
CrashStatsLogForwarder(const char* aKey);
virtual void Log(const std::string& aString) MOZ_OVERRIDE;
void SetCircularBufferSize(uint32_t aCapacity);
private:
// Helpers for the Log()
bool UpdateStringsVector(const std::string& aString);
void UpdateCrashReport();
private:
std::vector<std::pair<int32_t,std::string> > mBuffer;
nsCString mCrashCriticalKey;
uint32_t mMaxCapacity;
int32_t mIndex;
};
CrashStatsLogForwarder::CrashStatsLogForwarder(const char* aKey)
: mBuffer()
, mCrashCriticalKey(aKey)
, mMaxCapacity(0)
, mIndex(-1)
{
}
void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity)
{
mMaxCapacity = aCapacity;
mBuffer.reserve(static_cast<size_t>(aCapacity));
}
bool
CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString)
{
// We want at least the first one and the last one. Otherwise, no point.
if (mMaxCapacity < 2) {
return false;
}
mIndex += 1;
MOZ_ASSERT(mIndex >= 0);
// index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
int32_t index = mIndex ? (mIndex-1) % (mMaxCapacity-1) + 1 : 0;
MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
// Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
// just out of paranoia, but we know index <= mBuffer.size().
std::pair<int32_t,std::string> newEntry(mIndex,aString);
if (index >= static_cast<int32_t>(mBuffer.size())) {
mBuffer.push_back(newEntry);
} else {
mBuffer[index] = newEntry;
}
return true;
}
void CrashStatsLogForwarder::UpdateCrashReport()
{
std::stringstream message;
for(std::vector<std::pair<int32_t, std::string> >::iterator it = mBuffer.begin(); it != mBuffer.end(); ++it) {
message << "|[" << (*it).first << "]" << (*it).second;
}
#ifdef MOZ_CRASHREPORTER
if (!NS_IsMainThread()) {
return;
}
nsCString reportString(message.str().c_str());
nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString);
#else
nsresult annotated = NS_ERROR_NOT_IMPLEMENTED;
#endif
if (annotated != NS_OK) {
printf("Crash Annotation %s: %s",
mCrashCriticalKey.get(), message.str().c_str());
}
}
void CrashStatsLogForwarder::Log(const std::string& aString)
{
if (UpdateStringsVector(aString)) {
UpdateCrashReport();
}
}
NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
@ -358,11 +440,14 @@ gfxPlatform::Init()
}
gEverInitialized = true;
mozilla::gfx::Factory::SetLogForwarder(new CrashStatsLogForwarder);
CrashStatsLogForwarder* logForwarder = new CrashStatsLogForwarder("GraphicsCriticalError");
mozilla::gfx::Factory::SetLogForwarder(logForwarder);
// Initialize the preferences by creating the singleton.
gfxPrefs::GetSingleton();
logForwarder->SetCircularBufferSize(gfxPrefs::GfxLoggingCrashLength());
gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
/* Initialize the GfxInfo service.
@ -530,6 +615,9 @@ gfxPlatform::Shutdown()
mozilla::gl::GLContextProviderEGL::Shutdown();
#endif
// This is a bit iffy - we're assuming that we were the ones that set the
// log forwarder in the Factory, so that it's our responsibility to
// delete it.
delete mozilla::gfx::Factory::GetLogForwarder();
mozilla::gfx::Factory::SetLogForwarder(nullptr);

View File

@ -209,6 +209,8 @@ private:
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456);
// Note that "gfx.logging.level" is defined in Logging.h
DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 6);
DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false);
DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true);