Bug 1286798 - Part 19: Implement a helper method for datastore preloading verification; r=asuth
authorJan Varga <jan.varga@gmail.com>
Thu, 29 Nov 2018 21:48:15 +0100
changeset 508017 5714205a7bf9ea1083a7c24f18b188d8304679cd
parent 508016 61ce2d795e8e3db93cb8a191bad0a80b67eee92a
child 508018 615640a58a97fdf95584df9222358ff0372ad31d
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1286798
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1286798 - Part 19: Implement a helper method for datastore preloading verification; r=asuth A new type of request is introduced, PBackgroundLSSimpleRequest. This protocol is much simpler than PBackgroundLSRequest which needs to be cancelable.
dom/localstorage/ActorsChild.cpp
dom/localstorage/ActorsChild.h
dom/localstorage/ActorsParent.cpp
dom/localstorage/ActorsParent.h
dom/localstorage/LocalStorageManager2.cpp
dom/localstorage/LocalStorageManager2.h
dom/localstorage/PBackgroundLSSharedTypes.ipdlh
dom/localstorage/PBackgroundLSSimpleRequest.ipdl
dom/localstorage/moz.build
dom/localstorage/nsILocalStorageManager.idl
dom/storage/LocalStorageManager.cpp
dom/tests/browser/browser.ini
dom/tests/browser/browser_localStorage_e10s.js
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
--- a/dom/localstorage/ActorsChild.cpp
+++ b/dom/localstorage/ActorsChild.cpp
@@ -272,10 +272,47 @@ LSRequestChild::RecvReady()
 
   mFinishing = true;
 
   SendFinish();
 
   return IPC_OK();
 }
 
