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