Backed out 8 changesets (bug 1183910, bug 1190281)

Backed out changeset 6ddbdbd66174 (bug 1190281)
Backed out changeset c85c1d11bd72 (bug 1190281)
Backed out changeset 7f904a453bdb (bug 1190281)
Backed out changeset e17123b5bafd (bug 1190281)
Backed out changeset 50edbeb8912e (bug 1190281)
Backed out changeset cf98685302b6 (bug 1190281)
Backed out changeset e98a176b4e0b (bug 1190281)
Backed out changeset e7b3b23bcc82 (bug 1183910)

--HG--
rename : gfx/src/DriverCrashGuard.cpp => gfx/src/DriverInitCrashDetection.cpp
rename : gfx/src/DriverCrashGuard.h => gfx/src/DriverInitCrashDetection.h
This commit is contained in:
Sebastian Hengst 2015-08-11 10:13:43 +02:00
Родитель f55d77eadf
Коммит c2581fad83
13 изменённых файлов: 382 добавлений и 670 удалений

Просмотреть файл

@ -2081,10 +2081,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
SEND_SHUTDOWN_MESSAGE));
}
cpm->RemoveContentProcess(this->ChildID());
if (mDriverCrashGuard) {
mDriverCrashGuard->NotifyCrashed();
}
}
void
@ -5182,42 +5178,6 @@ ContentParent::RecvGetGraphicsDeviceInitData(DeviceInitData* aOut)
return true;
}
bool
ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed)
{
// Only one driver crash guard should be active at a time, per-process.
MOZ_ASSERT(!mDriverCrashGuard);
UniquePtr<gfx::DriverCrashGuard> guard;
switch (gfx::CrashGuardType(aGuardType)) {
case gfx::CrashGuardType::D3D11Layers:
guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
break;
case gfx::CrashGuardType::D3D9Video:
guard = MakeUnique<gfx::D3D9VideoCrashGuard>(this);
break;
default:
MOZ_ASSERT_UNREACHABLE("unknown crash guard type");
return false;
}
if (guard->Crashed()) {
*aOutCrashed = true;
return true;
}
*aOutCrashed = false;
mDriverCrashGuard = Move(guard);
return true;
}
bool
ContentParent::RecvEndDriverCrashGuard(const uint32_t& aGuardType)
{
mDriverCrashGuard = nullptr;
return true;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -25,7 +25,6 @@
#include "nsIDOMGeoPositionCallback.h"
#include "nsIDOMGeoPositionErrorCallback.h"
#include "PermissionMessageUtils.h"
#include "DriverCrashGuard.h"
#define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
@ -815,8 +814,6 @@ private:
virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
int32_t* aStatus,
bool* aSuccess) override;
virtual bool RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) override;
virtual bool RecvEndDriverCrashGuard(const uint32_t& aGuardType) override;
virtual bool RecvAddIdleObserver(const uint64_t& observerId,
const uint32_t& aIdleTimeInS) override;
@ -957,8 +954,6 @@ private:
nsRefPtr<mozilla::ProfileGatherer> mGatherer;
#endif
nsCString mProfile;
UniquePtr<gfx::DriverCrashGuard> mDriverCrashGuard;
};
} // namespace dom

Просмотреть файл

@ -933,10 +933,6 @@ parent:
sync GetGraphicsFeatureStatus(int32_t aFeature) returns (int32_t aStatus, bool aSuccess);
// Driver crash guards. aGuardType must be a member of CrashGuardType.
sync BeginDriverCrashGuard(uint32_t aGuardType) returns (bool crashDetected);
sync EndDriverCrashGuard(uint32_t aGuardType);
AddIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
RemoveIdleObserver(uint64_t observerId, uint32_t idleTimeInS);

Просмотреть файл