+/*******************************************************************************
+ * LSSimpleRequestChild
+ ******************************************************************************/
+
+LSSimpleRequestChild::LSSimpleRequestChild(
+                                        LSSimpleRequestChildCallback* aCallback)
+  : mCallback(aCallback)
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(aCallback);
+
+  MOZ_COUNT_CTOR(LSSimpleRequestChild);
+}
+
+LSSimpleRequestChild::~LSSimpleRequestChild()
+{
+  AssertIsOnOwningThread();
+
+  MOZ_COUNT_DTOR(LSSimpleRequestChild);
+}
+
+void
+LSSimpleRequestChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  AssertIsOnOwningThread();
+}
+
+mozilla::ipc::IPCResult
+LSSimpleRequestChild::Recv__delete__(const LSSimpleRequestResponse& aResponse)
+{
+  AssertIsOnOwningThread();
+
+  mCallback->OnResponse(aResponse);
+
+  return IPC_OK();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/localstorage/ActorsChild.h
+++ b/dom/localstorage/ActorsChild.h
@@ -6,31 +6,34 @@
 
 #ifndef mozilla_dom_localstorage_ActorsChild_h
 #define mozilla_dom_localstorage_ActorsChild_h
 
 #include "mozilla/dom/PBackgroundLSDatabaseChild.h"
 #include "mozilla/dom/PBackgroundLSObjectChild.h"
 #include "mozilla/dom/PBackgroundLSObserverChild.h"
 #include "mozilla/dom/PBackgroundLSRequestChild.h"
+#include "mozilla/dom/PBackgroundLSSimpleRequestChild.h"
 
 namespace mozilla {
 
 namespace ipc {
 
 class BackgroundChildImpl;
 
 } // namespace ipc
 
 namespace dom {
 
+class LocalStorageManager2;
 class LSDatabase;
 class LSObject;
 class LSObserver;
 class LSRequestChildCallback;
+class LSSimpleRequestChildCallback;
 
 class LSObjectChild final
   : public PBackgroundLSObjectChild
 {
   friend class mozilla::ipc::BackgroundChildImpl;
   friend class LSObject;
 
   LSObject* mObject;
@@ -191,12 +194,56 @@ public:
   virtual void
   OnResponse(const LSRequestResponse& aResponse) = 0;
 
 protected:
   virtual ~LSRequestChildCallback()
   { }
 };
 
+class LSSimpleRequestChild final
+  : public PBackgroundLSSimpleRequestChild
+{
+  friend class LocalStorageManager2;
+
+  RefPtr<LSSimpleRequestChildCallback> mCallback;
+
+  NS_DECL_OWNINGTHREAD
+
+public:
+  void
+  AssertIsOnOwningThread() const
+  {
+    NS_ASSERT_OWNINGTHREAD(LSSimpleReqeustChild);
+  }
+
+private:
+  // Only created by LocalStorageManager2.
+  explicit LSSimpleRequestChild(LSSimpleRequestChildCallback* aCallback);
+
+  // Only destroyed by mozilla::ipc::BackgroundChildImpl.
+  ~LSSimpleRequestChild();
+
+  // IPDL methods are only called by IPDL.
+  void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  mozilla::ipc::IPCResult
+  Recv__delete__(const LSSimpleRequestResponse& aResponse) override;
+};
+
+class NS_NO_VTABLE LSSimpleRequestChildCallback
+{
+public:
+  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
+
+  virtual void
+  OnResponse(const LSSimpleRequestResponse& aResponse) = 0;
+
+protected:
+  virtual ~LSSimpleRequestChildCallback()
+  { }
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_localstorage_ActorsChild_h
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -13,16 +13,17 @@
 #include "mozStorageCID.h"
 #include "mozStorageHelper.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/PBackgroundLSDatabaseParent.h"
 #include "mozilla/dom/PBackgroundLSObjectParent.h"
 #include "mozilla/dom/PBackgroundLSObserverParent.h"
 #include "mozilla/dom/PBackgroundLSRequestParent.h"
 #include "mozilla/dom/PBackgroundLSSharedTypes.h"
+#include "mozilla/dom/PBackgroundLSSimpleRequestParent.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/quota/UsageInfo.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
@@ -1489,16 +1490,84 @@ public:
 private:
   nsresult
   Open() override;
 
   void
   GetResponse(LSRequestResponse& aResponse) override;
 };
 
+class LSSimpleRequestBase
+  : public DatastoreOperationBase
+  , public PBackgroundLSSimpleRequestParent
+{
+protected:
+  enum class State
+  {
+    // Just created on the PBackground thread. Next step is Opening.
+    Initial,
+
+    // Waiting to open/opening on the main thread. Next step is SendingResults.
+    Opening,
+
+    // Waiting to send/sending results on the PBackground thread. Next step is
+    // Completed.
+    SendingResults,
+
+    // All done.
+    Completed
+  };
+
+  State mState;
+
+public:
+  LSSimpleRequestBase();
+
+  void
+  Dispatch();
+
+protected:
+  ~LSSimpleRequestBase() override;
+
+  virtual nsresult
+  Open() = 0;
+
+  virtual void
+  GetResponse(LSSimpleRequestResponse& aResponse) = 0;
+
+private:
+  void
+  SendResults();
+
+  // Common nsIRunnable implementation that subclasses may not override.
+  NS_IMETHOD
+  Run() final;
+
+  // IPDL methods.
+  void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+};
+
+class PreloadedOp
+  : public LSSimpleRequestBase
+{
+  const LSSimpleRequestPreloadedParams mParams;
+  nsCString mOrigin;
+
+public:
+  explicit PreloadedOp(const LSSimpleRequestParams& aParams);
+
+private:
+  nsresult
+  Open() override;
+
+  void
+  GetResponse(LSSimpleRequestResponse& aResponse) override;
+};
+
 /*******************************************************************************
  * Other class declarations
  ******************************************************************************/
 
 class QuotaClient final
   : public mozilla::dom::quota::Client
 {
   class ClearPrivateBrowsingRunnable;
@@ -1872,16 +1941,77 @@ DeallocPBackgroundLSRequestParent(PBackg
 
   // Transfer ownership back from IPDL.
   RefPtr<LSRequestBase> actor =
     dont_AddRef(static_cast<LSRequestBase*>(aActor));
 
   return true;
 }
 
+PBackgroundLSSimpleRequestParent*
+AllocPBackgroundLSSimpleRequestParent(const LSSimpleRequestParams& aParams)
+{
+  AssertIsOnBackgroundThread();
+
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
+    return nullptr;
+  }
+
+  RefPtr<LSSimpleRequestBase> actor;
+
+  switch (aParams.type()) {
+    case LSSimpleRequestParams::TLSSimpleRequestPreloadedParams: {
+      RefPtr<PreloadedOp> preloadedOp =
+        new PreloadedOp(aParams);
+
+      actor = std::move(preloadedOp);
+
+      break;
+    }
+
+    default:
+      MOZ_CRASH("Should never get here!");
+  }
+
+  // Transfer ownership to IPDL.
+  return actor.forget().take();
+}
+
+bool
+RecvPBackgroundLSSimpleRequestConstructor(
+                                       PBackgroundLSSimpleRequestParent* aActor,
+                                       const LSSimpleRequestParams& aParams)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aActor);
+  MOZ_ASSERT(aParams.type() != LSSimpleRequestParams::T__None);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
+
+  // The actor is now completely built.
+
+  auto* op = static_cast<LSSimpleRequestBase*>(aActor);
+
+  op->Dispatch();
+
+  return true;
+}
+
+bool
+DeallocPBackgroundLSSimpleRequestParent(
+                                       PBackgroundLSSimpleRequestParent* aActor)
+{
+  AssertIsOnBackgroundThread();
+
+  // Transfer ownership back from IPDL.
+  RefPtr<LSSimpleRequestBase> actor =
+    dont_AddRef(static_cast<LSSimpleRequestBase*>(aActor));
+
+  return true;
+}
+
 namespace localstorage {
 
 already_AddRefed<mozilla::dom::quota::Client>
 CreateQuotaClient()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
 
@@ -4223,16 +4353,183 @@ PrepareObserverOp::GetResponse(LSRequest
 
   LSRequestPrepareObserverResponse prepareObserverResponse;
   prepareObserverResponse.observerId() = observerId;
 
   aResponse = prepareObserverResponse;
 }
 
 /*******************************************************************************
++ * LSSimpleRequestBase
++ ******************************************************************************/
+
+LSSimpleRequestBase::LSSimpleRequestBase()
+  : mState(State::Initial)
+{
+}
+
+LSSimpleRequestBase::~LSSimpleRequestBase()
+{
+  MOZ_ASSERT_IF(MayProceedOnNonOwningThread(),
+                mState == State::Initial || mState == State::Completed);
+}
+
+void
+LSSimpleRequestBase::Dispatch()
+{
+  AssertIsOnOwningThread();
+
+  mState = State::Opening;
+
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
+}
+
+void
+LSSimpleRequestBase::SendResults()
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(mState == State::SendingResults);
+
+  if (!MayProceed()) {
+    MaybeSetFailureCode(NS_ERROR_FAILURE);
+  } else {
+    LSSimpleRequestResponse response;
+
+    if (NS_SUCCEEDED(ResultCode())) {
+      GetResponse(response);
+    } else {
+      response = ResultCode();
+    }
+
+    Unused <<
+      PBackgroundLSSimpleRequestParent::Send__delete__(this, response);
+  }
+
+  mState = State::Completed;
+}
+
+NS_IMETHODIMP
+LSSimpleRequestBase::Run()
+{
+  nsresult rv;
+
+  switch (mState) {
+    case State::Opening:
+      rv = Open();
+      break;
+
+    case State::SendingResults:
+      SendResults();
+      return NS_OK;
+
+    default:
+      MOZ_CRASH("Bad state!");
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::SendingResults) {
+    MaybeSetFailureCode(rv);
+
+    // Must set mState before dispatching otherwise we will race with the owning
+    // thread.
+    mState = State::SendingResults;
+
+    if (IsOnOwningThread()) {
+      SendResults();
+    } else {
+      MOZ_ALWAYS_SUCCEEDS(
+        OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
+    }
+  }
+
+  return NS_OK;
+}
+
+void
+LSSimpleRequestBase::ActorDestroy(ActorDestroyReason aWhy)
+{
+  AssertIsOnOwningThread();
+
+  NoteComplete();
+}
+
+/*******************************************************************************
+ * PreloadedOp
+ ******************************************************************************/
+
+PreloadedOp::PreloadedOp(const LSSimpleRequestParams& aParams)
+  : mParams(aParams.get_LSSimpleRequestPreloadedParams())
+{
+  MOZ_ASSERT(aParams.type() ==
+               LSSimpleRequestParams::TLSSimpleRequestPreloadedParams);
+}
+
+nsresult
+PreloadedOp::Open()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mState == State::Opening);
+
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+      !MayProceedOnNonOwningThread()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  const PrincipalInfo& principalInfo = mParams.principalInfo();
+
+  if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
+    QuotaManager::GetInfoForChrome(nullptr, nullptr, &mOrigin);
+  } else {
+    MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
+
+    nsresult rv;
+    nsCOMPtr<nsIPrincipal> principal =
+      PrincipalInfoToPrincipal(principalInfo, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = QuotaManager::GetInfoFromPrincipal(principal,
+                                            nullptr,
+                                            nullptr,
+                                            &mOrigin);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  mState = State::SendingResults;
+  MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
+
+  return NS_OK;
+}
+
+void
+PreloadedOp::GetResponse(LSSimpleRequestResponse& aResponse)
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(mState == State::SendingResults);
+  MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
+
+  bool preloaded;
+  RefPtr<Datastore> datastore;
+  if (gDatastores &&
+      (datastore = gDatastores->Get(mOrigin)) &&
+      !datastore->IsClosed()) {
+    preloaded = true;
+  } else {
+    preloaded = false;
+  }
+
+  LSSimpleRequestPreloadedResponse preloadedResponse;
+  preloadedResponse.preloaded() = preloaded;
+
+  aResponse = preloadedResponse;
+}
+
+/*******************************************************************************
  * QuotaClient
  ******************************************************************************/
 
 QuotaClient* QuotaClient::sInstance = nullptr;
 bool QuotaClient::sObserversRegistered = false;
 
 QuotaClient::QuotaClient()
   : mShutdownRequested(false)
