Bug 1252998 - StorageActivityService - part 1 - Introduce StorageActivityService to monitor origin activities, r=asuth

This commit is contained in:
Andrea Marchesini 2018-01-08 08:31:34 +01:00
Родитель b4db81eb44
Коммит 1ac04372e5
10 изменённых файлов: 333 добавлений и 0 удалений

Просмотреть файл

@ -10,6 +10,7 @@ with Files("**"):
XPIDL_SOURCES += [
'nsIDOMStorage.idl',
'nsIDOMStorageManager.idl',
'nsIStorageActivityService.idl',
]
XPIDL_MODULE = 'dom_storage'

Просмотреть файл

@ -0,0 +1,25 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
/**
* nsIStorageActivityService is a service that can be used to know which
* origins have been active in a time range. This information can be used to
* implement "Clear Recent History" or similar features.
*
* If you are implementing a new Storage component, you should use
* QuotaManager. But if you don't do it, remember to call
* StorageActivityService methods in order to inform this service about
* 'writing' operations executed by origins.
*/
[scriptable, builtinclass, uuid(fd1310ba-d1be-4327-988e-92b39fcff6f4)]
interface nsIStorageActivityService : nsISupports
{
};
%{ C++
#define STORAGE_ACTIVITY_SERVICE_CONTRACTID "@mozilla.org/storage/activity-service;1"
%}

Просмотреть файл

@ -0,0 +1,209 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "StorageActivityService.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/StaticPtr.h"
#include "nsXPCOM.h"
// This const is used to know when origin activities should be purged because
// too old. This value should be in sync with what the UI needs.
#define TIME_MAX_SECS 86400 /* 24 hours */
namespace mozilla {
namespace dom {
static StaticRefPtr<StorageActivityService> gStorageActivityService;
static bool gStorageActivityShutdown = false;
/* static */ void
StorageActivityService::SendActivity(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<StorageActivityService> service = GetOrCreate();
if (NS_WARN_IF(!service)) {
return;
}
service->SendActivityInternal(aPrincipal);
}
/* static */ void
StorageActivityService::SendActivity(const mozilla::ipc::PrincipalInfo& aPrincipalInfo)
{
RefPtr<Runnable> r = NS_NewRunnableFunction(
"StorageActivityService::SendActivity",
[aPrincipalInfo] () {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPrincipal> principal =
mozilla::ipc::PrincipalInfoToPrincipal(aPrincipalInfo);
StorageActivityService::SendActivity(principal);
});
SystemGroup::Dispatch(TaskCategory::Other, r.forget());
}
/* static */ already_AddRefed<StorageActivityService>
StorageActivityService::GetOrCreate()
{
MOZ_ASSERT(NS_IsMainThread());
if (!gStorageActivityService && !gStorageActivityShutdown) {
RefPtr<StorageActivityService> service = new StorageActivityService();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return nullptr;
}
nsresult rv = obs->AddObserver(service, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
gStorageActivityService = service;
}
RefPtr<StorageActivityService> service = gStorageActivityService;
return service.forget();
}
StorageActivityService::StorageActivityService()
{
MOZ_ASSERT(NS_IsMainThread());
}
StorageActivityService::~StorageActivityService()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mTimer);
}
void
StorageActivityService::SendActivityInternal(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
if (!XRE_IsParentProcess()) {
SendActivityToParent(aPrincipal);
return;
}
nsAutoCString origin;
nsresult rv = aPrincipal->GetOrigin(origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
mActivities.Put(origin, TimeStamp::NowLoRes());
MaybeStartTimer();
}
void
StorageActivityService::SendActivityToParent(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!XRE_IsParentProcess());
PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!actor)) {
return;
}
mozilla::ipc::PrincipalInfo principalInfo;
nsresult rv =
mozilla::ipc::PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
actor->SendStorageActivity(principalInfo);
}
NS_IMETHODIMP
StorageActivityService::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
MaybeStopTimer();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
}
gStorageActivityShutdown = true;
gStorageActivityService = nullptr;
return NS_OK;
}
void
StorageActivityService::MaybeStartTimer()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mTimer) {
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
mTimer->InitWithCallback(this,
1000 * 5 * 60 /* any 5 minutes */,
nsITimer::TYPE_REPEATING_SLACK);
}
}
void
StorageActivityService::MaybeStopTimer()
{
MOZ_ASSERT(NS_IsMainThread());
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
}
NS_IMETHODIMP
StorageActivityService::Notify(nsITimer* aTimer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mTimer == aTimer);
TimeStamp now = TimeStamp::NowLoRes();
for (auto iter = mActivities.Iter(); !iter.Done(); iter.Next()) {
if ((now - iter.UserData()).ToSeconds() > TIME_MAX_SECS) {
iter.Remove();
}
}
// If no activities, let's stop the timer.
if (mActivities.Count() == 0) {
MaybeStopTimer();
}
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN(StorageActivityService)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStorageActivityService)
NS_INTERFACE_MAP_ENTRY(nsIStorageActivityService)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(StorageActivityService)
NS_IMPL_RELEASE(StorageActivityService)
} // dom namespace
} // mozilla namespace

