Bug 1251238 - Part 3: Add timestamps to track when a service worker is installed/activated/redundant and when a service worker's registration is updated. r=bkelly
authorTom Tung <shes050117@gmail.com>
Thu, 06 Apr 2017 15:26:08 +0800
changeset 353091 9d157c0976e5d319c5482b076cf059dea8255088
parent 353090 c179e84b040f22612b228076d2d6d46229b1fa57
child 353092 35fafa7f1a8dde638c456b3c328c0d66682c7e74
push id31656
push userihsiao@mozilla.com
push dateFri, 14 Apr 2017 09:10:41 +0000
treeherdermozilla-central@cda24082bff8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1251238
milestone55.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 1251238 - Part 3: Add timestamps to track when a service worker is installed/activated/redundant and when a service worker's registration is updated. r=bkelly
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/workers/ServiceWorkerInfo.cpp
dom/workers/ServiceWorkerInfo.h
dom/workers/ServiceWorkerRegistrationInfo.cpp
dom/workers/ServiceWorkerRegistrationInfo.h
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -42,16 +42,20 @@ interface nsIServiceWorkerInfo : nsISupp
   readonly attribute DOMString cacheName;
 
   readonly attribute unsigned short state;
 
   readonly attribute nsIWorkerDebugger debugger;
 
   readonly attribute bool handlesFetchEvents;
 
+  readonly attribute PRTime installedTime;
+  readonly attribute PRTime activatedTime;
+  readonly attribute PRTime redundantTime;
+
   void attachDebugger();
 
   void detachDebugger();
 };
 
 [scriptable, uuid(87e63548-d440-4b8a-b158-65ad1de0211E)]
 interface nsIServiceWorkerRegistrationInfoListener : nsISupports
 {
@@ -61,16 +65,18 @@ interface nsIServiceWorkerRegistrationIn
 [scriptable, builtinclass, uuid(ddbc1fd4-2f2e-4fca-a395-6e010bbedfe3)]
 interface nsIServiceWorkerRegistrationInfo : nsISupports
 {
   readonly attribute nsIPrincipal principal;
 
   readonly attribute DOMString scope;
   readonly attribute DOMString scriptSpec;
 
+  readonly attribute PRTime lastUpdateTime;
+
   readonly attribute nsIServiceWorkerInfo installingWorker;
   readonly attribute nsIServiceWorkerInfo waitingWorker;
   readonly attribute nsIServiceWorkerInfo activeWorker;
 
   // Allows to get the related nsIServiceWorkerInfo for a given
   // nsIWorkerDebugger. Over time we shouldn't need this anymore,
   // and instead always control then nsIWorkerDebugger from
   // nsIServiceWorkerInfo and not the other way around.  Returns
--- a/dom/workers/ServiceWorkerInfo.cpp
+++ b/dom/workers/ServiceWorkerInfo.cpp
@@ -65,16 +65,43 @@ ServiceWorkerInfo::GetHandlesFetchEvents
 {
   MOZ_ASSERT(aValue);
   AssertIsOnMainThread();
   *aValue = HandlesFetch();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+ServiceWorkerInfo::GetInstalledTime(PRTime* _retval)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(_retval);
+  *_retval = mInstalledTime;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ServiceWorkerInfo::GetActivatedTime(PRTime* _retval)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(_retval);
+  *_retval = mActivatedTime;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ServiceWorkerInfo::GetRedundantTime(PRTime* _retval)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(_retval);
+  *_retval = mRedundantTime;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 ServiceWorkerInfo::AttachDebugger()
 {
   return mServiceWorkerPrivate->AttachDebugger();
 }
 
 NS_IMETHODIMP
 ServiceWorkerInfo::DetachDebugger()
 {
@@ -184,16 +211,21 @@ ServiceWorkerInfo::ServiceWorkerInfo(nsI
                                      nsLoadFlags aLoadFlags)
   : mPrincipal(aPrincipal)
   , mScope(aScope)
   , mScriptSpec(aScriptSpec)
   , mCacheName(aCacheName)
   , mLoadFlags(aLoadFlags)
   , mState(ServiceWorkerState::EndGuard_)
   , mServiceWorkerID(GetNextID())
+  , mCreationTime(PR_Now())
+  , mCreationTimeStamp(TimeStamp::Now())
+  , mInstalledTime(0)
+  , mActivatedTime(0)
+  , mRedundantTime(0)
   , mServiceWorkerPrivate(new ServiceWorkerPrivate(this))
   , mSkipWaitingFlag(false)
   , mHandlesFetch(Unknown)
 {
   MOZ_ASSERT(mPrincipal);
   // cache origin attributes so we can use them off main thread
   mOriginAttributes = mPrincipal->OriginAttributesRef();
   MOZ_ASSERT(!mScope.IsEmpty());
@@ -233,9 +265,42 @@ ServiceWorkerInfo::GetOrCreateInstance(n
 
   if (!ref) {
     ref = new ServiceWorker(aWindow, this);
   }
 
   return ref.forget();
 }
 
+void
+ServiceWorkerInfo::UpdateInstalledTime()
+{
+  MOZ_ASSERT(mState == ServiceWorkerState::Installed);
+  MOZ_ASSERT(mInstalledTime == 0);
+
+  mInstalledTime =
+    mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
+                                         mCreationTimeStamp).ToMicroseconds());
+}
+
+void
+ServiceWorkerInfo::UpdateActivatedTime()
+{
+  MOZ_ASSERT(mState == ServiceWorkerState::Activated);
+  MOZ_ASSERT(mActivatedTime == 0);
+
+  mActivatedTime =
+    mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
+                                         mCreationTimeStamp).ToMicroseconds());
+}
+
+void
+ServiceWorkerInfo::UpdateRedundantTime()
+{
+  MOZ_ASSERT(mState == ServiceWorkerState::Redundant);
+  MOZ_ASSERT(mRedundantTime == 0);
+
+  mRedundantTime =
+    mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
+                                         mCreationTimeStamp).ToMicroseconds());
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/ServiceWorkerInfo.h
+++ b/dom/workers/ServiceWorkerInfo.h
@@ -34,16 +34,26 @@ private:
   const nsLoadFlags mLoadFlags;
   ServiceWorkerState mState;
   OriginAttributes mOriginAttributes;
 
   // This id is shared with WorkerPrivate to match requests issued by service
   // workers to their corresponding serviceWorkerInfo.
   uint64_t mServiceWorkerID;
 