--- a/dom/localstorage/ActorsParent.h
+++ b/dom/localstorage/ActorsParent.h
@@ -14,19 +14,21 @@ namespace ipc {
 class PBackgroundParent;
 class PrincipalInfo;
 
 } // namespace ipc
 
 namespace dom {
 
 class LSRequestParams;
+class LSSimpleRequestParams;
 class PBackgroundLSObjectParent;
 class PBackgroundLSObserverParent;
 class PBackgroundLSRequestParent;
+class PBackgroundLSSimpleRequestParent;
 
 namespace quota {
 
 class Client;
 
 } // namespace quota
 
 PBackgroundLSObjectParent*
@@ -62,16 +64,28 @@ AllocPBackgroundLSRequestParent(
 
 bool
 RecvPBackgroundLSRequestConstructor(PBackgroundLSRequestParent* aActor,
                                     const LSRequestParams& aParams);
 
 bool
 DeallocPBackgroundLSRequestParent(PBackgroundLSRequestParent* aActor);
 
+PBackgroundLSSimpleRequestParent*
+AllocPBackgroundLSSimpleRequestParent(const LSSimpleRequestParams& aParams);
+
+bool
+RecvPBackgroundLSSimpleRequestConstructor(
+                                       PBackgroundLSSimpleRequestParent* aActor,
+                                       const LSSimpleRequestParams& aParams);
+
+bool
+DeallocPBackgroundLSSimpleRequestParent(
+                                      PBackgroundLSSimpleRequestParent* aActor);
+
 namespace localstorage {
 
 already_AddRefed<mozilla::dom::quota::Client>
 CreateQuotaClient();
 
 } // namespace localstorage
 
 } // namespace dom
--- a/dom/localstorage/LocalStorageManager2.cpp
+++ b/dom/localstorage/LocalStorageManager2.cpp
@@ -2,20 +2,93 @@
 /* vim: set ts=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 "LocalStorageManager2.h"
 
 #include "LSObject.h"
+#include "mozilla/dom/Promise.h"
 
 namespace mozilla {
 namespace dom {
 
+namespace {
+
+class SimpleRequestResolver final
+  : public LSSimpleRequestChildCallback
+{
+  RefPtr<Promise> mPromise;
+
+public:
+  explicit SimpleRequestResolver(Promise* aPromise)
+    : mPromise(aPromise)
+  { }
+
+  NS_INLINE_DECL_REFCOUNTING(SimpleRequestResolver, override);
+
+private:
+  ~SimpleRequestResolver() = default;
+
+  void
+  HandleResponse(nsresult aResponse);
+
+  void
+  HandleResponse(bool aResponse);
+
+  // LSRequestChildCallback
+  void
+  OnResponse(const LSSimpleRequestResponse& aResponse) override;
+};
+
+nsresult
+CreatePromise(JSContext* aContext, Promise** aPromise)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aContext);
+
+  nsIGlobalObject* global =
+    xpc::NativeGlobal(JS::CurrentGlobalOrNull(aContext));
+  if (NS_WARN_IF(!global)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  ErrorResult result;
+  RefPtr<Promise> promise = Promise::Create(global, result);
+  if (result.Failed()) {
+    return result.StealNSResult();
+  }
+
+  promise.forget(aPromise);
+  return NS_OK;
+}
+
+nsresult
+CheckedPrincipalToPrincipalInfo(nsIPrincipal* aPrincipal,
+                                PrincipalInfo& aPrincipalInfo)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+
+  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &aPrincipalInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (aPrincipalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
+      aPrincipalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+} // namespace
+
 LocalStorageManager2::LocalStorageManager2()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(NextGenLocalStorageEnabled());
 }
 
 LocalStorageManager2::~LocalStorageManager2()
 {
@@ -104,10 +177,105 @@ LocalStorageManager2::GetNextGenLocalSto
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aResult);
 
   *aResult = NextGenLocalStorageEnabled();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+LocalStorageManager2::IsPreloaded(nsIPrincipal* aPrincipal,
+                                  JSContext* aContext,
+                                  nsISupports** _retval)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(_retval);
+
+  RefPtr<Promise> promise;
+  nsresult rv = CreatePromise(aContext, getter_AddRefs(promise));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  LSSimpleRequestPreloadedParams params;
+
+  rv = CheckedPrincipalToPrincipalInfo(aPrincipal,
+                                       params.principalInfo());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = StartSimpleRequest(promise, params);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  promise.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+LocalStorageManager2::StartSimpleRequest(Promise* aPromise,
+                                         const LSSimpleRequestParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPromise);
+
+  PBackgroundChild* backgroundActor =
+    BackgroundChild::GetOrCreateForCurrentThread();
+  if (NS_WARN_IF(!backgroundActor)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<SimpleRequestResolver> resolver = new SimpleRequestResolver(aPromise);
+
+  auto actor = new LSSimpleRequestChild(resolver);
+
+  if (!backgroundActor->SendPBackgroundLSSimpleRequestConstructor(actor,
+                                                                  aParams)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+void
+SimpleRequestResolver::HandleResponse(nsresult aResponse)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mPromise);
+
+  mPromise->MaybeReject(aResponse);
+}
+
+void
+SimpleRequestResolver::HandleResponse(bool aResponse)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mPromise);
+
+  mPromise->MaybeResolve(aResponse);
+}
+
+void
+SimpleRequestResolver::OnResponse(const LSSimpleRequestResponse& aResponse)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  switch (aResponse.type()) {
+    case LSSimpleRequestResponse::Tnsresult:
+      HandleResponse(aResponse.get_nsresult());
+      break;
+
+    case LSSimpleRequestResponse::TLSSimpleRequestPreloadedResponse:
+      HandleResponse(
+        aResponse.get_LSSimpleRequestPreloadedResponse().preloaded());
+      break;
+
+   default:
+      MOZ_CRASH("Unknown response type!");
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/localstorage/LocalStorageManager2.h
+++ b/dom/localstorage/LocalStorageManager2.h
@@ -8,27 +8,34 @@
 #define mozilla_dom_localstorage_LocalStorageManager2_h
 
 #include "nsIDOMStorageManager.h"
 #include "nsILocalStorageManager.h"
 
 namespace mozilla {
 namespace dom {
 
+class LSSimpleRequestParams;
+class Promise;
+
 class LocalStorageManager2 final
   : public nsIDOMStorageManager
   , public nsILocalStorageManager
 {
 public:
   LocalStorageManager2();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMSTORAGEMANAGER
   NS_DECL_NSILOCALSTORAGEMANAGER
 
 private:
   ~LocalStorageManager2();
+
+  nsresult
+  StartSimpleRequest(Promise* aPromise,
+                     const LSSimpleRequestParams& aParams);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_localstorage_LocalStorageManager2_h
--- a/dom/localstorage/PBackgroundLSSharedTypes.ipdlh
+++ b/dom/localstorage/PBackgroundLSSharedTypes.ipdlh
@@ -18,10 +18,20 @@ struct LSRequestPrepareObserverParams
 };
 
 union LSRequestParams
 {
   LSRequestPrepareDatastoreParams;
   LSRequestPrepareObserverParams;
 };
 
+struct LSSimpleRequestPreloadedParams
+{
+  PrincipalInfo principalInfo;
+};
+
+union LSSimpleRequestParams
+{
+  LSSimpleRequestPreloadedParams;
+};
+
 } // namespace dom
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/PBackgroundLSSimpleRequest.ipdl
@@ -0,0 +1,30 @@
+/* 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 protocol PBackground;
+
+namespace mozilla {
+namespace dom {
+
+struct LSSimpleRequestPreloadedResponse
+{
+  bool preloaded;
+};
+
+union LSSimpleRequestResponse
+{
+  nsresult;
+  LSSimpleRequestPreloadedResponse;
+};
+
+protocol PBackgroundLSSimpleRequest
+{
+  manager PBackground;
+
+child:
+  async __delete__(LSSimpleRequestResponse response);
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/localstorage/moz.build
+++ b/dom/localstorage/moz.build
@@ -33,16 +33,17 @@ UNIFIED_SOURCES += [
 ]
 
 IPDL_SOURCES += [
     'PBackgroundLSDatabase.ipdl',
     'PBackgroundLSObject.ipdl',
     'PBackgroundLSObserver.ipdl',
     'PBackgroundLSRequest.ipdl',
     'PBackgroundLSSharedTypes.ipdlh',
+    'PBackgroundLSSimpleRequest.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
--- a/dom/localstorage/nsILocalStorageManager.idl
+++ b/dom/localstorage/nsILocalStorageManager.idl
@@ -7,9 +7,12 @@
 #include "nsISupports.idl"
 
 interface nsIPrincipal;
 
 [scriptable, builtinclass, uuid(d4f534da-2744-4db3-8774-8b187c64ade9)]
 interface nsILocalStorageManager : nsISupports
 {
   readonly attribute boolean nextGenLocalStorageEnabled;
+
+  [implicit_jscontext] nsISupports
+  isPreloaded(in nsIPrincipal aPrincipal);
 };
--- a/dom/storage/LocalStorageManager.cpp
+++ b/dom/storage/LocalStorageManager.cpp
@@ -376,16 +376,28 @@ LocalStorageManager::GetNextGenLocalStor
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aResult);
 
   *aResult = NextGenLocalStorageEnabled();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+LocalStorageManager::IsPreloaded(nsIPrincipal* aPrincipal,
+                                 JSContext* aContext,
+                                 nsISupports** _retval)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(_retval);
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 void
 LocalStorageManager::ClearCaches(uint32_t aUnloadFlags,
                                  const OriginAttributesPattern& aPattern,
                                  const nsACString& aOriginScope)
 {
   for (auto iter1 = mCaches.Iter(); !iter1.Done(); iter1.Next()) {
     OriginAttributes oa;
     DebugOnly<bool> rv = oa.PopulateFromSuffix(iter1.Key());
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -48,18 +48,18 @@ skip-if = e10s
 [browser_hasbeforeunload.js]
 support-files =
   beforeunload_test_page.html
 run-if = e10s
 [browser_largeAllocation_win32.js]
 skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires e10s
 [browser_largeAllocation_non_win32.js]
 skip-if = !e10s || (os == "win" && processor == "x86") || (verify && debug && (os == 'linux')) || (os == 'linux') || (os == 'mac' && debug)  # Large-Allocation requires e10s # Bug 1336075
-#[browser_localStorage_e10s.js]
-#skip-if = !e10s || verify # This is a test of e10s functionality.
+[browser_localStorage_e10s.js]
+skip-if = !e10s || verify # This is a test of e10s functionality.
 [browser_localStorage_privatestorageevent.js]
 [browser_persist_cookies.js]
 support-files =
   set-samesite-cookies-and-redirect.sjs
   mimeme.sjs
 [browser_persist_mixed_content_image.js]
 support-files =
   test_mixed_content_image.html
--- a/dom/tests/browser/browser_localStorage_e10s.js
+++ b/dom/tests/browser/browser_localStorage_e10s.js
@@ -74,16 +74,20 @@ async function cleanupTabs(knownTabs) {
 /**
  * Wait for a LocalStorage flush to occur.  This notification can occur as a
  * result of any of:
  * - The normal, hardcoded 5-second flush timer.
  * - InsertDBOp seeing a preload op for an origin with outstanding changes.
  * - Us generating a "domstorage-test-flush-force" observer notification.
  */
 function waitForLocalStorageFlush() {
+  if (Services.lsm.nextGenLocalStorageEnabled) {
+    return new Promise(resolve => executeSoon(resolve));
+  }
+
   return new Promise(function(resolve) {
     let observer = {
       observe: function() {
         SpecialPowers.removeObserver(observer, "domstorage-test-flushed");
         resolve();
       }
     };
     SpecialPowers.addObserver(observer, "domstorage-test-flushed");
@@ -96,16 +100,20 @@ function waitForLocalStorageFlush() {
  * to automatically flush when necessary for correctness.
  *
  * The notification we're waiting for to verify flushing is fundamentally
  * ambiguous (see waitForLocalStorageFlush), so we actually trigger the flush
  * twice and wait twice.  In the event there was a race, there will be 3 flush
  * notifications, but correctness is guaranteed after the second notification.
  */
 function triggerAndWaitForLocalStorageFlush() {
+  if (Services.lsm.nextGenLocalStorageEnabled) {
+    return new Promise(resolve => executeSoon(resolve));
+  }
+
   SpecialPowers.notifyObservers(null, "domstorage-test-flush-force");
   // This first wait is ambiguous...
   return waitForLocalStorageFlush().then(function() {
     // So issue a second flush and wait for that.
     SpecialPowers.notifyObservers(null, "domstorage-test-flush-force");
     return waitForLocalStorageFlush();
   })
 }
@@ -122,16 +130,28 @@ function triggerAndWaitForLocalStorageFl
  * So we explicitly access the cache here in the parent for the origin and issue
  * an explicit clear.  Clearing all storage might be a little easier but seems
  * like asking for intermittent failures.
  */
 function clearOriginStorageEnsuringNoPreload() {
   let principal =
     Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
       HELPER_PAGE_ORIGIN);
+
+  if (Services.lsm.nextGenLocalStorageEnabled) {
+    let request =
+      Services.qms.clearStoragesForPrincipal(principal, "default", "ls");
+    let promise = new Promise(resolve => {
+      request.callback = () => {
+        resolve();
+      };
+    });
+    return promise;
+  }
+
   // We want to use createStorage to force the cache to be created so we can
   // issue the clear.  It's possible for getStorage to return false but for the
   // origin preload hash to still have our origin in it.
   let storage = Services.domStorageManager.createStorage(null, principal, "");
   storage.clear();
 
   // We also need to trigger a flush os that mOriginsHavingData gets updated.
   // The inherent flush race is fine here because
@@ -141,16 +161,19 @@ function clearOriginStorageEnsuringNoPre
 async function verifyTabPreload(knownTab, expectStorageExists) {
   let storageExists = await ContentTask.spawn(
     knownTab.tab.linkedBrowser,
     HELPER_PAGE_ORIGIN,
     function(origin) {
       let principal =
         Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
           origin);
+      if (Services.lsm.nextGenLocalStorageEnabled) {
+        return Services.lsm.isPreloaded(principal);
+      }
       return !!Services.domStorageManager.getStorage(null, principal);
     });
   is(storageExists, expectStorageExists, "Storage existence === preload");
 }
 
 /**
  * Instruct the given tab to execute the given series of mutations.  For
  * simplicity, the mutations representation matches the expected events rep.
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -14,16 +14,17 @@
 #endif
 #include "mozilla/media/MediaChild.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/SchedulerGroup.h"
 #include "mozilla/dom/ClientManagerActors.h"
 #include "mozilla/dom/PBackgroundLSObjectChild.h"
 #include "mozilla/dom/PBackgroundLSObserverChild.h"
 #include "mozilla/dom/PBackgroundLSRequestChild.h"
+#include "mozilla/dom/PBackgroundLSSimpleRequestChild.h"
 #include "mozilla/dom/PBackgroundSDBConnectionChild.h"
 #include "mozilla/dom/PFileSystemRequestChild.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
 #include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
 #include "mozilla/dom/ipc/IPCBlobInputStreamChild.h"
@@ -312,16 +313,34 @@ BackgroundChildImpl::DeallocPBackgroundL
                                       PBackgroundLocalStorageCacheChild* aActor)
 {
   MOZ_ASSERT(aActor);
 
   delete aActor;
   return true;
 }
 
+BackgroundChildImpl::PBackgroundLSSimpleRequestChild*
+BackgroundChildImpl::AllocPBackgroundLSSimpleRequestChild(
+                                           const LSSimpleRequestParams& aParams)
+{
+  MOZ_CRASH("PBackgroundLSSimpleRequestChild actor should be manually "
+            "constructed!");
+}
+
+bool
+BackgroundChildImpl::DeallocPBackgroundLSSimpleRequestChild(
+                                        PBackgroundLSSimpleRequestChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+
+  delete aActor;
+  return true;
+}
+
 BackgroundChildImpl::PBackgroundStorageChild*
 BackgroundChildImpl::AllocPBackgroundStorageChild(const nsString& aProfilePath)
 {
   MOZ_CRASH("PBackgroundStorageChild actors should be manually constructed!");
 }
 
 bool
 BackgroundChildImpl::DeallocPBackgroundStorageChild(
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -95,16 +95,25 @@ protected:
                                     override;
 
   virtual PBackgroundLSRequestChild*
   AllocPBackgroundLSRequestChild(const LSRequestParams& aParams) override;
 
   virtual bool
   DeallocPBackgroundLSRequestChild(PBackgroundLSRequestChild* aActor) override;
 
+  virtual PBackgroundLSSimpleRequestChild*
+  AllocPBackgroundLSSimpleRequestChild(const LSSimpleRequestParams& aParams)
+                                       override;
+
+  virtual bool
+  DeallocPBackgroundLSSimpleRequestChild(
+                                        PBackgroundLSSimpleRequestChild* aActor)
+                                        override;
+
   virtual PBackgroundLocalStorageCacheChild*
   AllocPBackgroundLocalStorageCacheChild(const PrincipalInfo& aPrincipalInfo,
                                          const nsCString& aOriginKey,
                                          const uint32_t& aPrivateBrowsingId)
                                          override;
 
   virtual bool
   DeallocPBackgroundLocalStorageCacheChild(
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -407,16 +407,53 @@ BackgroundParentImpl::DeallocPBackground
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   return mozilla::dom::DeallocPBackgroundLSRequestParent(aActor);
 }
 
+BackgroundParentImpl::PBackgroundLSSimpleRequestParent*
+BackgroundParentImpl::AllocPBackgroundLSSimpleRequestParent(
+                                           const LSSimpleRequestParams& aParams)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+
+  return mozilla::dom::AllocPBackgroundLSSimpleRequestParent(aParams);
+}
+
+mozilla::ipc::IPCResult
+BackgroundParentImpl::RecvPBackgroundLSSimpleRequestConstructor(
+                                       PBackgroundLSSimpleRequestParent* aActor,
+                                       const LSSimpleRequestParams& aParams)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aActor);
+
+  if (!mozilla::dom::RecvPBackgroundLSSimpleRequestConstructor(aActor,
+                                                               aParams)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
+bool
+BackgroundParentImpl::DeallocPBackgroundLSSimpleRequestParent(
+                                       PBackgroundLSSimpleRequestParent* aActor)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aActor);
+
+  return mozilla::dom::DeallocPBackgroundLSSimpleRequestParent(aActor);
+}
+
 BackgroundParentImpl::PBackgroundLocalStorageCacheParent*
 BackgroundParentImpl::AllocPBackgroundLocalStorageCacheParent(
                                             const PrincipalInfo& aPrincipalInfo,
                                             const nsCString& aOriginKey,
                                             const uint32_t& aPrivateBrowsingId)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -110,16 +110,31 @@ protected:
   virtual mozilla::ipc::IPCResult
   RecvPBackgroundLSRequestConstructor(PBackgroundLSRequestParent* aActor,
                                       const LSRequestParams& aParams) override;
 
   virtual bool
   DeallocPBackgroundLSRequestParent(PBackgroundLSRequestParent* aActor)
                                     override;
 
+  virtual PBackgroundLSSimpleRequestParent*
+  AllocPBackgroundLSSimpleRequestParent(const LSSimpleRequestParams& aParams)
+                                        override;
+
+  virtual mozilla::ipc::IPCResult
+  RecvPBackgroundLSSimpleRequestConstructor(
+                                       PBackgroundLSSimpleRequestParent* aActor,
+                                       const LSSimpleRequestParams& aParams)
+                                       override;
+
+  virtual bool
+  DeallocPBackgroundLSSimpleRequestParent(
+                                       PBackgroundLSSimpleRequestParent* aActor)
+                                       override;
+
   virtual PBackgroundLocalStorageCacheParent*
   AllocPBackgroundLocalStorageCacheParent(const PrincipalInfo& aPrincipalInfo,
                                           const nsCString& aOriginKey,
                                           const uint32_t& aPrivateBrowsingId)
                                           override;
 
   virtual mozilla::ipc::IPCResult
   RecvPBackgroundLocalStorageCacheConstructor(
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -4,16 +4,17 @@
 
 include protocol PAsmJSCacheEntry;
 include protocol PBackgroundIDBFactory;
 include protocol PBackgroundIndexedDBUtils;
 include protocol PBackgroundSDBConnection;
 include protocol PBackgroundLSObject;
 include protocol PBackgroundLSObserver;
 include protocol PBackgroundLSRequest;
+include protocol PBackgroundLSSimpleRequest;
 include protocol PBackgroundLocalStorageCache;
 include protocol PBackgroundStorage;
 include protocol PBackgroundTest;
 include protocol PBroadcastChannel;
 include protocol PCache;
 include protocol PCacheStorage;
 include protocol PCacheStreamControl;
 include protocol PClientManager;
@@ -74,16 +75,17 @@ sync protocol PBackground
 {
   manages PAsmJSCacheEntry;
   manages PBackgroundIDBFactory;
   manages PBackgroundIndexedDBUtils;
   manages PBackgroundSDBConnection;
   manages PBackgroundLSObject;
   manages PBackgroundLSObserver;
   manages PBackgroundLSRequest;
+  manages PBackgroundLSSimpleRequest;
   manages PBackgroundLocalStorageCache;
   manages PBackgroundStorage;
   manages PBackgroundTest;
   manages PBroadcastChannel;
   manages PCache;
   manages PCacheStorage;
   manages PCacheStreamControl;
   manages PClientManager;
@@ -129,16 +131,18 @@ parent:
   async PBackgroundLSObject(PrincipalInfo principalInfo,
                             nsString documentURI,
                             uint32_t privateBrowsingId);
 
   async PBackgroundLSObserver(uint64_t observerId);
 
   async PBackgroundLSRequest(LSRequestParams params);
 
+  async PBackgroundLSSimpleRequest(LSSimpleRequestParams params);
+
   async PBackgroundLocalStorageCache(PrincipalInfo principalInfo,
                                      nsCString originKey,
                                      uint32_t privateBrowsingId);
 
   async PBackgroundStorage(nsString profilePath);
 
   async PVsync();