Просмотреть файл

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_StorageActivityService_h
#define mozilla_dom_StorageActivityService_h
#include "nsDataHashtable.h"
#include "nsIStorageActivityService.h"
#include "nsITimer.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace ipc {
class PrincipalInfo;
} // ipc
namespace dom {
class StorageActivityService final : public nsIStorageActivityService
, public nsIObserver
, public nsITimerCallback
, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTORAGEACTIVITYSERVICE
NS_DECL_NSIOBSERVER
NS_DECL_NSITIMERCALLBACK
// Main-thread only.
static void
SendActivity(nsIPrincipal* aPrincipal);
// Thread-safe.
static void
SendActivity(const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
// Used by XPCOM. Don't use it, use SendActivity() instead.
static already_AddRefed<StorageActivityService>
GetOrCreate();
private:
StorageActivityService();
~StorageActivityService();
void
SendActivityInternal(nsIPrincipal* aPrincipal);
void
SendActivityToParent(nsIPrincipal* aPrincipal);
void
MaybeStartTimer();
void
MaybeStopTimer();
// Activities grouped by origin (+OriginAttributes).
nsDataHashtable<nsCStringHashKey, TimeStamp> mActivities;
nsCOMPtr<nsITimer> mTimer;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_StorageActivityService_h

Просмотреть файл

@ -12,6 +12,7 @@ EXPORTS.mozilla.dom += [
'LocalStorageManager.h',
'SessionStorageManager.h',
'Storage.h',
'StorageActivityService.h',
'StorageIPC.h',
'StorageNotifierService.h',
'StorageUtils.h',
@ -25,6 +26,7 @@ UNIFIED_SOURCES += [
'SessionStorageCache.cpp',
'SessionStorageManager.cpp',
'Storage.cpp',
'StorageActivityService.cpp',
'StorageDBThread.cpp',
'StorageDBUpdater.cpp',
'StorageIPC.cpp',

Просмотреть файл

@ -24,6 +24,7 @@
#include "mozilla/dom/PGamepadTestChannelParent.h"
#include "mozilla/dom/MessagePortParent.h"
#include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/StorageActivityService.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/indexedDB/ActorsParent.h"
@ -987,6 +988,13 @@ BackgroundParentImpl::RecvPClientManagerConstructor(mozilla::dom::PClientManager
return IPC_OK();
}
IPCResult
BackgroundParentImpl::RecvStorageActivity(const PrincipalInfo& aPrincipalInfo)
{
dom::StorageActivityService::SendActivity(aPrincipalInfo);
return IPC_OK();
}
} // namespace ipc
} // namespace mozilla

Просмотреть файл

@ -271,6 +271,9 @@ protected:
virtual mozilla::ipc::IPCResult
RecvPClientManagerConstructor(PClientManagerParent* aActor) override;
virtual mozilla::ipc::IPCResult
RecvStorageActivity(const PrincipalInfo& aPrincipalInfo) override;
};
} // namespace ipc

Просмотреть файл