@ -429,8 +429,8 @@ public:
}
T firstEnd = std::max(mIntervals[0].mStart, aInterval.mStart);
T secondStart = std::min(mIntervals.LastElement().mEnd, aInterval.mEnd);
ElemType startInterval(mIntervals[0].mStart, firstEnd, aInterval.mFuzz);
ElemType endInterval(secondStart, mIntervals.LastElement().mEnd, aInterval.mFuzz);
ElemType startInterval(mIntervals[0].mStart, firstEnd);
ElemType endInterval(secondStart, mIntervals.LastElement().mEnd);
SelfType intervals(Move(startInterval));
intervals += Move(endInterval);
return Intersection(intervals);

Просмотреть файл

@ -776,4 +776,46 @@ TEST(IntervalSet, Substraction)
EXPECT_EQ(1u, i0.Length());
EXPECT_EQ(5, i0[0].mStart);
EXPECT_EQ(8, i0[0].mEnd);
i0 = IntIntervals();
i0 += IntInterval(0, 10);
IntIntervals i2;
i2 += IntInterval(4, 6);
i0 -= i2;
EXPECT_EQ(2u, i0.Length());
EXPECT_EQ(0, i0[0].mStart);
EXPECT_EQ(4, i0[0].mEnd);
EXPECT_EQ(6, i0[1].mStart);
EXPECT_EQ(10, i0[1].mEnd);
i0 = IntIntervals();
i0 += IntInterval(0, 1);
i0 += IntInterval(3, 10);
EXPECT_EQ(2u, i0.Length());
// This fuzz should collapse i0 into [0,10).
i0.SetFuzz(1);
EXPECT_EQ(1u, i0.Length());
EXPECT_EQ(1, i0[0].mFuzz);
i2 = IntInterval(4, 6);
i0 -= i2;
EXPECT_EQ(2u, i0.Length());
EXPECT_EQ(0, i0[0].mStart);
EXPECT_EQ(4, i0[0].mEnd);
EXPECT_EQ(6, i0[1].mStart);
EXPECT_EQ(10, i0[1].mEnd);
EXPECT_EQ(1, i0[0].mFuzz);
EXPECT_EQ(1, i0[1].mFuzz);
i0 = IntIntervals();
i0 += IntInterval(0, 10);
// [4,6) with fuzz 1 used to fail because the complementary interval set
// [0,4)+[6,10) would collapse into [0,10).
i2 = IntInterval(4, 6);
i2.SetFuzz(1);
i0 -= i2;
EXPECT_EQ(2u, i0.Length());
EXPECT_EQ(0, i0[0].mStart);
EXPECT_EQ(4, i0[0].mEnd);
EXPECT_EQ(6, i0[1].mStart);
EXPECT_EQ(10, i0[1].mEnd);
}

Просмотреть файл