+  // Timestamp to track SW's state
+  PRTime mCreationTime;
+  TimeStamp mCreationTimeStamp;
+
+  // The time of states are 0, if SW has not reached that state yet. Besides, we
+  // update each of them after UpdateState() is called in SWRegistrationInfo.
+  PRTime mInstalledTime;
+  PRTime mActivatedTime;
+  PRTime mRedundantTime;
+
   // We hold rawptrs since the ServiceWorker constructor and destructor ensure
   // addition and removal.
   // There is a high chance of there being at least one ServiceWorker
   // associated with this all the time.
   AutoTArray<ServiceWorker*, 1> mInstances;
 
   RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
   bool mSkipWaitingFlag;
@@ -168,15 +178,24 @@ public:
   void
   AppendWorker(ServiceWorker* aWorker);
 
   void
   RemoveWorker(ServiceWorker* aWorker);
 
   already_AddRefed<ServiceWorker>
   GetOrCreateInstance(nsPIDOMWindowInner* aWindow);
+
+  void
+  UpdateInstalledTime();
+
+  void
+  UpdateActivatedTime();
+
+  void
+  UpdateRedundantTime();
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkerinfo_h
--- a/dom/workers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/workers/ServiceWorkerRegistrationInfo.cpp
@@ -49,41 +49,47 @@ ServiceWorkerRegistrationInfo::Clear()
   }
 
   UpdateRegistrationStateProperties(WhichServiceWorker::INSTALLING_WORKER |
                                     WhichServiceWorker::WAITING_WORKER |
                                     WhichServiceWorker::ACTIVE_WORKER, Invalidate);
 
   if (mInstallingWorker) {
     mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
+    mInstallingWorker->UpdateRedundantTime();
     mInstallingWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mInstallingWorker = nullptr;
     // FIXME(nsm): Abort any inflight requests from installing worker.
   }
 
   if (mWaitingWorker) {
     mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
+    mWaitingWorker->UpdateRedundantTime();
     mWaitingWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mWaitingWorker = nullptr;
   }
 
   if (mActiveWorker) {
     mActiveWorker->UpdateState(ServiceWorkerState::Redundant);
+    mActiveWorker->UpdateRedundantTime();
     mActiveWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mActiveWorker = nullptr;
   }
 
   NotifyChromeRegistrationListeners();
 }
 
 ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                                              nsIPrincipal* aPrincipal,
                                                              nsLoadFlags aLoadFlags)
   : mControlledDocumentsCounter(0)
   , mUpdateState(NoUpdate)
