Bug 1443943 Port the performance APIs only to only clamping/jittering on non-System Principal r=baku
authorTom Ritter <tom@mozilla.com>
Fri, 09 Mar 2018 09:29:33 -0600
changeset 408253 a5ceb2a28cfd0267c607af9ad787fdcbce366146
parent 408252 68737a515062b449392822e9cd06292a0acf63d3
child 408254 b76d20f277db3015e0e2d8ccfe547d5f7af36ec0
push id100903
push usershindli@mozilla.com
push dateThu, 15 Mar 2018 10:18:10 +0000
treeherdermozilla-inbound@cad403cafed9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1443943
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1443943 Port the performance APIs only to only clamping/jittering on non-System Principal r=baku MozReview-Commit-ID: FKYLI5Yc1kX
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/performance/Performance.cpp
dom/performance/Performance.h
dom/performance/PerformanceMainThread.cpp
dom/performance/PerformanceNavigationTiming.h
dom/performance/PerformanceStorageWorker.cpp
dom/performance/PerformanceTiming.cpp
dom/performance/PerformanceTiming.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2361,17 +2361,17 @@ nsPIDOMWindowInner::CreatePerformanceObj
   nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
   bool timingEnabled = false;
   if (!timedChannel ||
       !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
       !timingEnabled) {
     timedChannel = nullptr;
   }
   if (timing) {
-    mPerformance = Performance::CreateForMainThread(this, timing, timedChannel);
+    mPerformance = Performance::CreateForMainThread(this, mDoc->NodePrincipal(), timing, timedChannel);
   }
 }
 
 bool
 nsPIDOMWindowInner::IsSecureContext() const
 {
   return nsGlobalWindowInner::Cast(this)->IsSecureContext();
 }
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -1857,16 +1857,17 @@ nsGlobalWindowOuter::SetNewDocument(nsID
       if (oldDoc == aDocument) {
         // Make a copy of the old window's performance object on document.open.
         // Note that we have to force eager creation of it here, because we need
         // to grab the current document channel and whatnot before that changes.
         currentInner->AsInner()->CreatePerformanceObjectIfNeeded();
         if (currentInner->mPerformance) {
           newInnerWindow->mPerformance =
             Performance::CreateForMainThread(newInnerWindow->AsInner(),
+                                             aDocument->NodePrincipal(),
                                              currentInner->mPerformance->GetDOMTiming(),
                                              currentInner->mPerformance->GetChannel());
         }
       }
 
       // Don't free objects on our current inner window if it's going to be
       // held in the bfcache.
       if (!currentInner->IsFrozen()) {
old mode 100644
new mode 100755
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -44,33 +44,36 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Perfo
                                    mUserEntries,
                                    mResourceEntries);
 
 NS_IMPL_ADDREF_INHERITED(Performance, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(Performance, DOMEventTargetHelper)
 
 /* static */ already_AddRefed<Performance>
 Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
+                                 nsIPrincipal* aPrincipal,
                                  nsDOMNavigationTiming* aDOMTiming,
                                  nsITimedChannel* aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<Performance> performance =
     new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
+  performance->mSystemPrincipal = nsContentUtils::IsSystemPrincipal(aPrincipal);
   return performance.forget();
 }
 
 /* static */ already_AddRefed<Performance>
 Performance::CreateForWorker(WorkerPrivate* aWorkerPrivate)
 {
   MOZ_ASSERT(aWorkerPrivate);
   aWorkerPrivate->AssertIsOnWorkerThread();
 
   RefPtr<Performance> performance = new PerformanceWorker(aWorkerPrivate);
+  performance->mSystemPrincipal = aWorkerPrivate->UsesSystemPrincipal();
   return performance.forget();
 }
 
 Performance::Performance()
   : mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
   , mPendingNotificationObserversTask(false)
 {
   MOZ_ASSERT(!NS_IsMainThread());
@@ -86,29 +89,40 @@ Performance::Performance(nsPIDOMWindowIn
 
 Performance::~Performance()
 {}
 
 DOMHighResTimeStamp
 Performance::Now() const
 {
   TimeDuration duration = TimeStamp::Now() - CreationTimeStamp();
-  return RoundTime(duration.ToMilliseconds());
+  DOMHighResTimeStamp rawTime = duration.ToMilliseconds();
+  if (mSystemPrincipal) {
+    return rawTime;
+  }
+
+  const double maxResolutionMs = 0.020;
+  DOMHighResTimeStamp minimallyClamped = floor(rawTime / maxResolutionMs) * maxResolutionMs;
+  return nsRFPService::ReduceTimePrecisionAsMSecs(minimallyClamped);
 }
 
 DOMHighResTimeStamp
 Performance::TimeOrigin()
 {
   if (!mPerformanceService) {
     mPerformanceService = PerformanceService::GetOrCreate();
   }
 
   MOZ_ASSERT(mPerformanceService);
-  return nsRFPService::ReduceTimePrecisionAsMSecs(
-    mPerformanceService->TimeOrigin(CreationTimeStamp()));
+  DOMHighResTimeStamp rawTimeOrigin = mPerformanceService->TimeOrigin(CreationTimeStamp());
+  if (mSystemPrincipal) {
+    return rawTimeOrigin;
+  }
+
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawTimeOrigin);
 }
 
 JSObject*
 Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return PerformanceBinding::Wrap(aCx, this, aGivenProto);
 }
 
@@ -201,27 +215,16 @@ Performance::ClearUserEntries(const Opti
 }
 
 void
 Performance::ClearResourceTimings()
 {
   mResourceEntries.Clear();
 }
 
-DOMHighResTimeStamp
-Performance::RoundTime(double aTime) const
-{
-  // Round down to the nearest 20us, because if the timer is too accurate people
-  // can do nasty timing attacks with it.
-  const double maxResolutionMs = 0.020;
-  return nsRFPService::ReduceTimePrecisionAsMSecs(
-    floor(aTime / maxResolutionMs) * maxResolutionMs);
-}
-
-
 void
 Performance::Mark(const nsAString& aName, ErrorResult& aRv)
 {
   // We add nothing when 'privacy.resistFingerprinting' is on.
   if (nsContentUtils::ShouldResistFingerprinting()) {
     return;
   }
 
old mode 100644
new mode 100755
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -36,16 +36,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Performance,
                                            DOMEventTargetHelper)
 
   static bool IsObserverEnabled(JSContext* aCx, JSObject* aGlobal);
 
   static already_AddRefed<Performance>
   CreateForMainThread(nsPIDOMWindowInner* aWindow,
+                      nsIPrincipal* aPrincipal,
                       nsDOMNavigationTiming* aDOMTiming,
                       nsITimedChannel* aChannel);
 
   static already_AddRefed<Performance>
   CreateForWorker(WorkerPrivate* aWorkerPrivate);
 
   JSObject* WrapObject(JSContext *cx,
                        JS::Handle<JSObject*> aGivenProto) override;
@@ -95,16 +96,21 @@ public:
                             JS::MutableHandle<JSObject*> aObj) = 0;
 
   virtual nsDOMNavigationTiming* GetDOMTiming() const = 0;
 
   virtual nsITimedChannel* GetChannel() const = 0;
 
   virtual TimeStamp CreationTimeStamp() const = 0;
 