@ -14,7 +14,6 @@
#include "mozilla/Preferences.h"
#include "mfapi.h"
#include "MFTDecoder.h"
#include "DriverCrashGuard.h"
const CLSID CLSID_VideoProcessorMFT =
{
@ -32,7 +31,7 @@ const GUID MF_XVP_PLAYBACK_MODE =
{ 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9 }
};
DEFINE_GUID(MF_LOW_LATENCY,
DEFINE_GUID(MF_LOW_LATENCY,
0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee);
namespace mozilla {
@ -91,12 +90,6 @@ D3D9DXVA2Manager::Init()
{
MOZ_ASSERT(NS_IsMainThread());
gfx::D3D9VideoCrashGuard crashGuard;
if (crashGuard.Crashed()) {
NS_WARNING("DXVA2D3D9 crash detected");
return E_FAIL;
}
// Create D3D9Ex.
HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
NS_ENSURE_TRUE(d3d9lib, E_FAIL);

Просмотреть файл

@ -1,451 +0,0 @@
/* -*- 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 "DriverCrashGuard.h"
#include "gfxPrefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsXULAppAPI.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Services.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla {
namespace gfx {
static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES);
static const char* sCrashGuardNames[NUM_CRASH_GUARD_TYPES] = {
"d3d11layers",
"d3d9video",
};
DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent)
: mType(aType)
, mMode(aContentParent ? Mode::Proxy : Mode::Normal)
, mInitialized(false)
, mGuardActivated(false)
, mCrashDetected(false)
{
MOZ_ASSERT(mType < CrashGuardType::NUM_TYPES);
mStatusPref.Assign("gfx.crash-guard.status.");
mStatusPref.Append(sCrashGuardNames[size_t(mType)]);
}
void
DriverCrashGuard::InitializeIfNeeded()
{
if (mInitialized) {
return;
}
mInitialized = true;
Initialize();
}
void
DriverCrashGuard::Initialize()
{
if (XRE_IsContentProcess()) {
// Ask the parent whether or not activating the guard is okay. The parent
// won't bother if it detected a crash.
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
cc->SendBeginDriverCrashGuard(uint32_t(mType), &mCrashDetected);
if (mCrashDetected) {
LogFeatureDisabled();
return;
}
ActivateGuard();
return;
}
// Always check whether or not the lock file exists. For example, we could
// have crashed creating a D3D9 device in the parent process, and on restart
// are now requesting one in the child process. We catch everything here.
if (RecoverFromCrash()) {
mCrashDetected = true;
return;
}
// If the environment has changed, we always activate the guard. In the
// parent process this performs main-thread disk I/O. Child process guards
// only incur an IPC cost, so if we're proxying for a child process, we
// play it safe and activate the guard as long as we don't expect it to
// crash.
if (CheckOrRefreshEnvironment() ||
(mMode == Mode::Proxy && GetStatus() != DriverInitStatus::Crashed))
{
ActivateGuard();
return;
}
// If we got here and our status is "crashed", then the environment has not
// updated and we do not want to attempt to use the driver again.
if (GetStatus() == DriverInitStatus::Crashed) {
mCrashDetected = true;
LogFeatureDisabled();
}
}
DriverCrashGuard::~DriverCrashGuard()
{
if (!mGuardActivated) {
return;
}
if (XRE_IsParentProcess()) {
if (mGuardFile) {
mGuardFile->Remove(false);
}
// If during our initialization, no other process encountered a crash, we
// proceed to mark the status as okay.
if (GetStatus() != DriverInitStatus::Crashed) {
SetStatus(DriverInitStatus::Okay);
}
} else {
dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType));
}
#ifdef MOZ_CRASHREPORTER
// Remove the crash report annotation.
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
NS_LITERAL_CSTRING(""));
#endif
}
bool
DriverCrashGuard::Crashed()
{
InitializeIfNeeded();
// Note, we read mCrashDetected instead of GetStatus(), since in child
// processes we're not guaranteed that the prefs have been synced in
// time.
return mCrashDetected;
}
nsCOMPtr<nsIFile>
DriverCrashGuard::GetGuardFile()
{
nsCString filename;
filename.Assign(sCrashGuardNames[size_t(mType)]);
filename.Append(".guard");
nsCOMPtr<nsIFile> file;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(file));
if (!file) {
return nullptr;
}
if (!NS_SUCCEEDED(file->AppendNative(filename))) {
return nullptr;
}
return file;
}
void
DriverCrashGuard::ActivateGuard()
{
mGuardActivated = true;
#ifdef MOZ_CRASHREPORTER
// Anotate crash reports only if we're a real guard. Otherwise, we could
// attribute a random parent process crash to a graphics problem in a child
// process.
if (mMode != Mode::Proxy) {
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
NS_LITERAL_CSTRING("1"));
}
#endif
// If we're in the content process, the rest of the guarding is handled
// in the parent.
if (XRE_IsContentProcess()) {
return;
}
SetStatus(DriverInitStatus::Attempting);
if (mMode != Mode::Proxy) {
// In parent process guards, we use two tombstones to detect crashes: a
// preferences and a zero-byte file on the filesystem.
FlushPreferences();
// Create a temporary tombstone/lockfile.
FILE* fp = nullptr;
mGuardFile = GetGuardFile();
if (!mGuardFile || !NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) {
return;
}
fclose(fp);
}
}
void
DriverCrashGuard::NotifyCrashed()
{
CheckOrRefreshEnvironment();
SetStatus(DriverInitStatus::Crashed);
FlushPreferences();
LogCrashRecovery();
}
bool
DriverCrashGuard::RecoverFromCrash()
{
nsCOMPtr<nsIFile> file = GetGuardFile();
bool exists;
if ((file &&
NS_SUCCEEDED(file->Exists(&exists)) &&
exists) ||
(GetStatus() == DriverInitStatus::Attempting))
{
// If we get here, we've just recovered from a crash. Disable acceleration
// until the environment changes.
if (file) {
file->Remove(false);
}
NotifyCrashed();
return true;
}
return false;
}
// Return true if the caller should proceed to guard for crashes. False if
// the environment has not changed. We persist the "changed" status across
// calls, so that after an environment changes, all guards for the new
// session are activated rather than just the first.
bool
DriverCrashGuard::CheckOrRefreshEnvironment()
{
static bool sBaseInfoChanged = false;
static bool sBaseInfoChecked = false;
if (!sBaseInfoChecked) {
// None of the prefs we care about, so we cache the result statically.
sBaseInfoChecked = true;
sBaseInfoChanged = UpdateBaseEnvironment();
}
// Always update the full environment, even if the base info didn't change.
return UpdateEnvironment() ||
sBaseInfoChanged ||
GetStatus() == DriverInitStatus::Unknown;
}
bool
DriverCrashGuard::UpdateBaseEnvironment()
{
bool changed = false;
if (mGfxInfo = services::GetGfxInfo()) {
nsString value;
// Driver properties.
mGfxInfo->GetAdapterDriverVersion(value);
changed |= CheckAndUpdatePref("driverVersion", value);
mGfxInfo->GetAdapterDeviceID(value);
changed |= CheckAndUpdatePref("deviceID", value);
}
// Firefox properties.
changed |= CheckAndUpdatePref("appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
return changed;
}
bool
DriverCrashGuard::FeatureEnabled(int aFeature)
{
int32_t status;
if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) {
return false;
}
return status == nsIGfxInfo::FEATURE_STATUS_OK;
}
bool
DriverCrashGuard::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue)
{
std::string pref = GetFullPrefName(aPrefName);
bool oldValue;
if (NS_SUCCEEDED(Preferences::GetBool(pref.c_str(), &oldValue)) &&
oldValue == aCurrentValue)
{
return false;
}
Preferences::SetBool(pref.c_str(), aCurrentValue);
return true;
}
bool
DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue)
{
std::string pref = GetFullPrefName(aPrefName);
nsAdoptingString oldValue = Preferences::GetString(pref.c_str());
if (oldValue == aCurrentValue) {
return false;
}
Preferences::SetString(pref.c_str(), aCurrentValue);
return true;
}
std::string
DriverCrashGuard::GetFullPrefName(const char* aPref)
{
return std::string("gfx.crash-guard.") +
std::string(sCrashGuardNames[uint32_t(mType)]) +
std::string(".") +
std::string(aPref);
}
DriverInitStatus
DriverCrashGuard::GetStatus() const
{
return (DriverInitStatus)Preferences::GetInt(mStatusPref.get(), 0);
}
void
DriverCrashGuard::SetStatus(DriverInitStatus aStatus)
{
MOZ_ASSERT(XRE_IsParentProcess());
Preferences::SetInt(mStatusPref.get(), int32_t(aStatus));
}
void
DriverCrashGuard::FlushPreferences()
{
MOZ_ASSERT(XRE_IsParentProcess());
if (nsIPrefService* prefService = Preferences::GetService()) {
prefService->SavePrefFile(nullptr);
}
}
D3D11LayersCrashGuard::D3D11LayersCrashGuard(dom::ContentParent* aContentParent)
: DriverCrashGuard(CrashGuardType::D3D11Layers, aContentParent)
{
}
void
D3D11LayersCrashGuard::Initialize()
{
if (!XRE_IsParentProcess()) {
// We assume the parent process already performed crash detection for
// graphics devices.
return;
}
DriverCrashGuard::Initialize();
// If no telemetry states have been recorded, this will set the state to okay.
// Otherwise, it will have no effect.
RecordTelemetry(TelemetryState::Okay);
}
bool
D3D11LayersCrashGuard::UpdateEnvironment()
{
// None of the prefs we care about, so we cache the result statically.
static bool checked = false;
static bool changed = false;
if (checked) {
return changed;
}
checked = true;
if (mGfxInfo) {
// Feature status.
#if defined(XP_WIN)
bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
(!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled);
bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
d3d11Enabled = false;
}
changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled);
#endif
}
if (!changed) {
return false;
}
RecordTelemetry(TelemetryState::EnvironmentChanged);
return true;
}
void
D3D11LayersCrashGuard::LogCrashRecovery()
{
RecordTelemetry(TelemetryState::RecoveredFromCrash);
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers just crashed; D3D11 will be disabled.";
}
void
D3D11LayersCrashGuard::LogFeatureDisabled()
{
RecordTelemetry(TelemetryState::FeatureDisabled);
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers disabled due to a prior crash.";
}
void
D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState)
{
// D3D11LayersCrashGuard is a no-op in the child process.
if (!XRE_IsParentProcess()) {
return;
}
// Since we instantiate this class more than once, make sure we only record
// the first state (since that is really all we care about).
static bool sTelemetryStateRecorded = false;
if (sTelemetryStateRecorded) {
return;
}
Telemetry::Accumulate(Telemetry::GRAPHICS_DRIVER_STARTUP_TEST, int32_t(aState));
sTelemetryStateRecorded = true;
}
D3D9VideoCrashGuard::D3D9VideoCrashGuard(dom::ContentParent* aContentParent)
: DriverCrashGuard(CrashGuardType::D3D9Video, aContentParent)
{
}
bool
D3D9VideoCrashGuard::UpdateEnvironment()
{
// We don't care about any extra preferences here.
return false;
}
void
D3D9VideoCrashGuard::LogCrashRecovery()
{
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 just crashed; hardware video will be disabled.";
}
void
D3D9VideoCrashGuard::LogFeatureDisabled()
{
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 video decoding is disabled due to a previous crash.";
}
} // namespace gfx
} // namespace mozilla

Просмотреть файл

@ -1,149 +0,0 @@
/* -*- 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/. */
#ifndef gfx_src_DriverCrashGuard_h__
#define gfx_src_DriverCrashGuard_h__
#include "gfxCore.h"
#include "nsCOMPtr.h"
#include "nsIGfxInfo.h"
#include "nsIFile.h"
#include "nsString.h"
#include <string>
namespace mozilla {
namespace dom {
class ContentParent;
} // namespace dom
namespace gfx {
enum class DriverInitStatus
{
// Drivers have not been initialized yet.
Unknown,
// We're attempting to initialize drivers.
Attempting,
// Drivers were successfully initialized last run.
Okay,
// We crashed during driver initialization, and have restarted.
Crashed
};
enum class CrashGuardType : uint32_t
{
D3D11Layers,
D3D9Video,
NUM_TYPES
};
// DriverCrashGuard is used to detect crashes at graphics driver callsites.
//
// If the graphics environment is unrecognized or has changed since the last
// session, the crash guard will activate and will detect any crashes within
// the scope of the guard object.
//
// If a callsite has a previously encountered crash, and the environment has
// not changed since the last session, then the guard will set a status flag
// indicating that the driver should not be used.
class DriverCrashGuard
{
public:
DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent);
virtual ~DriverCrashGuard();
bool Crashed();
void NotifyCrashed();
// These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST).
// Values should not change; add new values to the end.
enum class TelemetryState {
Okay = 0,
EnvironmentChanged = 1,
RecoveredFromCrash = 2,
FeatureDisabled = 3
};
enum class Mode {
// Normal operation.
Normal,
// Acting as a proxy between the parent and child process.
Proxy
};
protected:
virtual void Initialize();
virtual bool UpdateEnvironment() = 0;
virtual void LogCrashRecovery() = 0;
virtual void LogFeatureDisabled() = 0;
// Helper functions.
bool FeatureEnabled(int aFeature);
bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue);
bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue);
std::string GetFullPrefName(const char* aPref);
private:
// Either process.
void InitializeIfNeeded();
bool CheckOrRefreshEnvironment();
bool UpdateBaseEnvironment();
DriverInitStatus GetStatus() const;
// Parent process only.
nsCOMPtr<nsIFile> GetGuardFile();
bool RecoverFromCrash();
void ActivateGuard();
void FlushPreferences();
void SetStatus(DriverInitStatus aStatus);
private:
CrashGuardType mType;
Mode mMode;
bool mInitialized;
bool mGuardActivated;
bool mCrashDetected;
nsCOMPtr<nsIFile> mGuardFile;
protected:
nsCString mStatusPref;
nsCOMPtr<nsIGfxInfo> mGfxInfo;
};
class D3D11LayersCrashGuard final : public DriverCrashGuard
{
public:
explicit D3D11LayersCrashGuard(dom::ContentParent* aContentParent = nullptr);
protected:
void Initialize() override;
bool UpdateEnvironment() override;
void LogCrashRecovery() override;
void LogFeatureDisabled() override;
private:
void RecordTelemetry(TelemetryState aState);
};
class D3D9VideoCrashGuard final : public DriverCrashGuard
{
public:
explicit D3D9VideoCrashGuard(dom::ContentParent* aContentParent = nullptr);
protected:
bool UpdateEnvironment() override;
void LogCrashRecovery() override;
void LogFeatureDisabled() override;
};
} // namespace gfx
} // namespace mozilla
#endif // gfx_src_DriverCrashGuard_h__