+  , mCreationTime(PR_Now())
+  , mCreationTimeStamp(TimeStamp::Now())
+  , mLastUpdateTime(0)
   , mLastUpdateCheckTime(0)
   , mLoadFlags(aLoadFlags)
   , mScope(aScope)
   , mPrincipal(aPrincipal)
   , mPendingUninstall(false)
 {}
 
 ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
@@ -118,16 +124,25 @@ ServiceWorkerRegistrationInfo::GetScript
   RefPtr<ServiceWorkerInfo> newest = Newest();
   if (newest) {
     CopyUTF8toUTF16(newest->ScriptSpec(), aScriptSpec);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+ServiceWorkerRegistrationInfo::GetLastUpdateTime(PRTime* _retval)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(_retval);
+  *_retval = mLastUpdateTime;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetInstallingWorker(nsIServiceWorkerInfo **aResult)
 {
   AssertIsOnMainThread();
   nsCOMPtr<nsIServiceWorkerInfo> info = do_QueryInterface(mInstallingWorker);
   info.forget(aResult);
   return NS_OK;
 }
 
@@ -280,31 +295,37 @@ ServiceWorkerRegistrationInfo::FinishAct
 {
   if (mPendingUninstall || !mActiveWorker ||
       mActiveWorker->State() != ServiceWorkerState::Activating) {
     return;
   }
 
   // Activation never fails, so aSuccess is ignored.
   mActiveWorker->UpdateState(ServiceWorkerState::Activated);
+  mActiveWorker->UpdateActivatedTime();
   NotifyChromeRegistrationListeners();
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (!swm) {
     // browser shutdown started during async activation completion step
     return;
   }
   swm->StoreRegistration(mPrincipal, this);
 }
 
 void
 ServiceWorkerRegistrationInfo::RefreshLastUpdateCheckTime()
 {
   AssertIsOnMainThread();
   mLastUpdateCheckTime = PR_IntervalNow() / PR_MSEC_PER_SEC;
+
+  mLastUpdateTime =
+    mCreationTime + static_cast<PRTime>((TimeStamp::Now() -
+                                         mCreationTimeStamp).ToMicroseconds());
+  NotifyChromeRegistrationListeners();
 }
 
 bool
 ServiceWorkerRegistrationInfo::IsLastUpdateCheckTimeOverOneDay() const
 {
   AssertIsOnMainThread();
 
   // For testing.
@@ -477,31 +498,34 @@ ServiceWorkerRegistrationInfo::ClearEval
 {
   AssertIsOnMainThread();
 
   if (!mEvaluatingWorker) {
     return;
   }
 
   mEvaluatingWorker->UpdateState(ServiceWorkerState::Redundant);
+  // We don't update the redundant time for the sw here, since we've not expose
+  // evalutingWorker yet.
   mEvaluatingWorker = nullptr;
 }
 
 void
 ServiceWorkerRegistrationInfo::ClearInstalling()
 {
   AssertIsOnMainThread();
 
   if (!mInstallingWorker) {
     return;
   }
 
   UpdateRegistrationStateProperties(WhichServiceWorker::INSTALLING_WORKER,
                                     Invalidate);
   mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
+  mInstallingWorker->UpdateRedundantTime();
   mInstallingWorker = nullptr;
 
   NotifyChromeRegistrationListeners();
 }
 
 void
 ServiceWorkerRegistrationInfo::TransitionEvaluatingToInstalling()
 {
@@ -518,22 +542,24 @@ void
 ServiceWorkerRegistrationInfo::TransitionInstallingToWaiting()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mInstallingWorker);
 
   if (mWaitingWorker) {
     MOZ_ASSERT(mInstallingWorker->CacheName() != mWaitingWorker->CacheName());
     mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
+    mWaitingWorker->UpdateRedundantTime();
   }
 
   mWaitingWorker = mInstallingWorker.forget();
   UpdateRegistrationStateProperties(WhichServiceWorker::INSTALLING_WORKER,
                                     TransitionToNextState);
   mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
+  mWaitingWorker->UpdateInstalledTime();
   NotifyChromeRegistrationListeners();
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (!swm) {
     // browser shutdown began
     return;
   }
   swm->StoreRegistration(mPrincipal, this);
@@ -551,36 +577,40 @@ ServiceWorkerRegistrationInfo::SetActive
   //       overrides.
   MOZ_ASSERT(mInstallingWorker != aServiceWorker);
   MOZ_ASSERT(mWaitingWorker != aServiceWorker);
   MOZ_ASSERT(mActiveWorker != aServiceWorker);
 
   if (mActiveWorker) {
     MOZ_ASSERT(aServiceWorker->CacheName() != mActiveWorker->CacheName());
     mActiveWorker->UpdateState(ServiceWorkerState::Redundant);
+    mActiveWorker->UpdateRedundantTime();
   }
 
   // The active worker is being overriden due to initial load or
   // another process activating a worker.  Move straight to the
   // Activated state.
   mActiveWorker = aServiceWorker;
   mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
+  // We don't need to update activated time when we load registration from
+  // registrar.
   UpdateRegistrationStateProperties(WhichServiceWorker::ACTIVE_WORKER, Invalidate);
   NotifyChromeRegistrationListeners();
 }
 
 void
 ServiceWorkerRegistrationInfo::TransitionWaitingToActive()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mWaitingWorker);
 
   if (mActiveWorker) {
     MOZ_ASSERT(mWaitingWorker->CacheName() != mActiveWorker->CacheName());
     mActiveWorker->UpdateState(ServiceWorkerState::Redundant);
+    mActiveWorker->UpdateRedundantTime();
   }
 
   // We are transitioning from waiting to active normally, so go to
   // the activating state.
   mActiveWorker = mWaitingWorker.forget();
   UpdateRegistrationStateProperties(WhichServiceWorker::WAITING_WORKER,
                                     TransitionToNextState);
   mActiveWorker->UpdateState(ServiceWorkerState::Activating);
--- a/dom/workers/ServiceWorkerRegistrationInfo.h
+++ b/dom/workers/ServiceWorkerRegistrationInfo.h
@@ -20,16 +20,22 @@ class ServiceWorkerRegistrationInfo fina
 
   enum
   {
     NoUpdate,
     NeedTimeCheckAndUpdate,
     NeedUpdate
   } mUpdateState;
 
+  // Timestamp to track SWR's last update time
+  PRTime mCreationTime;
+  TimeStamp mCreationTimeStamp;
+  // The time of update is 0, if SWR've never been updated yet.
+  PRTime mLastUpdateTime;
+
   uint64_t mLastUpdateCheckTime;
 
   nsLoadFlags mLoadFlags;
 
   RefPtr<ServiceWorkerInfo> mEvaluatingWorker;
   RefPtr<ServiceWorkerInfo> mActiveWorker;
   RefPtr<ServiceWorkerInfo> mWaitingWorker;
   RefPtr<ServiceWorkerInfo> mInstallingWorker;