@ -140,6 +140,10 @@ parent:
async PClientManager();
// This method is used to propagate storage activities from the child actor
// to the parent actor. See StorageActivityService.
async StorageActivity(PrincipalInfo principalInfo);
child:
async PCache();
async PCacheStreamControl();

Просмотреть файл

@ -79,6 +79,10 @@
#define SERVICEWORKERMANAGER_CID \
{ 0xc74bde32, 0xbcc7, 0x4840, { 0x84, 0x30, 0xc7, 0x33, 0x35, 0x1b, 0x21, 0x2a } }
// {69da374a-fda3-4a93-9fbc-d9304f66a7fe}
#define STORAGEACTIVITYSERVICE_CID \
{ 0x69da374a, 0xfda3, 0x4a93, { 0x9f, 0xbc, 0xd9, 0x30, 0x4f, 0x66, 0xa7, 0xfe } }
#define NOTIFICATIONTELEMETRYSERVICE_CID \
{ 0x5995b782, 0x6a0e, 0x4066, { 0xaa, 0xc5, 0x27, 0x6f, 0x0a, 0x9a, 0xd8, 0xcf } }

Просмотреть файл

@ -83,6 +83,7 @@
#include "mozilla/dom/network/UDPSocketChild.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/StorageActivityService.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/dom/workers/WorkerDebuggerManager.h"
#include "mozilla/dom/Notification.h"
@ -252,6 +253,8 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager,
ServiceWorkerManager::GetInstance)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WorkerDebuggerManager,
WorkerDebuggerManager::GetInstance)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(StorageActivityService,
StorageActivityService::GetOrCreate)
#ifdef MOZ_WEBSPEECH
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSynthVoiceRegistry,
@ -625,6 +628,7 @@ NS_DEFINE_NAMED_CID(NS_TEXTEDITOR_CID);
NS_DEFINE_NAMED_CID(DOMREQUEST_SERVICE_CID);
NS_DEFINE_NAMED_CID(QUOTAMANAGER_SERVICE_CID);
NS_DEFINE_NAMED_CID(SERVICEWORKERMANAGER_CID);
NS_DEFINE_NAMED_CID(STORAGEACTIVITYSERVICE_CID);
NS_DEFINE_NAMED_CID(NOTIFICATIONTELEMETRYSERVICE_CID);
NS_DEFINE_NAMED_CID(PUSHNOTIFIER_CID);
NS_DEFINE_NAMED_CID(WORKERDEBUGGERMANAGER_CID);
@ -882,6 +886,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
{ &kDOMREQUEST_SERVICE_CID, false, nullptr, DOMRequestServiceConstructor },
{ &kQUOTAMANAGER_SERVICE_CID, false, nullptr, QuotaManagerServiceConstructor },
{ &kSERVICEWORKERMANAGER_CID, false, nullptr, ServiceWorkerManagerConstructor },
{ &kSTORAGEACTIVITYSERVICE_CID, false, nullptr, StorageActivityServiceConstructor },
{ &kNOTIFICATIONTELEMETRYSERVICE_CID, false, nullptr, NotificationTelemetryServiceConstructor },
{ &kPUSHNOTIFIER_CID, false, nullptr, PushNotifierConstructor },
{ &kWORKERDEBUGGERMANAGER_CID, true, nullptr, WorkerDebuggerManagerConstructor },
@ -1007,6 +1012,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ DOMREQUEST_SERVICE_CONTRACTID, &kDOMREQUEST_SERVICE_CID },
{ QUOTAMANAGER_SERVICE_CONTRACTID, &kQUOTAMANAGER_SERVICE_CID },
{ SERVICEWORKERMANAGER_CONTRACTID, &kSERVICEWORKERMANAGER_CID },
{ STORAGE_ACTIVITY_SERVICE_CONTRACTID, &kSTORAGEACTIVITYSERVICE_CID },
{ NOTIFICATIONTELEMETRYSERVICE_CONTRACTID, &kNOTIFICATIONTELEMETRYSERVICE_CID },
{ PUSHNOTIFIER_CONTRACTID, &kPUSHNOTIFIER_CID },
{ WORKERDEBUGGERMANAGER_CONTRACTID, &kWORKERDEBUGGERMANAGER_CID },