Просмотреть файл

@ -0,0 +1,253 @@
/* -*- 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 "DriverInitCrashDetection.h"
#include "gfxPrefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsXULAppAPI.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Services.h"
#include "mozilla/gfx/Logging.h"
namespace mozilla {
namespace gfx {
bool DriverInitCrashDetection::sDisableAcceleration = false;
bool DriverInitCrashDetection::sEnvironmentHasBeenUpdated = false;
DriverInitCrashDetection::DriverInitCrashDetection()
: mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default)
{
if (sDisableAcceleration) {
// We already disabled acceleration earlier.
return;
}
if (!mIsChromeProcess) {
// In child processes we only need to check the pref state set by the
// parent process.
sDisableAcceleration = (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered));
return;
}
if (!InitLockFilePath()) {
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Failed to create the graphics startup lockfile.";
return;
}
if (RecoverFromDriverInitCrash()) {
// This is the first time we're checking for a crash recovery, so print
// a message and disable acceleration for anyone who asks for it.
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Recovered from graphics driver startup crash; acceleration disabled.";
sDisableAcceleration = true;
return;
}
if (UpdateEnvironment() || sEnvironmentHasBeenUpdated) {
// Something in the environment changed, *or* a previous instance of this
// class already updated the environment. Allow a fresh attempt at driver
// acceleration. This doesn't mean the previous attempt failed, it just
// means we want to detect whether the new environment crashes.
AllowDriverInitAttempt();
sEnvironmentHasBeenUpdated = true;
return;
}
RecordTelemetry(TelemetryState::Okay);
}
DriverInitCrashDetection::~DriverInitCrashDetection()
{
if (mLockFile) {
mLockFile->Remove(false);
}
if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Attempting)) {
// If we attempted to initialize the driver, and got this far without
// crashing, assume everything is okay.
gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Okay));
#ifdef MOZ_CRASHREPORTER
// Remove the crash report annotation.
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
NS_LITERAL_CSTRING(""));
#endif
}
}
bool
DriverInitCrashDetection::InitLockFilePath()
{
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mLockFile));
if (!mLockFile) {
return false;
}
if (!NS_SUCCEEDED(mLockFile->AppendNative(NS_LITERAL_CSTRING("gfxinit.lock")))) {
return false;
}
return true;
}
void
DriverInitCrashDetection::AllowDriverInitAttempt()
{
// Create a temporary tombstone/lockfile.
FILE* fp;
if (!NS_SUCCEEDED(mLockFile->OpenANSIFileDesc("w", &fp))) {
return;
}
fclose(fp);
gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Attempting));
// Flush preferences, so if we crash, we don't think the environment has changed again.
FlushPreferences();
// If we crash, we'll just lose this. Not a big deal, next startup we'll
// record the failure.
RecordTelemetry(TelemetryState::EnvironmentChanged);
#ifdef MOZ_CRASHREPORTER
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
NS_LITERAL_CSTRING("1"));
#endif
}
bool
DriverInitCrashDetection::RecoverFromDriverInitCrash()
{
bool exists;
if (mLockFile &&
NS_SUCCEEDED(mLockFile->Exists(&exists)) &&
exists)
{
// If we get here, we've just recovered from a crash. Disable acceleration
// until the environment changes. Since we may have crashed before
// preferences we're flushed, we cache the environment again, then flush
// preferences so child processes can start right away.
gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Recovered));
UpdateEnvironment();
FlushPreferences();
RecordTelemetry(TelemetryState::RecoveredFromCrash);
return true;
}
if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered)) {
// If we get here, we crashed in the current environment and have already
// disabled acceleration.
RecordTelemetry(TelemetryState::AccelerationDisabled);
return true;
}
return false;
}
bool
DriverInitCrashDetection::UpdateEnvironment()
{
mGfxInfo = services::GetGfxInfo();
bool changed = false;
if (mGfxInfo) {
nsString value;
// Driver properties.
mGfxInfo->GetAdapterDriverVersion(value);
changed |= CheckAndUpdatePref("gfx.driver-init.driverVersion", value);
mGfxInfo->GetAdapterDeviceID(value);
changed |= CheckAndUpdatePref("gfx.driver-init.deviceID", value);
// Feature status.
#if defined(XP_WIN)
bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
(!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d2d", d2dEnabled);
bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
d3d11Enabled = false;
}
changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d3d11", d3d11Enabled);
#endif
}
// Firefox properties.
changed |= CheckAndUpdatePref("gfx.driver-init.appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
// Finally, mark as changed if the status has been reset by the user.
changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None));
mGfxInfo = nullptr;
return changed;
}
bool
DriverInitCrashDetection::FeatureEnabled(int aFeature)
{
int32_t status;
if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) {
return false;
}
return status == nsIGfxInfo::FEATURE_STATUS_OK;
}
bool
DriverInitCrashDetection::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue)
{
bool oldValue;
if (NS_SUCCEEDED(Preferences::GetBool(aPrefName, &oldValue)) &&
oldValue == aCurrentValue)
{
return false;
}
Preferences::SetBool(aPrefName, aCurrentValue);
return true;
}
bool
DriverInitCrashDetection::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue)
{
nsAdoptingString oldValue = Preferences::GetString(aPrefName);
if (oldValue == aCurrentValue) {
return false;
}
Preferences::SetString(aPrefName, aCurrentValue);
return true;
}
void
DriverInitCrashDetection::FlushPreferences()
{
if (nsIPrefService* prefService = Preferences::GetService()) {
prefService->SavePrefFile(nullptr);
}
}
void
DriverInitCrashDetection::RecordTelemetry(TelemetryState aState)
{
// Since we run this in each child process, we only want the initial results
// from the chrome process.
if (XRE_GetProcessType() != GeckoProcessType_Default) {
return;
}
// Since we instantiate this class more than once, make sure we only record
// the first state (since that is really all we care about).
static bool sTelemetryStateRecorded = false;
if (sTelemetryStateRecorded) {
return;
}
Telemetry::Accumulate(Telemetry::GRAPHICS_DRIVER_STARTUP_TEST, int32_t(aState));
sTelemetryStateRecorded = true;
}
} // namespace gfx
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,76 @@
/* -*- 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/. */
#ifndef gfx_src_DriverInitCrashDetection_h__
#define gfx_src_DriverInitCrashDetection_h__
#include "gfxCore.h"
#include "nsCOMPtr.h"
#include "nsIGfxInfo.h"
#include "nsIFile.h"
namespace mozilla {
namespace gfx {
enum class DriverInitStatus
{
// Drivers have not been initialized yet.
None,
// We're attempting to initialize drivers.
Attempting,
// Drivers were successfully initialized last run.
Okay,
// We crashed during driver initialization, and have restarted.
Recovered
};
class DriverInitCrashDetection
{
public:
DriverInitCrashDetection();
~DriverInitCrashDetection();
bool DisableAcceleration() const {
return sDisableAcceleration;
}
// These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST).
// Values should not change; add new values to the end.
enum class TelemetryState {
Okay = 0,
EnvironmentChanged = 1,
RecoveredFromCrash = 2,
AccelerationDisabled = 3
};
private:
bool InitLockFilePath();
bool UpdateEnvironment();
bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue);
bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue);
bool FeatureEnabled(int aFeature);
void AllowDriverInitAttempt();
bool RecoverFromDriverInitCrash();
void FlushPreferences();
void RecordTelemetry(TelemetryState aState);
private:
static bool sDisableAcceleration;
static bool sEnvironmentHasBeenUpdated;
private:
bool mIsChromeProcess;
nsCOMPtr<nsIGfxInfo> mGfxInfo;
nsCOMPtr<nsIFile> mLockFile;
};
} // namespace gfx
} // namespace mozilla
#endif // gfx_src_DriverInitCrashDetection_h__

