Bug 1610775 [wpt PR 21336] - Update urllib3 to 1.25.8, a=testonly
[gecko.git] / dom / storage / StorageActivityService.cpp
blobe3411da9a3f548fab23c81a98cd7354c24fe619f
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/. */
7 #include "StorageActivityService.h"
9 #include "mozilla/ipc/BackgroundUtils.h"
10 #include "mozilla/StaticPtr.h"
11 #include "nsIMutableArray.h"
12 #include "nsSupportsPrimitives.h"
13 #include "nsXPCOM.h"
15 // This const is used to know when origin activities should be purged because
16 // too old. This value should be in sync with what the UI needs.
17 #define TIME_MAX_SECS 86400 /* 24 hours */
19 namespace mozilla {
20 namespace dom {
22 static StaticRefPtr<StorageActivityService> gStorageActivityService;
23 static bool gStorageActivityShutdown = false;
25 /* static */
26 void StorageActivityService::SendActivity(nsIPrincipal* aPrincipal) {
27 MOZ_ASSERT(NS_IsMainThread());
29 if (!aPrincipal || BasePrincipal::Cast(aPrincipal)->Kind() !=
30 BasePrincipal::eContentPrincipal) {
31 // Only content principals.
32 return;
35 RefPtr<StorageActivityService> service = GetOrCreate();
36 if (NS_WARN_IF(!service)) {
37 return;
40 service->SendActivityInternal(aPrincipal);
43 /* static */
44 void StorageActivityService::SendActivity(
45 const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
46 if (aPrincipalInfo.type() !=
47 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) {
48 // only content principal.
49 return;
52 RefPtr<Runnable> r = NS_NewRunnableFunction(
53 "StorageActivityService::SendActivity", [aPrincipalInfo]() {
54 MOZ_ASSERT(NS_IsMainThread());
56 nsCOMPtr<nsIPrincipal> principal =
57 mozilla::ipc::PrincipalInfoToPrincipal(aPrincipalInfo);
59 StorageActivityService::SendActivity(principal);
60 });
62 SystemGroup::Dispatch(TaskCategory::Other, r.forget());
65 /* static */
66 void StorageActivityService::SendActivity(const nsACString& aOrigin) {
67 MOZ_ASSERT(XRE_IsParentProcess());
69 nsCString origin;
70 origin.Assign(aOrigin);
72 RefPtr<Runnable> r = NS_NewRunnableFunction(
73 "StorageActivityService::SendActivity", [origin]() {
74 MOZ_ASSERT(NS_IsMainThread());
76 RefPtr<StorageActivityService> service = GetOrCreate();
77 if (NS_WARN_IF(!service)) {
78 return;
81 service->SendActivityInternal(origin);
82 });
84 if (NS_IsMainThread()) {
85 Unused << r->Run();
86 } else {
87 SystemGroup::Dispatch(TaskCategory::Other, r.forget());
91 /* static */
92 already_AddRefed<StorageActivityService> StorageActivityService::GetOrCreate() {
93 MOZ_ASSERT(NS_IsMainThread());
95 if (!gStorageActivityService && !gStorageActivityShutdown) {
96 RefPtr<StorageActivityService> service = new StorageActivityService();
98 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
99 if (NS_WARN_IF(!obs)) {
100 return nullptr;
103 nsresult rv =
104 obs->AddObserver(service, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
105 if (NS_WARN_IF(NS_FAILED(rv))) {
106 return nullptr;
109 gStorageActivityService = service;
112 RefPtr<StorageActivityService> service = gStorageActivityService;
113 return service.forget();
116 StorageActivityService::StorageActivityService() {
117 MOZ_ASSERT(NS_IsMainThread());
120 StorageActivityService::~StorageActivityService() {
121 MOZ_ASSERT(NS_IsMainThread());
122 MOZ_ASSERT(!mTimer);
125 void StorageActivityService::SendActivityInternal(nsIPrincipal* aPrincipal) {
126 MOZ_ASSERT(NS_IsMainThread());
127 MOZ_ASSERT(aPrincipal);
128 MOZ_ASSERT(BasePrincipal::Cast(aPrincipal)->Kind() ==
129 BasePrincipal::eContentPrincipal);
131 if (!XRE_IsParentProcess()) {
132 SendActivityToParent(aPrincipal);
133 return;
136 nsAutoCString origin;
137 nsresult rv = aPrincipal->GetOrigin(origin);
138 if (NS_WARN_IF(NS_FAILED(rv))) {
139 return;
142 SendActivityInternal(origin);
145 void StorageActivityService::SendActivityInternal(const nsACString& aOrigin) {
146 MOZ_ASSERT(XRE_IsParentProcess());
148 mActivities.Put(aOrigin, PR_Now());
149 MaybeStartTimer();
152 void StorageActivityService::SendActivityToParent(nsIPrincipal* aPrincipal) {
153 MOZ_ASSERT(NS_IsMainThread());
154 MOZ_ASSERT(!XRE_IsParentProcess());
156 PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
157 if (NS_WARN_IF(!actor)) {
158 return;
161 mozilla::ipc::PrincipalInfo principalInfo;
162 nsresult rv =
163 mozilla::ipc::PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
164 if (NS_WARN_IF(NS_FAILED(rv))) {
165 return;
168 actor->SendStorageActivity(principalInfo);
171 NS_IMETHODIMP
172 StorageActivityService::Observe(nsISupports* aSubject, const char* aTopic,
173 const char16_t* aData) {
174 MOZ_ASSERT(NS_IsMainThread());
175 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
177 MaybeStopTimer();
179 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
180 if (obs) {
181 obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
184 gStorageActivityShutdown = true;
185 gStorageActivityService = nullptr;
186 return NS_OK;
189 void StorageActivityService::MaybeStartTimer() {
190 MOZ_ASSERT(NS_IsMainThread());
192 if (!mTimer) {
193 mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
194 mTimer->InitWithCallback(this, 1000 * 5 * 60 /* any 5 minutes */,
195 nsITimer::TYPE_REPEATING_SLACK);
199 void StorageActivityService::MaybeStopTimer() {
200 MOZ_ASSERT(NS_IsMainThread());
202 if (mTimer) {
203 mTimer->Cancel();
204 mTimer = nullptr;
208 NS_IMETHODIMP
209 StorageActivityService::Notify(nsITimer* aTimer) {
210 MOZ_ASSERT(NS_IsMainThread());
211 MOZ_ASSERT(mTimer == aTimer);
213 uint64_t now = PR_Now();
215 for (auto iter = mActivities.Iter(); !iter.Done(); iter.Next()) {
216 if ((now - iter.UserData()) / PR_USEC_PER_SEC > TIME_MAX_SECS) {
217 iter.Remove();
221 // If no activities, let's stop the timer.
222 if (mActivities.Count() == 0) {
223 MaybeStopTimer();
226 return NS_OK;
229 NS_IMETHODIMP
230 StorageActivityService::GetActiveOrigins(PRTime aFrom, PRTime aTo,
231 nsIArray** aRetval) {
232 uint64_t now = PR_Now();
233 if (((now - aFrom) / PR_USEC_PER_SEC) > TIME_MAX_SECS || aFrom >= aTo) {
234 return NS_ERROR_INVALID_ARG;
237 nsresult rv = NS_OK;
238 nsCOMPtr<nsIMutableArray> devices =
239 do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
240 if (NS_WARN_IF(NS_FAILED(rv))) {
241 return rv;
244 for (auto iter = mActivities.Iter(); !iter.Done(); iter.Next()) {
245 if (iter.UserData() >= aFrom && iter.UserData() <= aTo) {
246 RefPtr<BasePrincipal> principal =
247 BasePrincipal::CreateContentPrincipal(iter.Key());
248 MOZ_ASSERT(principal);
250 rv = devices->AppendElement(principal);
251 if (NS_WARN_IF(NS_FAILED(rv))) {
252 return rv;
257 devices.forget(aRetval);
258 return NS_OK;
261 NS_IMETHODIMP
262 StorageActivityService::MoveOriginInTime(nsIPrincipal* aPrincipal,
263 PRTime aWhen) {
264 if (!XRE_IsParentProcess()) {
265 return NS_ERROR_FAILURE;
268 nsAutoCString origin;
269 nsresult rv = aPrincipal->GetOrigin(origin);
270 if (NS_WARN_IF(NS_FAILED(rv))) {
271 return rv;
274 mActivities.Put(origin, aWhen / PR_USEC_PER_SEC);
275 return NS_OK;
278 NS_IMETHODIMP
279 StorageActivityService::TestOnlyReset() {
280 mActivities.Clear();
281 return NS_OK;
284 NS_INTERFACE_MAP_BEGIN(StorageActivityService)
285 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStorageActivityService)
286 NS_INTERFACE_MAP_ENTRY(nsIStorageActivityService)
287 NS_INTERFACE_MAP_ENTRY(nsIObserver)
288 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
289 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
290 NS_INTERFACE_MAP_END
292 NS_IMPL_ADDREF(StorageActivityService)
293 NS_IMPL_RELEASE(StorageActivityService)
295 } // namespace dom
296 } // namespace mozilla