1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_serviceworkerregistrationinfo_h 8 #define mozilla_dom_serviceworkerregistrationinfo_h 9 10 #include <functional> 11 12 #include "mozilla/dom/ServiceWorkerInfo.h" 13 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h" 14 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h" 15 #include "nsProxyRelease.h" 16 #include "nsTObserverArray.h" 17 18 namespace mozilla { 19 namespace dom { 20 21 class ServiceWorkerRegistrationListener; 22 23 class ServiceWorkerRegistrationInfo final 24 : public nsIServiceWorkerRegistrationInfo { 25 nsCOMPtr<nsIPrincipal> mPrincipal; 26 ServiceWorkerRegistrationDescriptor mDescriptor; 27 nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners; 28 nsTObserverArray<ServiceWorkerRegistrationListener*> mInstanceList; 29 30 struct VersionEntry { 31 const ServiceWorkerRegistrationDescriptor mDescriptor; 32 TimeStamp mTimeStamp; 33 VersionEntryVersionEntry34 explicit VersionEntry( 35 const ServiceWorkerRegistrationDescriptor& aDescriptor) 36 : mDescriptor(aDescriptor), mTimeStamp(TimeStamp::Now()) {} 37 }; 38 nsTArray<UniquePtr<VersionEntry>> mVersionList; 39 40 const nsID mAgentClusterId = nsContentUtils::GenerateUUID(); 41 42 uint32_t mControlledClientsCounter; 43 uint32_t mDelayMultiplier; 44 45 enum { NoUpdate, NeedTimeCheckAndUpdate, NeedUpdate } mUpdateState; 46 47 // Timestamp to track SWR's last update time 48 PRTime mCreationTime; 49 TimeStamp mCreationTimeStamp; 50 // The time of update is 0, if SWR've never been updated yet. 51 PRTime mLastUpdateTime; 52 53 RefPtr<ServiceWorkerInfo> mEvaluatingWorker; 54 RefPtr<ServiceWorkerInfo> mActiveWorker; 55 RefPtr<ServiceWorkerInfo> mWaitingWorker; 56 RefPtr<ServiceWorkerInfo> mInstallingWorker; 57 58 virtual ~ServiceWorkerRegistrationInfo(); 59 60 // When unregister() is called on a registration, it is removed from the 61 // "scope to registration map" but not immediately "cleared" (i.e. its workers 62 // terminated, updated to the redundant state, etc.) because it may still be 63 // controlling clients. It is marked as unregistered and when all controlled 64 // clients go away, cleared. This way we can tell if a registration 65 // is unregistered by querying the object itself rather than incurring a table 66 // lookup (in the case when the registrations are passed around as pointers). 67 bool mUnregistered; 68 69 bool mCorrupt; 70 71 public: 72 NS_DECL_ISUPPORTS 73 NS_DECL_NSISERVICEWORKERREGISTRATIONINFO 74 75 typedef std::function<void()> TryToActivateCallback; 76 77 ServiceWorkerRegistrationInfo(const nsACString& aScope, 78 nsIPrincipal* aPrincipal, 79 ServiceWorkerUpdateViaCache aUpdateViaCache); 80 81 void AddInstance(ServiceWorkerRegistrationListener* aInstance, 82 const ServiceWorkerRegistrationDescriptor& aDescriptor); 83 84 void RemoveInstance(ServiceWorkerRegistrationListener* aInstance); 85 86 const nsCString& Scope() const; 87 88 nsIPrincipal* Principal() const; 89 90 bool IsUnregistered() const; 91 92 void SetUnregistered(); 93 Newest()94 already_AddRefed<ServiceWorkerInfo> Newest() const { 95 RefPtr<ServiceWorkerInfo> newest; 96 if (mInstallingWorker) { 97 newest = mInstallingWorker; 98 } else if (mWaitingWorker) { 99 newest = mWaitingWorker; 100 } else { 101 newest = mActiveWorker; 102 } 103 104 return newest.forget(); 105 } 106 NewestIncludingEvaluating()107 already_AddRefed<ServiceWorkerInfo> NewestIncludingEvaluating() const { 108 if (mEvaluatingWorker) { 109 RefPtr<ServiceWorkerInfo> newest = mEvaluatingWorker; 110 return newest.forget(); 111 } 112 return Newest(); 113 } 114 115 already_AddRefed<ServiceWorkerInfo> GetServiceWorkerInfoById(uint64_t aId); 116 StartControllingClient()117 void StartControllingClient() { 118 ++mControlledClientsCounter; 119 mDelayMultiplier = 0; 120 } 121 StopControllingClient()122 void StopControllingClient() { 123 MOZ_ASSERT(mControlledClientsCounter); 124 --mControlledClientsCounter; 125 } 126 IsControllingClients()127 bool IsControllingClients() const { 128 return mActiveWorker && mControlledClientsCounter; 129 } 130 131 // As a side effect, this nullifies 132 // `m{Evaluating,Installing,Waiting,Active}Worker`s. 133 void ShutdownWorkers(); 134 135 void Clear(); 136 137 void ClearAsCorrupt(); 138 139 bool IsCorrupt() const; 140 141 void TryToActivateAsync(TryToActivateCallback&& aCallback = nullptr); 142 143 void TryToActivate(TryToActivateCallback&& aCallback); 144 145 void Activate(); 146 147 void FinishActivate(bool aSuccess); 148 149 void RefreshLastUpdateCheckTime(); 150 151 bool IsLastUpdateCheckTimeOverOneDay() const; 152 153 void MaybeScheduleTimeCheckAndUpdate(); 154 155 void MaybeScheduleUpdate(); 156 157 bool CheckAndClearIfUpdateNeeded(); 158 159 ServiceWorkerInfo* GetEvaluating() const; 160 161 ServiceWorkerInfo* GetInstalling() const; 162 163 ServiceWorkerInfo* GetWaiting() const; 164 165 ServiceWorkerInfo* GetActive() const; 166 167 ServiceWorkerInfo* GetByDescriptor( 168 const ServiceWorkerDescriptor& aDescriptor) const; 169 170 // Set the given worker as the evaluating service worker. The worker 171 // state is not changed. 172 void SetEvaluating(ServiceWorkerInfo* aServiceWorker); 173 174 // Remove an existing evaluating worker, if present. The worker will 175 // be transitioned to the Redundant state. 176 void ClearEvaluating(); 177 178 // Remove an existing installing worker, if present. The worker will 179 // be transitioned to the Redundant state. 180 void ClearInstalling(); 181 182 // Transition the current evaluating worker to be the installing worker. The 183 // worker's state is update to Installing. 184 void TransitionEvaluatingToInstalling(); 185 186 // Transition the current installing worker to be the waiting worker. The 187 // worker's state is updated to Installed. 188 void TransitionInstallingToWaiting(); 189 190 // Override the current active worker. This is used during browser 191 // initialization to load persisted workers. Its also used to propagate 192 // active workers across child processes in e10s. This second use will 193 // go away once the ServiceWorkerManager moves to the parent process. 194 // The worker is transitioned to the Activated state. 195 void SetActive(ServiceWorkerInfo* aServiceWorker); 196 197 // Transition the current waiting worker to be the new active worker. The 198 // worker is updated to the Activating state. 199 void TransitionWaitingToActive(); 200 201 // Determine if the registration is actively performing work. 202 bool IsIdle() const; 203 204 ServiceWorkerUpdateViaCache GetUpdateViaCache() const; 205 206 void SetUpdateViaCache(ServiceWorkerUpdateViaCache aUpdateViaCache); 207 208 int64_t GetLastUpdateTime() const; 209 210 void SetLastUpdateTime(const int64_t aTime); 211 212 const ServiceWorkerRegistrationDescriptor& Descriptor() const; 213 214 uint64_t Id() const; 215 216 uint64_t Version() const; 217 218 uint32_t GetUpdateDelay(const bool aWithMultiplier = true); 219 220 void FireUpdateFound(); 221 222 void NotifyCleared(); 223 224 void ClearWhenIdle(); 225 226 const nsID& AgentClusterId() const; 227 228 private: 229 // Roughly equivalent to [[Update Registration State algorithm]]. Make sure 230 // this is called *before* updating SW instances' state, otherwise they 231 // may get CC-ed. 232 void UpdateRegistrationState(); 233 234 void UpdateRegistrationState(ServiceWorkerUpdateViaCache aUpdateViaCache); 235 236 // Used by devtools to track changes to the properties of 237 // *nsIServiceWorkerRegistrationInfo*. Note, this doesn't necessarily need to 238 // be in sync with the DOM registration objects, but it does need to be called 239 // in the same task that changed |mInstallingWorker|, |mWaitingWorker| or 240 // |mActiveWorker|. 241 void NotifyChromeRegistrationListeners(); 242 243 static uint64_t GetNextId(); 244 245 static uint64_t GetNextVersion(); 246 247 // `aFunc`'s argument will be a reference to 248 // `m{Evaluating,Installing,Waiting,Active}Worker` (not to copy of them). 249 // Additionally, a null check will be performed for each worker before each 250 // call to `aFunc`, so `aFunc` will always get a reference to a non-null 251 // pointer. 252 void ForEachWorker(void (*aFunc)(RefPtr<ServiceWorkerInfo>&)); 253 }; 254 255 } // namespace dom 256 } // namespace mozilla 257 258 #endif // mozilla_dom_serviceworkerregistrationinfo_h 259