Просмотреть файл

@ -14,7 +14,7 @@ XPIDL_MODULE = 'gfx'
DEFINES['MOZ_APP_VERSION'] = '"%s"' % CONFIG['MOZ_APP_VERSION']
EXPORTS += [
'DriverCrashGuard.h',
'DriverInitCrashDetection.h',
'FilterSupport.h',
'gfxCore.h',
'gfxCrashReporterUtils.h',
@ -54,7 +54,7 @@ if CONFIG['MOZ_X11']:
]
UNIFIED_SOURCES += [
'DriverCrashGuard.cpp',
'DriverInitCrashDetection.cpp',
'FilterSupport.cpp',
'gfxCrashReporterUtils.cpp',
'gfxTelemetry.cpp',
@ -77,12 +77,6 @@ SOURCES += [
FAIL_ON_WARNINGS = True
include('/ipc/chromium/chromium-config.mozbuild')
LOCAL_INCLUDES += [
'/dom/ipc', # for ContentChild.h
]
FINAL_LIBRARY = 'xul'
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']

Просмотреть файл

@ -232,6 +232,9 @@ private:
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false);
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
// This should be set to values in the DriverInitStatus enumeration found in
// DriverInitCrashDetection.h.
DECL_GFX_PREF(Live, "gfx.driver-init.status", DriverInitStatus, int32_t, 0);
DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.enabled", DirectWriteFontRenderingEnabled, bool, false);
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);

Просмотреть файл

@ -73,7 +73,7 @@
#include "gfxPrefs.h"
#include "VsyncSource.h"
#include "DriverCrashGuard.h"
#include "DriverInitCrashDetection.h"
#include "mozilla/dom/ContentParent.h"
using namespace mozilla;
@ -2183,8 +2183,8 @@ gfxWindowsPlatform::InitializeDevices()
// If we previously crashed initializing devices, bail out now. This is
// effectively a parent-process only check, since the content process
// cannot create a lock file.
D3D11LayersCrashGuard detectCrashes;
if (detectCrashes.Crashed()) {
DriverInitCrashDetection detectCrashes;
if (detectCrashes.DisableAcceleration()) {
mAcceleration = FeatureStatus::Blocked;
return;
}