Bug 1432429 Switch Fuzzyfox over to a pref 11/14
MozReview-Commit-ID: LSMpcxQ5IN3
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1203,16 +1203,19 @@ pref("services.sync.prefs.sync.privacy.c
pref("services.sync.prefs.sync.privacy.clearOnShutdown.cookies", true);
pref("services.sync.prefs.sync.privacy.clearOnShutdown.downloads", true);
pref("services.sync.prefs.sync.privacy.clearOnShutdown.formdata", true);
pref("services.sync.prefs.sync.privacy.clearOnShutdown.history", true);
pref("services.sync.prefs.sync.privacy.clearOnShutdown.offlineApps", true);
pref("services.sync.prefs.sync.privacy.clearOnShutdown.sessions", true);
pref("services.sync.prefs.sync.privacy.clearOnShutdown.siteSettings", true);
pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
+pref("services.sync.prefs.sync.privacy.fuzzyfox.enabled", true);
+pref("services.sync.prefs.sync.privacy.fuzzyfox.clockgrainus", true);
+pref("services.sync.prefs.sync.privacy.fuzzyfox.durationus", true);
pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true);
pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true);
pref("services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled", true);
pref("services.sync.prefs.sync.privacy.resistFingerprinting", true);
pref("services.sync.prefs.sync.privacy.reduceTimerPrecision", true);
pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.microseconds", true);
pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.jitter", true);
pref("services.sync.prefs.sync.security.OCSP.enabled", true);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1294,16 +1294,21 @@ pref("privacy.firstparty.isolate.restric
// Anti-fingerprinting, disabled by default
pref("privacy.resistFingerprinting", false);
// We automatically decline canvas permission requests if they are not initiated
// from user input. Just in case that breaks something, we allow the user to revert
// this behaior with this obscure pref. We do not intend to support this long term.
// If you do set it, to work around some broken website, please file a bug with
// information so we can understand why it is needed.
pref("privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts", true);
+
+pref("privacy.fuzzyfox.enabled", false);
+pref("privacy.fuzzyfox.clockgrainus", 100);
+pref("privacy.fuzzyfox.durationus", 2000);
+
// A subset of Resist Fingerprinting protections focused specifically on timers for testing
// This affects the Animation API, the performance APIs, Date.getTime, Event.timestamp,
// File.lastModified, audioContext.currentTime, canvas.captureStream.currentTime
pref("privacy.reduceTimerPrecision", true);
// Dynamically tune the resolution of the timer reduction for both of the two above prefs
pref("privacy.resistFingerprinting.reduceTimerPrecision.microseconds", 1000);
// Enable jittering the clock one precision value forward
pref("privacy.resistFingerprinting.reduceTimerPrecision.jitter", true);
--- a/mozglue/misc/TimeStamp.cpp
+++ b/mozglue/misc/TimeStamp.cpp
@@ -41,16 +41,30 @@ struct TimeStampInitialization
};
~TimeStampInitialization()
{
TimeStamp::Shutdown();
};
};
+bool TimeStamp::sFuzzyfoxEnabled;
+
+/* static */ bool
+TimeStamp::GetFuzzyfoxEnabled()
+{
+ return sFuzzyfoxEnabled;
+}
+
+/* static */ void
+TimeStamp::SetFuzzyfoxEnabled(bool aValue)
+{
+ sFuzzyfoxEnabled = aValue;
+}
+
#ifdef XP_WIN
static Atomic<uint64_t> sCanonicalGTC;
static Atomic<uint64_t> sCanonicalQPC;
static Atomic<bool> sCanonicalHasQPC;
#else
static Atomic<uint64_t> sCanonicalNow;
#endif
@@ -106,28 +120,35 @@ TimeStamp::RecordProcessRestart()
MFBT_API TimeStamp
TimeStamp::NowFuzzy(TimeStampValue aValue)
{
#ifdef XP_WIN
TimeStampValue canonicalNow = TimeStampValue(sCanonicalGTC, sCanonicalQPC, sCanonicalHasQPC);
#else
TimeStampValue canonicalNow = sCanonicalNow;
#endif
- if(canonicalNow > 0) {
+ if (TimeStamp::GetFuzzyfoxEnabled()) {
+ if(MOZ_LIKELY(canonicalNow > 0)) {
+ return TimeStamp(canonicalNow, true);
+ }
+ }
+ // When we disable Fuzzyfox, time may goes backwards, so we need to make sure
+ // we don't do that.
+ else if (MOZ_UNLIKELY(canonicalNow > aValue)) {
return TimeStamp(canonicalNow, true);
}
return TimeStamp(aValue);
}
MFBT_API void
TimeStamp::UpdateFuzzyTimeStamp(TimeStamp aValue)
{
#ifdef XP_WIN
sCanonicalGTC = aValue.mValue.mGTC;
sCanonicalQPC = aValue.mValue.mQPC;
sCanonicalHasQPC = aValue.mValue.mHasQPC;
#else
- sCanonicalNow = aValue;
+ sCanonicalNow = aValue.mValue;
#endif
}
} // namespace mozilla
--- a/mozglue/misc/TimeStamp.h
+++ b/mozglue/misc/TimeStamp.h
@@ -451,16 +451,18 @@ public:
* |if (timestamp) { ... }|
*/
explicit operator bool() const
{
return mValue != 0;
}
bool UsedCanonicalNow() const { return mUsedCanonicalNow; }
+ static MFBT_API bool GetFuzzyfoxEnabled();
+ static MFBT_API void SetFuzzyfoxEnabled(bool aValue);
/**
* Return a timestamp reflecting the current elapsed system time. This
* is monotonically increasing (i.e., does not decrease) over the
* lifetime of this process' XPCOM session.
*
* Now() is trying to ensure the best possible precision on each platform,
* at least one millisecond.
@@ -600,16 +602,18 @@ public:
// be allowed.
static MFBT_API void Startup();
static MFBT_API void Shutdown();
private:
friend struct IPC::ParamTraits<mozilla::TimeStamp>;
+ static bool sFuzzyfoxEnabled;
+
MOZ_IMPLICIT TimeStamp(TimeStampValue aValue)
: mValue(aValue)
, mUsedCanonicalNow(false)
{}
MOZ_IMPLICIT TimeStamp(TimeStampValue aValue, bool aUsedCanonicalNow)
: mValue(aValue)
, mUsedCanonicalNow(aUsedCanonicalNow)
--- a/toolkit/components/fuzzyfox/Fuzzyfox.cpp
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.cpp
@@ -1,39 +1,40 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "Fuzzyfox.h"
#include "mozilla/Logging.h"
+#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/TimeStamp.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserverService.h"
#include "nsISupportsPrimitives.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsServiceManagerUtils.h"
#include "prrng.h"
#include "prtime.h"
// For usleep/Sleep & QueryPerformanceFrequency
#ifdef XP_WIN
#include <windows.h>
#else
#include <unistd.h>
#endif
using namespace mozilla;
static LazyLogModule sFuzzyfoxLog("Fuzzyfox");
-#define PT_STATIC_CLOCK_GRAIN 80
-#define PT_DURATION_CENTER 100000
-
#define US_TO_NS(x) ((x)*1000)
#define NS_TO_US(x) ((x)/1000)
#ifdef LOG
#undef LOG
#endif
#define LOG(level, args) MOZ_LOG(sFuzzyfoxLog, mozilla::LogLevel::level, args)
@@ -57,68 +58,162 @@ static LazyLogModule sFuzzyfoxLog("Fuzzy
#define mt2ms_f(x) (double(x) / sFrequencyPerSec)
// Result of QueryPerformanceFrequency
// We use default of 1 for the case we can't use QueryPerformanceCounter
// to make mt/ms conversions work despite that.
static uint64_t sFrequencyPerSec = 1;
#endif
+#define FUZZYFOX_ENABLED_PREF "privacy.fuzzyfox.enabled"
+#define FUZZYFOX_ENABLED_PREF_DEFAULT false
+#define FUZZYFOX_CLOCKGRAIN_PREF "privacy.fuzzyfox.clockgrainus"
+#define FUZZYFOX_CLOCKGRAIN_PREF_DEFAULT 100
+#define FUZZYFOX_DURATION_PREF "privacy.fuzzyfox.durationus"
+#define FUZZYFOX_DURATION_PREF_DEFAULT 2000
+
+Atomic<bool, Relaxed> Fuzzyfox::sFuzzyfoxEnabledPrefMapped;
+Atomic<uint32_t, Relaxed> Fuzzyfox::sFuzzyfoxClockGrain;
+Atomic<uint32_t, Relaxed> Fuzzyfox::sFuzzyfoxDuration;
+
+NS_IMPL_ISUPPORTS_INHERITED(Fuzzyfox, Runnable, nsIObserver)
+
/* static */ void
Fuzzyfox::Start()
{
MOZ_ASSERT(NS_IsMainThread());
- RefPtr<Fuzzyfox> r = new Fuzzyfox();
- SystemGroup::Dispatch(TaskCategory::Other, r.forget());
-
#ifdef XP_WIN
LARGE_INTEGER freq;
bool gotFrequency = ::QueryPerformanceFrequency(&freq);
if (!gotFrequency) {
LOG(Error, ("QueryPerformanceFrequency did not succeed"));
return;
}
sFrequencyPerSec = freq.QuadPart;
LOG(Debug, ("TimeStamp: QPC frequency=%llu", sFrequencyPerSec));
#endif
+
+ RefPtr<Fuzzyfox> r = new Fuzzyfox();
+ SystemGroup::Dispatch(TaskCategory::Other, r.forget());
}
Fuzzyfox::Fuzzyfox()
: Runnable("Fuzzyfox")
- , mStartTime(ActualTime())
+ , mSanityCheck(false)
+ , mStartTime(0)
, mDuration(PickDuration())
, mTickType(eUptick)
{
MOZ_ASSERT(NS_IsMainThread());
+
+ // [[ I originally ran this after observing profile-after-change, but
+ // it turned out that this contructor was getting called _after_ that
+ // event had already fired. ]]
+ Preferences::AddAtomicBoolVarCache(&sFuzzyfoxEnabledPrefMapped,
+ FUZZYFOX_ENABLED_PREF,
+ FUZZYFOX_ENABLED_PREF_DEFAULT);
+ Preferences::AddAtomicUintVarCache(&sFuzzyfoxClockGrain,
+ FUZZYFOX_CLOCKGRAIN_PREF,
+ FUZZYFOX_CLOCKGRAIN_PREF_DEFAULT);
+ Preferences::AddAtomicUintVarCache(&sFuzzyfoxDuration,
+ FUZZYFOX_DURATION_PREF,
+ FUZZYFOX_DURATION_PREF_DEFAULT);
+
+ LOG(Info, ("PT(%p) Created Fuzzyfox, sFuzzyfoxEnabled is now %s \n",
+ this, (sFuzzyfoxEnabledPrefMapped ? "enabled" : "disabled")));
+
+ TimeStamp::SetFuzzyfoxEnabled(sFuzzyfoxEnabledPrefMapped);
+
+ // Should I see if these fail? And do what?
+ nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+ prefs->AddObserver(FUZZYFOX_ENABLED_PREF, this, false);
+ prefs->AddObserver(FUZZYFOX_CLOCKGRAIN_PREF, this, false);
+ prefs->AddObserver(FUZZYFOX_DURATION_PREF, this, false);
}
Fuzzyfox::~Fuzzyfox() = default;
NS_IMETHODIMP
+Fuzzyfox::Observe(nsISupports* aObject, const char* aTopic,
+ const char16_t* aMessage)
+{
+ if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
+ NS_ConvertUTF16toUTF8 pref(aMessage);
+
+ if (pref.EqualsLiteral(FUZZYFOX_ENABLED_PREF)) {
+ LOG(Info, ("PT(%p) Observed a pref change, sFuzzyfoxEnabled is now %s \n",
+ this, (sFuzzyfoxEnabledPrefMapped ? "enabled" : "disabled")));
+
+
+ TimeStamp::SetFuzzyfoxEnabled(sFuzzyfoxEnabledPrefMapped);
+
+
+ if (TimeStamp::GetFuzzyfoxEnabled()) {
+ // Queue a runnable
+ nsCOMPtr<nsIRunnable> r = this;
+ SystemGroup::Dispatch(TaskCategory::Other, r.forget());
+ } else {
+ mStartTime = 0;
+ mTickType = eUptick;
+ mSanityCheck = false;
+ }
+ }
+ }
+ return NS_OK;
+}
#define QUEUE_AND_RETURN() \
nsCOMPtr<nsIRunnable> r = this; \
SystemGroup::Dispatch(TaskCategory::Other, r.forget()); \
return NS_OK
NS_IMETHODIMP
Fuzzyfox::Run()
{
MOZ_ASSERT(NS_IsMainThread());
+ if (!TimeStamp::GetFuzzyfoxEnabled()) {
+ LOG(Info, ("[FuzzyfoxEvent] PT(%p) Fuzzyfox is shut down, doing nothing \n", this));
+ return NS_OK;
+ } else if (mStartTime == 0) {
+ // This is the first time we are running afer enabling FuzzyFox. We need
+ // to prevent time from going backwards, so for the first run we round the time up
+ // to the next grain.
+ mStartTime = CeilToGrain(ActualTime());
+ TimeStamp newTimeStamp = CeilToGrain(TimeStamp::NowReally());
+ Fuzzyfox::UpdateClocks(mStartTime, newTimeStamp);
+
+ mSanityCheck = true;
+ LOG(Info, ("[FuzzyfoxEvent] PT(%p) Going to start Fuzzyfox, queuing up the job \n",
+ this));
+
+ QUEUE_AND_RETURN();
+ }
// We need to check how long its been since we ran
uint64_t endTime = ActualTime();
uint64_t remaining = 0;
uint64_t durationCount = 1;
// Pick the amount to sleep
- if ((endTime - mStartTime) > mDuration) {
+ if (endTime < mStartTime) {
+ // This can only happen if we just enabled FuzzyFox, rounded up, and then re-ran the
+ // runnable before we advanced to the next grain.
+ // If that happens, then repeat the current time.
+ // We use mSanityCheck just to be sure (and will eventually remove it.)
+ MOZ_ASSERT(mSanityCheck);
+ LOG(Debug, ("[FuzzyfoxEvent] PT(%p) endTime < mStartTime mStartTime %" PRIu64 " endTime %" PRIu64 " \n",
+ this, mStartTime, endTime));
+
+ mSanityCheck = true;
+ QUEUE_AND_RETURN();
+ }
+ else if ((endTime - mStartTime) > mDuration) {
// We ran over our budget!
uint64_t over = (endTime - mStartTime) - mDuration;
LOG(Verbose, ("[FuzzyfoxEvent] PT(%p) Overran budget of %" PRIu32 " by %" PRIu64 " \n",
this, mDuration, over));
//TODO: this should probably influence uptick/downtick stuff, and it doesn't
uint64_t nextDuration = PickDuration();
while (over > nextDuration) {
@@ -130,28 +225,31 @@ Fuzzyfox::Run()
remaining = nextDuration - over;
} else {
// Didn't go over budget
remaining = mDuration - (endTime - mStartTime);
LOG(Verbose, ("[FuzzyfoxEvent] PT(%p) Finishing budget of %" PRIu32 " with %" PRIu64 " \n",
this, mDuration, remaining));
}
+ mSanityCheck = false;
// Sleep for now
#ifdef XP_WIN
Sleep(remaining);
#else
usleep(remaining);
#endif
//TODO we slept extra long almost certainly, what do we do about that?
// Update clocks (and fire pending events etc)
- UpdateClocks();
+ uint64_t newTime = FloorToGrain(ActualTime());
+ TimeStamp newTimeStamp = FloorToGrain(TimeStamp::NowReally());
+ UpdateClocks(newTime, newTimeStamp);
// Reset values
mTickType = mTickType == eUptick ? eDowntick : eUptick;
mStartTime = ActualTime();
mDuration = PickDuration();
QUEUE_AND_RETURN();
}
@@ -166,30 +264,27 @@ Fuzzyfox::ActualTime()
}
uint64_t
Fuzzyfox::PickDuration()
{
// TODO: Fix to be secure
long int rval = rand();
- // We want uniform distribution from 1->PT_DURATION_CENTER*2
- // so that the mean is PT_DURATION_CENTER
- return 1 + (rval % (PT_DURATION_CENTER * 2));
+ // Avoid divide by zero errors
+ uint32_t duration = sFuzzyfoxDuration <= 0 ? 1 : sFuzzyfoxDuration;
+
+ // We want uniform distribution from 1->duration*2
+ // so that the mean is duration
+ return 1 + (rval % (duration * 2));
}
void
-Fuzzyfox::UpdateClocks()
+Fuzzyfox::UpdateClocks(uint64_t aNewTime, TimeStamp aNewTimeStamp)
{
- uint64_t time = ActualTime();
- TimeStamp timestamp = TimeStamp::NowReally();
-
- uint64_t newTime = RoundToGrain(time);
- TimeStamp newTimeStamp = RoundToGrain(timestamp);
-
// newTime is the new canonical time for this scope!
#ifndef XP_WIN
LOG(Verbose, ("[Time] New time is %" PRIu64 " (compare to %" PRIu64 ") and timestamp is %" PRIu64 " (compare to %" PRIu64 ")\n",
aNewTime, ActualTime(), aNewTimeStamp.mValue, TimeStamp::NowReally().mValue));
#else
LOG(Verbose, ("[Time] New time is %" PRIu64 " (compare to %" PRIu64 ") \n", aNewTime, ActualTime()));
#endif
@@ -205,51 +300,93 @@ Fuzzyfox::UpdateClocks()
}
nsCOMPtr<nsISupportsPRInt64> wrapper =
do_CreateInstance(NS_SUPPORTS_PRINT64_CONTRACTID);
if (NS_WARN_IF(!wrapper)) {
return;
}
- wrapper->SetData(newTime);
+ wrapper->SetData(aNewTime);
// Clocks get the official 'realtime' time in microseconds
// This happens on all ticks
os->NotifyObservers(wrapper, "fuzzyfox-update-clocks", nullptr);
// Update the timestamp canonicaltime
- TimeStamp::UpdateFuzzyTimeStamp(newTimeStamp);
+ TimeStamp::UpdateFuzzyTimeStamp(aNewTimeStamp);
}
uint64_t
Fuzzyfox::GetClockGrain()
{
- // Static for now
- // Should be reading from some config probably
- return PT_STATIC_CLOCK_GRAIN;
+ return sFuzzyfoxClockGrain;
+}
+
+
+/*
+ * FloorToGrain accepts a timestamp in microsecond precision
+ * and returns it in microseconds, rounded down to the nearest
+ * ClockGrain value.
+ */
+uint64_t
+Fuzzyfox::FloorToGrain(uint64_t aValue)
+{
+ return aValue - (aValue % GetClockGrain());
}
-uint64_t
-Fuzzyfox::RoundToGrain(uint64_t aValue)
+
+/*
+ * FloorToGrain accepts a timestamp and returns it, rounded down
+ * to the nearest ClockGrain value.
+ */
+TimeStamp
+Fuzzyfox::FloorToGrain(TimeStamp aValue)
{
+#ifdef XP_WIN
+ // grain is in us
uint64_t grain = GetClockGrain();
- return US_TO_NS(aValue - (aValue % grain));
+ // GTC and QPS are stored in |mt| and need to be converted to
+ uint64_t GTC = mt2ms(aValue.mValue.mGTC) * 1000;
+ uint64_t QPC = mt2ms(aValue.mValue.mQPC) * 1000;
+
+ return TimeStamp(TimeStampValue(
+ ms2mt((GTC - (GTC % grain)) / 1000),
+ ms2mt((QPC - (QPC % grain)) / 1000),
+ aValue.mValue.mHasQPC), true);
+#else
+ return TimeStamp(US_TO_NS(FloorToGrain(NS_TO_US(aValue.mValue))));
+#endif
}
+/*
+ * CeilToGrain accepts a timestamp in microsecond precision
+ * and returns it in microseconds, rounded up to the nearest
+ * ClockGrain value.
+ */
+uint64_t
+Fuzzyfox::CeilToGrain(uint64_t aValue)
+{
+ return (aValue / GetClockGrain()) * GetClockGrain();
+}
+
+/*
+ * CeilToGrain accepts a timestamp and returns it, rounded up
+ * to the nearest ClockGrain value.
+ */
TimeStamp
-Fuzzyfox::RoundToGrain(TimeStamp aValue)
+Fuzzyfox::CeilToGrain(TimeStamp aValue)
{
#ifdef XP_WIN
// grain is in us
uint64_t grain = GetClockGrain();
// GTC and QPS are stored in |mt| and need to be converted
- uint64_t GTC = mt2ms(aValue.mValue.mGTC);
- uint64_t QPC = mt2ms(aValue.mValue.mQPC);
+ uint64_t GTC = mt2ms(aValue.mValue.mGTC) * 1000;
+ uint64_t QPC = mt2ms(aValue.mValue.mQPC) * 1000;
return TimeStamp(TimeStampValue(
- ms2mt(GTC - (GTC % grain)),
- ms2mt(GTC - (GTC % grain)),
+ ms2mt(((GTC / grain) * grain) / 1000),
+ ms2mt(((QPC / grain) * grain) / 1000),
aValue.mValue.mHasQPC), true);
#else
- return TimeStamp(RoundToGrain(aValue.mValue));
+ return TimeStamp(US_TO_NS(CeilToGrain(NS_TO_US(aValue.mValue))));
#endif
}
\ No newline at end of file
--- a/toolkit/components/fuzzyfox/Fuzzyfox.h
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.h
@@ -2,58 +2,76 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 mozilla_Fuzzyfox_h
#define mozilla_Fuzzyfox_h
+#include "nsIObserver.h"
#include "nsThreadUtils.h"
#include "mozilla/TimeStamp.h"
namespace mozilla {
-class Fuzzyfox final : public Runnable
+class Fuzzyfox final : public Runnable, public nsIObserver
{
public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIOBSERVER
+
static void
Start();
NS_IMETHOD
Run() override;
+ static bool
+ Enabled();
+
private:
Fuzzyfox();
~Fuzzyfox();
uint64_t
ActualTime();
uint64_t
PickDuration();
void
- UpdateClocks();
+ UpdateClocks(uint64_t aNewTime, TimeStamp aNewTimeStamp);
uint64_t
GetClockGrain();
uint64_t
- RoundToGrain(uint64_t aValue);
+ FloorToGrain(uint64_t aValue);
TimeStamp
- RoundToGrain(TimeStamp aValue);
+ FloorToGrain(TimeStamp aValue);
+
+ uint64_t
+ CeilToGrain(uint64_t aValue);
+ TimeStamp
+ CeilToGrain(TimeStamp aValue);
+
+ bool mSanityCheck;
uint64_t mStartTime;
uint32_t mDuration;
enum Tick {
eUptick,
eDowntick,
};
Tick mTickType;
+
+ static Atomic<bool, Relaxed> sFuzzyfoxEnabledPrefMapped;
+ static Atomic<uint32_t, Relaxed> sFuzzyfoxClockGrain;
+ static Atomic<uint32_t, Relaxed> sFuzzyfoxDuration;
};
} // mozilla namespace
#endif /* mozilla_Fuzzyfox_h */