+  uint64_t IsSystemPrincipal()
+  {
+    return mSystemPrincipal;
+  }
+
   void MemoryPressure();
 
   size_t SizeOfUserEntries(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfResourceEntries(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   void InsertResourceEntry(PerformanceEntry* aEntry);
 
 protected:
@@ -138,30 +144,30 @@ protected:
 
   void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const;
   void TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner,
                           uint64_t epoch);
 
   void RunNotificationObserversTask();
   void QueueEntry(PerformanceEntry* aEntry);
 
-  DOMHighResTimeStamp RoundTime(double aTime) const;
-
   nsTObserverArray<PerformanceObserver*> mObservers;
 
 protected:
   static const uint64_t kDefaultResourceTimingBufferSize = 150;
 
   // When kDefaultResourceTimingBufferSize is increased or removed, these should
   // be changed to use SegmentedVector
   AutoTArray<RefPtr<PerformanceEntry>, kDefaultResourceTimingBufferSize> mUserEntries;
   AutoTArray<RefPtr<PerformanceEntry>, kDefaultResourceTimingBufferSize> mResourceEntries;
 
   uint64_t mResourceTimingBufferSize;
   bool mPendingNotificationObserversTask;
 
   RefPtr<PerformanceService> mPerformanceService;
+
+  bool mSystemPrincipal;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Performance_h
old mode 100644
new mode 100755
old mode 100644
new mode 100755
--- a/dom/performance/PerformanceNavigationTiming.h
+++ b/dom/performance/PerformanceNavigationTiming.h
@@ -34,17 +34,21 @@ public:
     : PerformanceResourceTiming(Move(aPerformanceTiming), aPerformance,
                                 NS_LITERAL_STRING("document")) {
       SetEntryType(NS_LITERAL_STRING("navigation"));
       SetInitiatorType(NS_LITERAL_STRING("navigation"));
     }
 
   DOMHighResTimeStamp Duration() const override
   {
-    return nsRFPService::ReduceTimePrecisionAsMSecs(LoadEventEnd() - StartTime());
+    DOMHighResTimeStamp rawDuration = LoadEventEnd() - StartTime();
+    if (mPerformance->IsSystemPrincipal()) {
+      return rawDuration;
+    }
+    return nsRFPService::ReduceTimePrecisionAsMSecs(rawDuration);
   }
 
   DOMHighResTimeStamp StartTime() const override
   {
     return 0;
   }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
old mode 100644
new mode 100755
old mode 100644
new mode 100755
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -76,17 +76,19 @@ PerformanceTiming::PerformanceTiming(Per
                                      nsITimedChannel* aChannel,
                                      nsIHttpChannel* aHttpChannel,
                                      DOMHighResTimeStamp aZeroTime)
   : mPerformance(aPerformance)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
 
   mTimingData.reset(new PerformanceTimingData(aChannel, aHttpChannel,
-                                              aZeroTime));
+    aPerformance->IsSystemPrincipal()
+    ? aZeroTime
+    : nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime)));
 
   // Non-null aHttpChannel implies that this PerformanceTiming object is being
   // used for subresources, which is irrelevant to this probe.
   if (!aHttpChannel &&
       nsContentUtils::IsPerformanceTimingEnabled() &&
       IsTopLevelContentDocument()) {
     Telemetry::Accumulate(Telemetry::TIME_TO_RESPONSE_START_MS,
                           mTimingData->ResponseStartHighRes(aPerformance) -
@@ -107,18 +109,18 @@ PerformanceTimingData::PerformanceTiming
   , mRedirectCount(0)
   , mAllRedirectsSameOrigin(true)
   , mReportCrossOriginRedirect(true)
   , mSecureConnection(false)
   , mTimingAllowed(true)
   , mInitialized(false)
 {
   mInitialized = !!aChannel;
+  mZeroTime = aZeroTime;
 
-  mZeroTime = nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime);
   if (!nsContentUtils::IsPerformanceTimingEnabled() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     mZeroTime = 0;
   }
 
   nsCOMPtr<nsIURI> uri;
   if (aHttpChannel) {
     aHttpChannel->GetURI(getter_AddRefs(uri));
@@ -247,16 +249,19 @@ PerformanceTimingData::FetchStartHighRes
     if (!mAsyncOpen.IsNull()) {
       if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
         mFetchStart = TimeStampToDOMHighRes(aPerformance, mWorkerRequestStart);
       } else {
         mFetchStart = TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
       }
     }
   }
+  if (aPerformance->IsSystemPrincipal()) {
+    return mFetchStart;
+  }
   return nsRFPService::ReduceTimePrecisionAsMSecs(mFetchStart);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::FetchStart()
 {
   return static_cast<int64_t>(mTimingData->FetchStartHighRes(mPerformance));
 }
@@ -322,31 +327,37 @@ DOMHighResTimeStamp
 PerformanceTimingData::AsyncOpenHighRes(Performance* aPerformance)
 {
   MOZ_ASSERT(aPerformance);
 
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) {
     return mZeroTime;
   }
-  return nsRFPService::ReduceTimePrecisionAsMSecs(
-           TimeStampToDOMHighRes(aPerformance, mAsyncOpen));
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 DOMHighResTimeStamp
 PerformanceTimingData::WorkerStartHighRes(Performance* aPerformance)
 {
   MOZ_ASSERT(aPerformance);
 
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) {
     return mZeroTime;
   }
-  return nsRFPService::ReduceTimePrecisionAsMSecs(
-           TimeStampToDOMHighRes(aPerformance, mWorkerStart));
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mWorkerStart);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 /**
  * RedirectStartHighRes() is used by both the navigation timing and the
  * resource timing. Since, navigation timing and resource timing check and
  * interpret cross-domain redirects in a different manner,
  * RedirectStartHighRes() will make no checks for cross-domain redirect.
  * It's up to the consumers of this method (PerformanceTiming::RedirectStart()
@@ -442,20 +453,24 @@ PerformanceTimingData::DomainLookupEndHi
 {
   MOZ_ASSERT(aPerformance);
 
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
-  return mDomainLookupEnd.IsNull()
-          ? DomainLookupStartHighRes(aPerformance)
-          : nsRFPService::ReduceTimePrecisionAsMSecs(
-              TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd));
+  if (mDomainLookupEnd.IsNull()) {
+    return DomainLookupStartHighRes(aPerformance);
+  }
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::DomainLookupEnd()
 {
   return static_cast<int64_t>(mTimingData->DomainLookupEndHighRes(mPerformance));
 }
 
@@ -463,20 +478,24 @@ DOMHighResTimeStamp
 PerformanceTimingData::ConnectStartHighRes(Performance* aPerformance)
 {
   MOZ_ASSERT(aPerformance);
 
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
-  return mConnectStart.IsNull()
-           ? DomainLookupEndHighRes(aPerformance)
-           : nsRFPService::ReduceTimePrecisionAsMSecs(
-               TimeStampToDOMHighRes(aPerformance, mConnectStart));
+  if (mConnectStart.IsNull()) {
+    return DomainLookupEndHighRes(aPerformance);
+  }
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mConnectStart);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ConnectStart()
 {
   return static_cast<int64_t>(mTimingData->ConnectStartHighRes(mPerformance));
 }
 
@@ -484,23 +503,28 @@ DOMHighResTimeStamp
 PerformanceTimingData::SecureConnectionStartHighRes(Performance* aPerformance)
 {
   MOZ_ASSERT(aPerformance);
 
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
-  return !mSecureConnection
-    ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
+  if (!mSecureConnection) {
+    return 0; // We use 0 here, because mZeroTime is sometimes set to the navigation
         // start time.
-    : (mSecureConnectionStart.IsNull()
-        ? mZeroTime
-        : nsRFPService::ReduceTimePrecisionAsMSecs(
-            TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart)));
+  }
+  if (mSecureConnectionStart.IsNull()) {
+    return mZeroTime;
+  }
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::SecureConnectionStart()
 {
   return static_cast<int64_t>(mTimingData->SecureConnectionStartHighRes(mPerformance));
 }
 
@@ -509,20 +533,24 @@ PerformanceTimingData::ConnectEndHighRes
 {
   MOZ_ASSERT(aPerformance);
 
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
-  return mConnectEnd.IsNull()
-           ? ConnectStartHighRes(aPerformance)
-           : nsRFPService::ReduceTimePrecisionAsMSecs(
-               TimeStampToDOMHighRes(aPerformance, mConnectEnd));
+  if (mConnectEnd.IsNull()) {
+    return ConnectStartHighRes(aPerformance);
+  }
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mConnectEnd);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ConnectEnd()
 {
   return static_cast<int64_t>(mTimingData->ConnectEndHighRes(mPerformance));
 }
 
@@ -588,20 +616,24 @@ PerformanceTimingData::ResponseEndHighRe
   if (mResponseEnd.IsNull() ||
      (!mCacheReadEnd.IsNull() && mCacheReadEnd < mResponseEnd)) {
     mResponseEnd = mCacheReadEnd;
   }
   if (mResponseEnd.IsNull()) {
     mResponseEnd = mWorkerResponseEnd;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
-  return mResponseEnd.IsNull()
-           ? ResponseStartHighRes(aPerformance)
-           : nsRFPService::ReduceTimePrecisionAsMSecs(
-               TimeStampToDOMHighRes(aPerformance, mResponseEnd));
+  if (mResponseEnd.IsNull()) {
+    return ResponseStartHighRes(aPerformance);
+  }
+  DOMHighResTimeStamp rawValue = TimeStampToDOMHighRes(aPerformance, mResponseEnd);
+  if (aPerformance->IsSystemPrincipal()) {
+    return rawValue;
+  }
+  return nsRFPService::ReduceTimePrecisionAsMSecs(rawValue);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ResponseEnd()
 {
   return static_cast<int64_t>(mTimingData->ResponseEndHighRes(mPerformance));
 }
 
old mode 100644
new mode 100755
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -77,20 +77,26 @@ public:
    *          the FetchStart timing value.
    */
   inline DOMHighResTimeStamp
   TimeStampToReducedDOMHighResOrFetchStart(Performance* aPerformance,
                                            TimeStamp aStamp)
   {
     MOZ_ASSERT(aPerformance);
 
-    return (!aStamp.IsNull())
-        ? nsRFPService::ReduceTimePrecisionAsMSecs(
-            TimeStampToDOMHighRes(aPerformance, aStamp))
-        : FetchStartHighRes(aPerformance);
+    if(aStamp.IsNull()) {
+      return FetchStartHighRes(aPerformance);
+    }
+
+    DOMHighResTimeStamp rawTimestamp = TimeStampToDOMHighRes(aPerformance, aStamp);
+    if (aPerformance->IsSystemPrincipal()) {
+      return rawTimestamp;
+    }
+
+    return nsRFPService::ReduceTimePrecisionAsMSecs(rawTimestamp);
   }
 
   /**
    * The nsITimedChannel records an absolute timestamp for each event.
    * The nsDOMNavigationTiming will record the moment when the user landed on
    * the page. This is a window.performance unique timestamp, so it can be used
    * for all the events (navigation timing and resource timing events).
    *
@@ -263,36 +269,45 @@ public:
 
   // PerformanceNavigation WebIDL methods
   DOMTimeMilliSec NavigationStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetNavigationStart();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetNavigationStart());
   }
 
   DOMTimeMilliSec UnloadEventStart()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetUnloadEventStart();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetUnloadEventStart());
   }
 
   DOMTimeMilliSec UnloadEventEnd()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetUnloadEventEnd();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetUnloadEventEnd());
   }
 
   // Low resolution (used by navigation timing)
   DOMTimeMilliSec FetchStart();
   DOMTimeMilliSec RedirectStart();
   DOMTimeMilliSec RedirectEnd();
@@ -306,86 +321,110 @@ public:
   DOMTimeMilliSec ResponseEnd();
 
   DOMTimeMilliSec DomLoading()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetDomLoading();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetDomLoading());
   }
 
   DOMTimeMilliSec DomInteractive() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetDomInteractive();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetDomInteractive());
   }
 
   DOMTimeMilliSec DomContentLoadedEventStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetDomContentLoadedEventStart();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetDomContentLoadedEventStart());
   }
 
   DOMTimeMilliSec DomContentLoadedEventEnd() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetDomContentLoadedEventEnd();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetDomContentLoadedEventEnd());
   }
 
   DOMTimeMilliSec DomComplete() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetDomComplete();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetDomComplete());
   }
 
   DOMTimeMilliSec LoadEventStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetLoadEventStart();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetLoadEventStart());
   }
 
   DOMTimeMilliSec LoadEventEnd() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetLoadEventEnd();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetLoadEventEnd());
   }
 
   DOMTimeMilliSec TimeToNonBlankPaint() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetTimeToNonBlankPaint();
+    }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetTimeToNonBlankPaint());
   }
 
   PerformanceTimingData* Data() const
   {
     return mTimingData.get();
   }