gecko-dev/dom/localstorage/LSObject.h
Nika Layzell 2485971930 Bug 1805963 - Part 1: Stop using local execution mode for LSObject operations, r=janv
The reason this was originally added was for bug 1516277 in order to allow a
synchronous dispatch to a background thread to create a new PBackground
instance without deadlocking. The dispatch didn't want to support running other
main thread runnables, but needed to support sending the runnable to create a
new PBackground instance on the main thread.

This is no longer an issue since bug 1737828, where we changed PBackground
startup to no longer require the main thread, so we can remove the complexity
and instead use a monitor to handle changes. This also allows removing the
timer, as the monitor's timeout can be used instead.

I also changed the logic slightly to make it more likely to catch an expecting
shutdown by waiting on the monitor with a timeout, as previously the main
thread would not be being woken up and checking the condition very often, due
to it not having any runnables to execute.

Differential Revision: https://phabricator.services.mozilla.com/D164840
2022-12-21 22:01:24 +00:00

220 lines
7.6 KiB
C++

/* -*- 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_localstorage_LSObject_h
#define mozilla_dom_localstorage_LSObject_h
#include <cstdint>
#include "ErrorList.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "nsCycleCollectionParticipant.h"
#include "nsID.h"
#include "nsISupports.h"
#include "nsStringFwd.h"
#include "nsTArrayForwardDeclare.h"
class nsGlobalWindowInner;
class nsIEventTarget;
class nsIPrincipal;
class nsISerialEventTarget;
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
namespace dom {
class LSDatabase;
class LSObjectChild;
class LSObserver;
class LSRequestChild;
class LSRequestChildCallback;
class LSRequestParams;
class LSRequestResponse;
/**
* Backs the WebIDL `Storage` binding; all content LocalStorage calls are
* handled by this class.
*
* ## Semantics under e10s / multi-process ##
*
* A snapshot mechanism used in conjuction with stable points ensures that JS
* run-to-completion semantics are experienced even if the same origin is
* concurrently accessing LocalStorage across multiple content processes.
*
* ### Snapshot Consistency ###
*
* An LSSnapshot is created locally whenever the contents of LocalStorage are
* about to be read or written (including length). This synchronously
* establishes a corresponding Snapshot in PBackground in the parent process.
* An effort is made to send as much data from the parent process as possible,
* so sites using a small/reasonable amount of LocalStorage data will have it
* sent to the content process for immediate access. Sites with greater
* LocalStorage usage may only have some of the information relayed. In that
* case, the parent Snapshot will ensure that it retains the exact state of the
* parent Datastore at the moment the Snapshot was created.
*/
class LSObject final : public Storage {
using PrincipalInfo = mozilla::ipc::PrincipalInfo;
friend nsGlobalWindowInner;
UniquePtr<PrincipalInfo> mPrincipalInfo;
UniquePtr<PrincipalInfo> mStoragePrincipalInfo;
RefPtr<LSDatabase> mDatabase;
RefPtr<LSObserver> mObserver;
uint32_t mPrivateBrowsingId;
Maybe<nsID> mClientId;
Maybe<PrincipalInfo> mClientPrincipalInfo;
nsCString mOrigin;
nsCString mOriginKey;
nsString mDocumentURI;
bool mInExplicitSnapshot;
public:
/**
* The normal creation path invoked by nsGlobalWindowInner.
*/
static nsresult CreateForWindow(nsPIDOMWindowInner* aWindow,
Storage** aStorage);
/**
* nsIDOMStorageManager creation path for use in testing logic. Supports the
* system principal where CreateForWindow does not. This is also why aPrivate
* exists separate from the principal; because the system principal can never
* be mutated to have a private browsing id even though it can be used in a
* window/document marked as private browsing. That's a legacy issue that is
* being dealt with, but it's why it exists here.
*/
static nsresult CreateForPrincipal(nsPIDOMWindowInner* aWindow,
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal,
const nsAString& aDocumentURI,
bool aPrivate, LSObject** aObject);
void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(LSObject); }
const RefPtr<LSDatabase>& DatabaseStrongRef() const { return mDatabase; }
const nsString& DocumentURI() const { return mDocumentURI; }
bool InExplicitSnapshot() const { return mInExplicitSnapshot; }
LSRequestChild* StartRequest(const LSRequestParams& aParams,
LSRequestChildCallback* aCallback);
// Storage overrides.
StorageType Type() const override;
bool IsForkOf(const Storage* aStorage) const override;
int64_t GetOriginQuotaUsage() const override;
void Disconnect() override;
uint32_t GetLength(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void Key(uint32_t aIndex, nsAString& aResult, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void GetItem(const nsAString& aKey, nsAString& aResult,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void GetSupportedNames(nsTArray<nsString>& aNames) override;
void SetItem(const nsAString& aKey, const nsAString& aValue,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
//////////////////////////////////////////////////////////////////////////////
// Testing Methods: See Storage.h
void Open(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void Close(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void CheckpointExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
bool GetHasSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
int64_t GetSnapshotUsage(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
//////////////////////////////////////////////////////////////////////////////
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LSObject, Storage)
private:
LSObject(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal);
~LSObject();
nsresult DoRequestSynchronously(const LSRequestParams& aParams,
LSRequestResponse& aResponse);
nsresult EnsureDatabase();
void DropDatabase();
/**
* Invoked by nsGlobalWindowInner whenever a new "storage" event listener is
* added to the window in order to ensure that "storage" events are received
* from other processes. (`LSObject::OnChange` directly invokes
* `Storage::NotifyChange` to notify in-process listeners.)
*
* If this is the first request in the process for an observer for this
* origin, this will trigger a RequestHelper-mediated synchronous LSRequest
* to prepare a new observer in the parent process and also construction of
* corresponding actors, which will result in the observer being fully
* registered in the parent process.
*/
nsresult EnsureObserver();
/**
* Invoked by nsGlobalWindowInner whenever its last "storage" event listener
* is removed.
*/
void DropObserver();
/**
* Internal helper method used by mutation methods that wraps the call to
* Storage::NotifyChange to generate same-process "storage" events.
*/
void OnChange(const nsAString& aKey, const nsAString& aOldValue,
const nsAString& aNewValue);
// Storage overrides.
void LastRelease() override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LSObject_h