2017-10-27 22:55:37 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2017-10-27 23:10:06 +00:00
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2016-04-29 04:52:54 +00:00
|
|
|
/* 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/. */
|
2016-08-16 22:41:12 +00:00
|
|
|
|
2016-04-29 04:52:56 +00:00
|
|
|
#include "gfxFeature.h"
|
2016-08-16 22:41:12 +00:00
|
|
|
|
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "mozilla/Sprintf.h"
|
2016-05-07 02:01:58 +00:00
|
|
|
#include "nsString.h"
|
2016-04-29 04:52:54 +00:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace gfx {
|
|
|
|
|
2016-04-29 04:52:55 +00:00
|
|
|
bool FeatureState::IsEnabled() const {
|
2016-05-12 17:30:54 +00:00
|
|
|
return IsInitialized() && IsFeatureStatusSuccess(GetValue());
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:54 +00:00
|
|
|
FeatureStatus FeatureState::GetValue() const {
|
2016-08-21 03:59:10 +00:00
|
|
|
if (!IsInitialized()) {
|
|
|
|
return FeatureStatus::Unused;
|
|
|
|
}
|
2016-04-29 04:52:55 +00:00
|
|
|
|
2016-04-29 04:52:54 +00:00
|
|
|
if (mRuntime.mStatus != FeatureStatus::Unused) {
|
|
|
|
return mRuntime.mStatus;
|
|
|
|
}
|
2016-04-29 04:52:55 +00:00
|
|
|
if (mUser.mStatus == FeatureStatus::ForceEnabled) {
|
|
|
|
return FeatureStatus::ForceEnabled;
|
|
|
|
}
|
|
|
|
if (mEnvironment.mStatus != FeatureStatus::Unused) {
|
|
|
|
return mEnvironment.mStatus;
|
|
|
|
}
|
2016-04-29 04:52:54 +00:00
|
|
|
if (mUser.mStatus != FeatureStatus::Unused) {
|
|
|
|
return mUser.mStatus;
|
|
|
|
}
|
|
|
|
return mDefault.mStatus;
|
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:55 +00:00
|
|
|
bool FeatureState::SetDefault(bool aEnable, FeatureStatus aDisableStatus,
|
|
|
|
const char* aDisableMessage) {
|
|
|
|
if (!aEnable) {
|
2016-06-03 18:54:56 +00:00
|
|
|
DisableByDefault(aDisableStatus, aDisableMessage,
|
|
|
|
"FEATURE_FAILURE_DISABLED"_ns);
|
2016-04-29 04:52:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EnableByDefault();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:56 +00:00
|
|
|
void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
|
2020-05-04 01:01:53 +00:00
|
|
|
bool aDefaultValue,
|
|
|
|
Maybe<bool> aUserValue) {
|
2017-11-14 08:06:01 +00:00
|
|
|
bool baseValue =
|
|
|
|
Preferences::GetBool(aPrefName, aDefaultValue, PrefValueKind::Default);
|
2016-04-29 04:52:56 +00:00
|
|
|
SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled,
|
|
|
|
"Disabled by default");
|
|
|
|
|
2020-05-04 01:01:53 +00:00
|
|
|
if (aUserValue) {
|
|
|
|
if (*aUserValue == aIsEnablePref) {
|
2016-05-07 02:01:58 +00:00
|
|
|
nsCString message("Enabled via ");
|
|
|
|
message.AppendASCII(aPrefName);
|
|
|
|
UserEnable(message.get());
|
2016-04-29 04:52:56 +00:00
|
|
|
} else {
|
2016-05-07 02:01:58 +00:00
|
|
|
nsCString message("Disabled via ");
|
|
|
|
message.AppendASCII(aPrefName);
|
2016-06-03 18:54:56 +00:00
|
|
|
UserDisable(message.get(), "FEATURE_FAILURE_PREF_OFF"_ns);
|
2016-04-29 04:52:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-04 01:01:53 +00:00
|
|
|
void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref,
|
|
|
|
bool aDefaultValue) {
|
|
|
|
Maybe<bool> userValue;
|
|
|
|
if (Preferences::HasUserValue(aPrefName)) {
|
|
|
|
userValue.emplace(Preferences::GetBool(aPrefName, aDefaultValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDefaultFromPref(aPrefName, aIsEnablePref, aDefaultValue, userValue);
|
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:55 +00:00
|
|
|
bool FeatureState::InitOrUpdate(bool aEnable, FeatureStatus aDisableStatus,
|
|
|
|
const char* aDisableMessage) {
|
|
|
|
if (!IsInitialized()) {
|
|
|
|
return SetDefault(aEnable, aDisableStatus, aDisableMessage);
|
|
|
|
}
|
2016-06-03 18:54:56 +00:00
|
|
|
return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage, nsCString());
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FeatureState::UserEnable(const char* aMessage) {
|
|
|
|
AssertInitialized();
|
2020-09-25 14:11:52 +00:00
|
|
|
SetUser(FeatureStatus::Available, aMessage, nsCString());
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FeatureState::UserForceEnable(const char* aMessage) {
|
|
|
|
AssertInitialized();
|
2020-09-25 14:11:52 +00:00
|
|
|
SetUser(FeatureStatus::ForceEnabled, aMessage, nsCString());
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
void FeatureState::UserDisable(const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:55 +00:00
|
|
|
AssertInitialized();
|
2020-09-25 14:11:52 +00:00
|
|
|
SetUser(FeatureStatus::Disabled, aMessage, aFailureId);
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
void FeatureState::Disable(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:55 +00:00
|
|
|
AssertInitialized();
|
|
|
|
|
|
|
|
// We should never bother setting an environment status to "enabled," since
|
|
|
|
// it could override an explicit user decision to disable it.
|
|
|
|
MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
SetEnvironment(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
void FeatureState::SetFailed(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:55 +00:00
|
|
|
AssertInitialized();
|
|
|
|
|
|
|
|
// We should never bother setting a runtime status to "enabled," since it
|
|
|
|
// could override an explicit user decision to disable it.
|
|
|
|
MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
SetRuntime(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
bool FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus,
|
|
|
|
const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:55 +00:00
|
|
|
if (!aEnable) {
|
2016-06-03 18:54:56 +00:00
|
|
|
SetFailed(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
bool FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
|
|
|
return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage,
|
|
|
|
aFailureId);
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:54 +00:00
|
|
|
bool FeatureState::DisabledByDefault() const {
|
|
|
|
return mDefault.mStatus != FeatureStatus::Available;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FeatureState::IsForcedOnByUser() const {
|
2016-04-29 04:52:55 +00:00
|
|
|
AssertInitialized();
|
2016-04-29 04:52:54 +00:00
|
|
|
return mUser.mStatus == FeatureStatus::ForceEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FeatureState::EnableByDefault() {
|
|
|
|
// User/runtime decisions should not have been made yet.
|
2016-04-29 04:52:56 +00:00
|
|
|
MOZ_ASSERT(!mUser.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mEnvironment.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mRuntime.IsInitialized());
|
2016-04-29 04:52:54 +00:00
|
|
|
|
|
|
|
mDefault.Set(FeatureStatus::Available);
|
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
void FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:54 +00:00
|
|
|
// User/runtime decisions should not have been made yet.
|
2016-04-29 04:52:56 +00:00
|
|
|
MOZ_ASSERT(!mUser.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mEnvironment.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mRuntime.IsInitialized());
|
2016-04-29 04:52:54 +00:00
|
|
|
|
2017-02-24 20:43:33 +00:00
|
|
|
// Make sure that when disabling we actually use a failure status.
|
|
|
|
MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
mDefault.Set(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:54 +00:00
|
|
|
}
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
void FeatureState::SetUser(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:55 +00:00
|
|
|
// Default decision must have been made, but not runtime or environment.
|
2016-04-29 04:52:56 +00:00
|
|
|
MOZ_ASSERT(mDefault.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mEnvironment.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mRuntime.IsInitialized());
|
2016-04-29 04:52:54 +00:00
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
mUser.Set(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:54 +00:00
|
|
|
}
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
void FeatureState::SetEnvironment(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:55 +00:00
|
|
|
// Default decision must have been made, but not runtime.
|
2016-04-29 04:52:56 +00:00
|
|
|
MOZ_ASSERT(mDefault.IsInitialized());
|
|
|
|
MOZ_ASSERT(!mRuntime.IsInitialized());
|
2016-04-29 04:52:55 +00:00
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
mEnvironment.Set(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:55 +00:00
|
|
|
}
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
void FeatureState::SetRuntime(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:56 +00:00
|
|
|
AssertInitialized();
|
2016-04-29 04:52:54 +00:00
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
mRuntime.Set(aStatus, aMessage, aFailureId);
|
2016-04-29 04:52:54 +00:00
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:55 +00:00
|
|
|
const char* FeatureState::GetRuntimeMessage() const {
|
|
|
|
MOZ_ASSERT(IsFeatureStatusFailure(mRuntime.mStatus));
|
|
|
|
return mRuntime.mMessage;
|
|
|
|
}
|
|
|
|
|
2016-04-29 04:52:56 +00:00
|
|
|
void FeatureState::ForEachStatusChange(
|
|
|
|
const StatusIterCallback& aCallback) const {
|
|
|
|
AssertInitialized();
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
aCallback("default", mDefault.mStatus, mDefault.MessageOrNull(),
|
|
|
|
mDefault.FailureId());
|
2016-04-29 04:52:56 +00:00
|
|
|
if (mUser.IsInitialized()) {
|
2022-11-22 16:00:15 +00:00
|
|
|
aCallback("user", mUser.mStatus, mUser.Message(), mUser.FailureId());
|
2016-04-29 04:52:56 +00:00
|
|
|
}
|
|
|
|
if (mEnvironment.IsInitialized()) {
|
2020-09-25 14:11:52 +00:00
|
|
|
aCallback("env", mEnvironment.mStatus, mEnvironment.Message(),
|
2022-11-22 16:00:15 +00:00
|
|
|
mEnvironment.FailureId());
|
2016-04-29 04:52:56 +00:00
|
|
|
}
|
|
|
|
if (mRuntime.IsInitialized()) {
|
2020-09-25 14:11:52 +00:00
|
|
|
aCallback("runtime", mRuntime.mStatus, mRuntime.Message(),
|
2022-11-22 16:00:15 +00:00
|
|
|
mRuntime.FailureId());
|
2016-04-29 04:52:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 03:59:11 +00:00
|
|
|
const char* FeatureState::GetFailureMessage() const {
|
|
|
|
AssertInitialized();
|
|
|
|
MOZ_ASSERT(!IsEnabled());
|
|
|
|
|
|
|
|
if (mRuntime.mStatus != FeatureStatus::Unused &&
|
|
|
|
IsFeatureStatusFailure(mRuntime.mStatus)) {
|
|
|
|
return mRuntime.mMessage;
|
|
|
|
}
|
|
|
|
if (mEnvironment.mStatus != FeatureStatus::Unused &&
|
|
|
|
IsFeatureStatusFailure(mEnvironment.mStatus)) {
|
|
|
|
return mEnvironment.mMessage;
|
|
|
|
}
|
|
|
|
if (mUser.mStatus != FeatureStatus::Unused &&
|
|
|
|
IsFeatureStatusFailure(mUser.mStatus)) {
|
|
|
|
return mUser.mMessage;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus));
|
|
|
|
return mDefault.mMessage;
|
|
|
|
}
|
|
|
|
|
2016-06-03 18:54:56 +00:00
|
|
|
const nsCString& FeatureState::GetFailureId() const {
|
|
|
|
MOZ_ASSERT(!IsEnabled());
|
2020-09-25 14:11:52 +00:00
|
|
|
|
|
|
|
if (mRuntime.mStatus != FeatureStatus::Unused) {
|
|
|
|
return mRuntime.mFailureId;
|
|
|
|
}
|
|
|
|
if (mEnvironment.mStatus != FeatureStatus::Unused) {
|
|
|
|
return mEnvironment.mFailureId;
|
|
|
|
}
|
|
|
|
if (mUser.mStatus != FeatureStatus::Unused) {
|
|
|
|
return mUser.mFailureId;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mDefault.mFailureId;
|
2016-06-03 18:54:56 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 22:39:24 +00:00
|
|
|
nsCString FeatureState::GetStatusAndFailureIdString() const {
|
|
|
|
nsCString status;
|
|
|
|
auto value = GetValue();
|
|
|
|
switch (value) {
|
|
|
|
case FeatureStatus::Blocklisted:
|
|
|
|
case FeatureStatus::Disabled:
|
|
|
|
case FeatureStatus::Unavailable:
|
|
|
|
case FeatureStatus::UnavailableNoAngle:
|
|
|
|
case FeatureStatus::Blocked:
|
|
|
|
status.AppendPrintf("%s:%s", FeatureStatusToString(value),
|
|
|
|
GetFailureId().get());
|
|
|
|
break;
|
2023-12-15 15:07:17 +00:00
|
|
|
case FeatureStatus::Failed:
|
|
|
|
status.AppendPrintf("%s:%s", FeatureStatusToString(value),
|
|
|
|
GetFailureMessage());
|
|
|
|
break;
|
2021-01-18 22:39:24 +00:00
|
|
|
default:
|
|
|
|
status.Append(FeatureStatusToString(value));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2016-08-21 03:59:11 +00:00
|
|
|
void FeatureState::Reset() {
|
|
|
|
mDefault.Set(FeatureStatus::Unused);
|
|
|
|
mUser.Set(FeatureStatus::Unused);
|
|
|
|
mEnvironment.Set(FeatureStatus::Unused);
|
|
|
|
mRuntime.Set(FeatureStatus::Unused);
|
|
|
|
}
|
|
|
|
|
2020-09-25 14:11:52 +00:00
|
|
|
void FeatureState::Instance::Set(FeatureStatus aStatus) {
|
|
|
|
mStatus = aStatus;
|
|
|
|
mMessage[0] = '\0';
|
|
|
|
mFailureId.Truncate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage,
|
|
|
|
const nsACString& aFailureId) {
|
2016-04-29 04:52:54 +00:00
|
|
|
mStatus = aStatus;
|
|
|
|
if (aMessage) {
|
2016-08-16 22:41:12 +00:00
|
|
|
SprintfLiteral(mMessage, "%s", aMessage);
|
2016-08-21 03:59:11 +00:00
|
|
|
} else {
|
|
|
|
mMessage[0] = '\0';
|
2016-04-29 04:52:54 +00:00
|
|
|
}
|
2020-09-25 14:11:52 +00:00
|
|
|
mFailureId.Assign(aFailureId);
|
2016-04-29 04:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace gfx
|
|
|
|
} // namespace mozilla
|