Bug 957086 - patch 3 - DataStoreService in C++ OOP, r=janv
☠☠ backed out by ea7edac9664a ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 29 May 2014 16:35:03 +0100
changeset 204846 083b9fb75e9a8fff9eab3dddfed568a88d4a2bcf
parent 204845 4cbc8cf0b6199852d1a303acbcb55a9992e0a89c
child 204847 9d0c1f1037e37465eeafb4466fb3ad2973b1755b
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanv
bugs957086
milestone32.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 957086 - patch 3 - DataStoreService in C++ OOP, r=janv
dom/datastore/DataStoreChangeNotifier.jsm
dom/datastore/DataStoreDB.cpp
dom/datastore/DataStoreRevision.h
dom/datastore/DataStoreService.cpp
dom/datastore/DataStoreService.h
dom/datastore/DataStoreServiceInternal.jsm
dom/datastore/moz.build
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
--- a/dom/datastore/DataStoreChangeNotifier.jsm
+++ b/dom/datastore/DataStoreChangeNotifier.jsm
@@ -7,19 +7,16 @@
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 this.EXPORTED_SYMBOLS = ["DataStoreChangeNotifier"];
 
 function debug(s) {
   //dump('DEBUG DataStoreChangeNotifier: ' + s + '\n');
 }
 
-// DataStoreServiceInternal should not be converted into a lazy getter as it
-// runs code during initialization.
-Cu.import('resource://gre/modules/DataStoreServiceInternal.jsm');
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageBroadcaster");
 
 this.DataStoreChangeNotifier = {
--- a/dom/datastore/DataStoreDB.cpp
+++ b/dom/datastore/DataStoreDB.cpp
@@ -139,42 +139,42 @@ DataStoreDB::UpgradeSchema()
   IDBDatabase* database = nullptr;
   nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
   if (NS_FAILED(rv)) {
     NS_WARNING("Didn't get the object we expected!");
     return rv;
   }
 
   {
-    IDBObjectStoreParameters params;
+    RootedDictionary<IDBObjectStoreParameters> params(cx);
     params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true }"));
     nsRefPtr<IDBObjectStore> store =
       database->CreateObjectStore(cx, NS_LITERAL_STRING(DATASTOREDB_NAME),
                                   params, error);
     if (NS_WARN_IF(error.Failed())) {
       return error.ErrorCode();
     }
   }
 
   nsRefPtr<IDBObjectStore> store;
 
   {
-    IDBObjectStoreParameters params;
+    RootedDictionary<IDBObjectStoreParameters> params(cx);
     params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true, \"keyPath\": \"internalRevisionId\" }"));
 
     store =
       database->CreateObjectStore(cx, NS_LITERAL_STRING(DATASTOREDB_REVISION),
                                   params, error);
     if (NS_WARN_IF(error.Failed())) {
       return error.ErrorCode();
     }
   }
 
   {
-    IDBIndexParameters params;
+    RootedDictionary<IDBIndexParameters> params(cx);
     params.Init(NS_LITERAL_STRING("{ \"unique\": true }"));
     nsRefPtr<IDBIndex> index =
       store->CreateIndex(cx, NS_LITERAL_STRING(DATASTOREDB_REVISION_INDEX),
                          NS_LITERAL_STRING("revisionId"), params, error);
     if (NS_WARN_IF(error.Failed())) {
       return error.ErrorCode();
     }
   }
--- a/dom/datastore/DataStoreRevision.h
+++ b/dom/datastore/DataStoreRevision.h
@@ -2,20 +2,20 @@
 /* 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/. */
 
 #ifndef mozilla_dom_DataStoreRevision_h
 #define mozilla_dom_DataStoreRevision_h
 
-#include "nsIDOMEventListener.h"
+#include "jsapi.h"
 #include "nsAutoPtr.h"
+#include "nsIDOMEventListener.h"
 #include "nsString.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace indexedDB {
 class IDBObjectStore;
 class IDBRequest;
 }
--- a/dom/datastore/DataStoreService.cpp
+++ b/dom/datastore/DataStoreService.cpp
@@ -5,27 +5,31 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DataStoreService.h"
 
 #include "DataStoreCallbacks.h"
 #include "DataStoreDB.h"
 #include "DataStoreRevision.h"
 #include "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/DataStoreImplBinding.h"
 #include "nsIDataStore.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMError.h"
-#include "mozilla/dom/Promise.h"
 #include "mozilla/dom/indexedDB/IDBCursor.h"
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
-#include "mozilla/dom/DataStoreBinding.h"
-#include "mozilla/dom/DataStoreImplBinding.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/unused.h"
 
 #include "mozIApplication.h"
 #include "mozIApplicationClearPrivateDataParams.h"
 #include "nsIAppsService.h"
 #include "nsIDOMEvent.h"
 #include "nsIDocument.h"
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsIIOService.h"
@@ -39,40 +43,55 @@
 #include "nsContentUtils.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 #define ASSERT_PARENT_PROCESS()                                             \
   AssertIsInMainProcess();                                                  \
-  if (NS_WARN_IF(XRE_GetProcessType() != GeckoProcessType_Default)) {       \
+  if (NS_WARN_IF(!IsMainProcess())) {                                       \
     return NS_ERROR_FAILURE;                                                \
   }
 
 namespace mozilla {
 namespace dom {
 
 using namespace indexedDB;
 
 // This class contains all the information about a DataStore.
 class DataStoreInfo
 {
 public:
+  DataStoreInfo()
+    : mReadOnly(true)
+    , mEnabled(false)
+  {}
+
   DataStoreInfo(const nsAString& aName,
                 const nsAString& aOriginURL,
                 const nsAString& aManifestURL,
                 bool aReadOnly,
                 bool aEnabled)
-    : mName(aName)
-    , mOriginURL(aOriginURL)
-    , mManifestURL(aManifestURL)
-    , mReadOnly(aReadOnly)
-    , mEnabled(aEnabled)
-  {}
+  {
+    Init(aName, aOriginURL, aManifestURL, aReadOnly, aEnabled);
+  }
+
+  void Init(const nsAString& aName,
+            const nsAString& aOriginURL,
+            const nsAString& aManifestURL,
+            bool aReadOnly,
+            bool aEnabled)
+  {
+    mName = aName;
+    mOriginURL = aOriginURL;
+    mManifestURL = aManifestURL;
+    mReadOnly = aReadOnly;
+    mEnabled = aEnabled;
+  }
 
   void Update(const nsAString& aName,
               const nsAString& aOriginURL,
               const nsAString& aManifestURL,
               bool aReadOnly)
   {
     mName = aName;
     mOriginURL = aOriginURL;
@@ -336,20 +355,20 @@ GetDataStoreInfosEnumerator(const uint32
   }
 
   DataStoreInfo* accessInfo = nullptr;
   if (!apps->Get(data->mAppId, &accessInfo)) {
     return PL_DHASH_NEXT;
   }
 
   bool readOnly = aInfo->mReadOnly || accessInfo->mReadOnly;
-  DataStoreInfo accessStore(aInfo->mName, aInfo->mOriginURL,
-                            aInfo->mManifestURL, readOnly,
-                            aInfo->mEnabled);
-  data->mStores.AppendElement(accessStore);
+  DataStoreInfo* accessStore = data->mStores.AppendElement();
+  accessStore->Init(aInfo->mName, aInfo->mOriginURL,
+                    aInfo->mManifestURL, readOnly,
+                    aInfo->mEnabled);
 
   return PL_DHASH_NEXT;
 }
 
 // This class is useful to enumerate the add permissions for each app.
 class MOZ_STACK_CLASS AddPermissionsData
 {
 public:
@@ -423,25 +442,24 @@ AddAccessPermissionsEnumerator(const uin
 
 } /* anonymous namespace */
 
 // A PendingRequest is created when a content code wants a list of DataStores
 // but some of them are not enabled yet.
 class PendingRequest
 {
 public:
-  PendingRequest(nsPIDOMWindow* aWindow,
-                 Promise* aPromise,
-                 const nsTArray<DataStoreInfo>& aStores,
-                 const nsTArray<nsString>& aPendingDataStores)
-    : mWindow(aWindow)
-    , mPromise(aPromise)
-    , mStores(aStores)
-    , mPendingDataStores(aPendingDataStores)
+  void Init(nsPIDOMWindow* aWindow, Promise* aPromise,
+            const nsTArray<DataStoreInfo>& aStores,
+            const nsTArray<nsString>& aPendingDataStores)
   {
+    mWindow = aWindow;
+    mPromise = aPromise;
+    mStores = aStores;
+    mPendingDataStores = aPendingDataStores;
   }
 
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsRefPtr<Promise> mPromise;
   nsTArray<DataStoreInfo> mStores;
 
   // This array contains the list of manifestURLs of the DataStores that are
   // not enabled yet.
@@ -851,61 +869,74 @@ DataStoreService::GetDataStores(nsIDOMWi
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
   if (!window) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
   nsRefPtr<Promise> promise = new Promise(global);
 
+  nsCOMPtr<nsIDocument> document = window->GetDoc();
+  MOZ_ASSERT(document);
+
+  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
+  MOZ_ASSERT(principal);
+
+  nsTArray<DataStoreInfo> stores;
+
   // If this request comes from the main process, we have access to the
   // window, so we can skip the ipc communication.
   if (IsMainProcess()) {
-    nsCOMPtr<nsIDocument> document = window->GetDoc();
-    MOZ_ASSERT(document);
-
-    nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
-    MOZ_ASSERT(principal);
-
     uint32_t appId;
     nsresult rv = principal->GetAppId(&appId);
     if (NS_FAILED(rv)) {
       RejectPromise(window, promise, rv);
       promise.forget(aDataStores);
       return NS_OK;
     }
 
-    nsTArray<DataStoreInfo> stores;
     rv = GetDataStoreInfos(aName, appId, stores);
     if (NS_FAILED(rv)) {
       RejectPromise(window, promise, rv);
       promise.forget(aDataStores);
       return NS_OK;
     }
-
-    GetDataStoresCreate(window, promise, stores);
-    promise.forget(aDataStores);
-    return NS_OK;
   }
 
   else {
     // This method can be called in the child so we need to send a request
     // to the parent and create DataStore object here.
-    // TODO
+    ContentChild* contentChild = ContentChild::GetSingleton();
+
+    nsTArray<DataStoreSetting> array;
+    if (!contentChild->SendDataStoreGetStores(nsAutoString(aName),
+                                              IPC::Principal(principal),
+                                              &array)) {
+      RejectPromise(window, promise, NS_ERROR_FAILURE);
+      promise.forget(aDataStores);
+      return NS_OK;
+    }
+
+    for (uint32_t i = 0; i < array.Length(); ++i) {
+      DataStoreInfo* info = stores.AppendElement();
+      info->Init(array[i].name(), array[i].originURL(),
+                 array[i].manifestURL(), array[i].readOnly(),
+                 array[i].enabled());
+    }
   }
 
+  GetDataStoresCreate(window, promise, stores);
   promise.forget(aDataStores);
   return NS_OK;
 }
 
 void
 DataStoreService::GetDataStoresCreate(nsPIDOMWindow* aWindow, Promise* aPromise,
                                       const nsTArray<DataStoreInfo>& aStores)
 {
-  AssertIsInMainProcess();
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!aStores.Length()) {
     GetDataStoresResolve(aWindow, aPromise, aStores);
     return;
   }
 
   nsTArray<nsString> pendingDataStores;
@@ -921,26 +952,25 @@ DataStoreService::GetDataStoresCreate(ns
   }
 
   PendingRequests* requests;
   if (!mPendingRequests.Get(aStores[0].mName, &requests)) {
     requests = new PendingRequests();
     mPendingRequests.Put(aStores[0].mName, requests);
   }
 
-  PendingRequest request(aWindow, aPromise, aStores, pendingDataStores);
-  requests->AppendElement(request);
+  PendingRequest* request = requests->AppendElement();
+  request->Init(aWindow, aPromise, aStores, pendingDataStores);
 }
 
 void
 DataStoreService::GetDataStoresResolve(nsPIDOMWindow* aWindow,
                                        Promise* aPromise,
                                        const nsTArray<DataStoreInfo>& aStores)
 {
-  AssertIsInMainProcess();
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!aStores.Length()) {
     nsTArray<nsRefPtr<DataStore>> results;
     aPromise->MaybeResolve(results);
     return;
   }
 
@@ -1040,19 +1070,19 @@ DataStoreService::GetDataStoreInfos(cons
 
   HashApp* apps = nullptr;
   if (!mStores.Get(aName, &apps)) {
     return NS_OK;
   }
 
   DataStoreInfo* info = nullptr;
   if (apps->Get(aAppId, &info)) {
-    DataStoreInfo owned(info->mName, info->mOriginURL, info->mManifestURL,
-                        false, info->mEnabled);
-    aStores.AppendElement(owned);
+    DataStoreInfo* owned = aStores.AppendElement();
+    owned->Init(info->mName, info->mOriginURL, info->mManifestURL, false,
+                info->mEnabled);
   }
 
   GetDataStoreInfosData data(mAccessStores, aName, aAppId, aStores);
   apps->EnumerateRead(GetDataStoreInfosEnumerator, &data);
   return NS_OK;
 }
 
 // This method is called when an app with DataStores is deleted.
@@ -1190,16 +1220,28 @@ DataStoreService::EnableDataStore(uint32
   {
     HashApp* apps = nullptr;
     DataStoreInfo* info = nullptr;
     if (mStores.Get(aName, &apps) && apps->Get(aAppId, &info)) {
       info->Enable();
     }
   }
 
+  // Notify the child processes.
+  if (IsMainProcess()) {
+    nsTArray<ContentParent*> children;
+    ContentParent::GetAll(children);
+    for (uint32_t i = 0; i < children.Length(); i++) {
+      if (children[i]->NeedsDataStoreInfos()) {
+        unused << children[i]->SendDataStoreNotify(aAppId, nsAutoString(aName),
+                                                   nsAutoString(aManifestURL));
+      }
+    }
+  }
+
   // Maybe we have some pending request waiting for this DataStore.
   PendingRequests* requests;
   if (!mPendingRequests.Get(aName, &requests)) {
     return NS_OK;
   }
 
   for (uint32_t i = 0; i < requests->Length();) {
     PendingRequest& request = requests->ElementAt(i);
@@ -1226,31 +1268,60 @@ DataStoreService::EnableDataStore(uint32
   }
 
   return NS_OK;
 }
 
 already_AddRefed<RetrieveRevisionsCounter>
 DataStoreService::GetCounter(uint32_t aId) const
 {
-  AssertIsInMainProcess();
   MOZ_ASSERT(NS_IsMainThread());
 
   nsRefPtr<RetrieveRevisionsCounter> counter;
   return mPendingCounters.Get(aId, getter_AddRefs(counter))
            ? counter.forget() : nullptr;
 }
 
 void
 DataStoreService::RemoveCounter(uint32_t aId)
 {
-  AssertIsInMainProcess();
+  MOZ_ASSERT(NS_IsMainThread());
+  mPendingCounters.Remove(aId);
+}
+
+nsresult
+DataStoreService::GetDataStoresFromIPC(const nsAString& aName,
+                                       nsIPrincipal* aPrincipal,
+                                       nsTArray<DataStoreSetting>* aValue)
+{
+  MOZ_ASSERT(IsMainProcess());
   MOZ_ASSERT(NS_IsMainThread());
 
-  mPendingCounters.Remove(aId);
+  uint32_t appId;
+  nsresult rv = aPrincipal->GetAppId(&appId);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsTArray<DataStoreInfo> stores;
+  rv = GetDataStoreInfos(aName, appId, stores);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  for (uint32_t i = 0; i < stores.Length(); ++i) {
+    DataStoreSetting* data = aValue->AppendElement();
+    data->name() = stores[i].mName;
+    data->originURL() = stores[i].mOriginURL;
+    data->manifestURL() = stores[i].mManifestURL;
+    data->readOnly() = stores[i].mReadOnly;
+    data->enabled() = stores[i].mEnabled;
+  }
+
+  return NS_OK;
 }
 
 nsresult
 DataStoreService::GenerateUUID(nsAString& aID)
 {
   nsresult rv;
 
   if (!mUUIDGenerator) {
--- a/dom/datastore/DataStoreService.h
+++ b/dom/datastore/DataStoreService.h
@@ -2,37 +2,40 @@
 /* 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/. */
 
 #ifndef mozilla_dom_DataStoreService_h
 #define mozilla_dom_DataStoreService_h
 
+#include "mozilla/dom/PContent.h"
 #include "nsClassHashtable.h"
 #include "nsIDataStoreService.h"
 #include "nsIObserver.h"
 #include "nsRefPtrHashtable.h"
 
+class nsIPrincipal;
 class nsIUUIDGenerator;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class DataStoreInfo;
 class FirstRevisionIdCallback;
 class PendingRequest;
 class Promise;
 class RetrieveRevisionsCounter;
 class RevisionAddedEnableStoreCallback;
 
 class DataStoreService MOZ_FINAL : public nsIDataStoreService
                                  , public nsIObserver
 {
+  friend class ContentChild;
   friend class FirstRevisionIdCallback;
   friend class RetrieveRevisionsCounter;
   friend class RevisionAddedEnableStoreCallback;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIDATASTORESERVICE
@@ -42,16 +45,20 @@ public:
   static already_AddRefed<DataStoreService> GetOrCreate();
 
   static already_AddRefed<DataStoreService> Get();
 
   static void Shutdown();
 
   nsresult GenerateUUID(nsAString& aID);
 
+  nsresult GetDataStoresFromIPC(const nsAString& aName,
+                                nsIPrincipal* aPrincipal,
+                                nsTArray<DataStoreSetting>* aValue);
+
 private:
   DataStoreService();
   ~DataStoreService();
 
   nsresult Init();
 
   typedef nsClassHashtable<nsUint32HashKey, DataStoreInfo> HashApp;
 
deleted file mode 100644
--- a/dom/datastore/DataStoreServiceInternal.jsm
+++ /dev/null
@@ -1,68 +0,0 @@
-/* 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/. */
-
-"use strict"
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-this.EXPORTED_SYMBOLS = ["DataStoreServiceInternal"];
-
-function debug(s) {
-  //dump('DEBUG DataStoreServiceInternal: ' + s + '\n');
-}
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
-                                   "@mozilla.org/parentprocessmessagemanager;1",
-                                   "nsIMessageBroadcaster");
-
-XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
-                                   "@mozilla.org/datastore-service;1",
-                                   "nsIDataStoreService");
-
-this.DataStoreServiceInternal = {
-  init: function() {
-    debug("init");
-
-    let inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
-                      .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-    if (inParent) {
-      ppmm.addMessageListener("DataStore:Get", this);
-    }
-  },
-
-  receiveMessage: function(aMessage) {
-    debug("receiveMessage");
-
-    if (aMessage.name != 'DataStore:Get') {
-      return;
-    }
-
-    let prefName = 'dom.testing.datastore_enabled_for_hosted_apps';
-    if ((Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
-         !Services.prefs.getBoolPref(prefName)) &&
-        !aMessage.target.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) {
-      return;
-    }
-
-    let msg = aMessage.data;
-
-    if (!aMessage.principal ||
-        aMessage.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
-      aMessage.target.sendAsyncMessage("DataStore:Get:Return:KO");
-      return;
-    }
-
-    msg.stores = dataStoreService.getDataStoresInfo(msg.name, aMessage.principal.appId);
-    if (msg.stores === null) {
-      aMessage.target.sendAsyncMessage("DataStore:Get:Return:KO");
-      return;
-    }
-    aMessage.target.sendAsyncMessage("DataStore:Get:Return:OK", msg);
-  }
-}
-
-DataStoreServiceInternal.init();
--- a/dom/datastore/moz.build
+++ b/dom/datastore/moz.build
@@ -33,17 +33,16 @@ EXTRA_COMPONENTS += [
     'DataStore.manifest',
     'DataStoreImpl.js',
 ]
 
 EXTRA_JS_MODULES += [
     'DataStoreChangeNotifier.jsm',
     'DataStoreCursorImpl.jsm',
     'DataStoreDB.jsm',
-    'DataStoreServiceInternal.jsm',
 ]
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 FAIL_ON_WARNINGS = True
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -137,16 +137,17 @@
 #include "ProcessUtils.h"
 #include "StructuredCloneUtils.h"
 #include "URIUtils.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
 #include "AudioChannelService.h"
 #include "JavaScriptChild.h"
+#include "mozilla/dom/DataStoreService.h"
 #include "mozilla/dom/telephony/PTelephonyChild.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 
 using namespace base;
 using namespace mozilla;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
@@ -764,16 +765,34 @@ ContentChild::RecvAudioChannelNotify()
         AudioChannelService::GetAudioChannelService();
     if (service) {
         service->Notify();
     }
     return true;
 }
 
 bool
+ContentChild::RecvDataStoreNotify(const uint32_t& aAppId,
+                                  const nsString& aName,
+                                  const nsString& aManifestURL)
+{
+  nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
+  if (NS_WARN_IF(!service)) {
+    return false;
+  }
+
+  nsresult rv = service->EnableDataStore(aAppId, aName, aManifestURL);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  return true;
+}
+
+bool
 ContentChild::DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor)
 {
     static_cast<MemoryReportRequestChild*>(actor)->Release();
     return true;
 }
 
 PCycleCollectWithLogsChild*
 ContentChild::AllocPCycleCollectWithLogsChild(const bool& aDumpAllTraces,
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -152,16 +152,20 @@ public:
     RecvPCycleCollectWithLogsConstructor(PCycleCollectWithLogsChild* aChild,
                                          const bool& aDumpAllTraces,
                                          const FileDescriptor& aGCLog,
                                          const FileDescriptor& aCCLog) MOZ_OVERRIDE;
 
     virtual bool
     RecvAudioChannelNotify() MOZ_OVERRIDE;
 
+    virtual bool
+    RecvDataStoreNotify(const uint32_t& aAppId, const nsString& aName,
+                        const nsString& aManifestURL) MOZ_OVERRIDE;
+
     virtual PTestShellChild* AllocPTestShellChild() MOZ_OVERRIDE;
     virtual bool DeallocPTestShellChild(PTestShellChild*) MOZ_OVERRIDE;
     virtual bool RecvPTestShellConstructor(PTestShellChild*) MOZ_OVERRIDE;
     jsipc::JavaScriptChild *GetCPOWManager();
 
     virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE;
     virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -28,16 +28,17 @@
 #include "IHistory.h"
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "IndexedDatabaseManager.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/DataStoreService.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/PFileDescriptorSetParent.h"
 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/PFMRadioParent.h"
@@ -1490,16 +1491,17 @@ ContentParent::InitializeMembers()
 {
     mSubprocess = nullptr;
     mChildID = gContentChildID++;
     mGeolocationWatchID = -1;
     mForceKillTask = nullptr;
     mNumDestroyingTabs = 0;
     mIsAlive = true;
     mSendPermissionUpdates = false;
+    mSendDataStoreInfos = false;
     mCalledClose = false;
     mCalledCloseWithError = false;
     mCalledKillHard = false;
 }
 
 ContentParent::ContentParent(mozIApplication* aApp,
                              bool aIsForBrowser,
                              bool aIsForPreallocated,
@@ -2072,16 +2074,36 @@ ContentParent::RecvAudioChannelChangeDef
     if (service) {
        service->SetDefaultVolumeControlChannelInternal(aChannel,
                                                        aHidden, mChildID);
     }
     return true;
 }
 
 bool
+ContentParent::RecvDataStoreGetStores(
+                                    const nsString& aName,
+                                    const IPC::Principal& aPrincipal,
+                                    InfallibleTArray<DataStoreSetting>* aValue)
+{
+  nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
+  if (NS_WARN_IF(!service)) {
+    return false;
+  }
+
+  nsresult rv = service->GetDataStoresFromIPC(aName, aPrincipal, aValue);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  mSendDataStoreInfos = true;
+  return true;
+}
+
+bool
 ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
 {
 #ifdef MOZ_WIDGET_GONK
     nsresult rv;
     nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
     if (vs) {
         vs->BroadcastVolume(aVolumeName);
     }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -155,20 +155,24 @@ public:
 #endif
 
     GeckoChildProcessHost* Process() {
         return mSubprocess;
     }
 
     int32_t Pid();
 
-    bool NeedsPermissionsUpdate() {
+    bool NeedsPermissionsUpdate() const {
         return mSendPermissionUpdates;
     }
 
+    bool NeedsDataStoreInfos() const {
+        return mSendDataStoreInfos;
+    }
+
     BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
 
     /**
      * Kill our subprocess and make sure it dies.  Should only be used
      * in emergency situations since it bypasses the normal shutdown
      * process.
      */
     void KillHard();
@@ -521,16 +525,21 @@ private:
 
     virtual bool RecvAudioChannelChangedNotification() MOZ_OVERRIDE;
 
     virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
                                                      const bool& aHidden) MOZ_OVERRIDE;
     virtual bool RecvGetSystemMemory(const uint64_t& getterId) MOZ_OVERRIDE;
     virtual bool RecvBroadcastVolume(const nsString& aVolumeName) MOZ_OVERRIDE;
 
+    virtual bool RecvDataStoreGetStores(
+                       const nsString& aName,
+                       const IPC::Principal& aPrincipal,
+                       InfallibleTArray<DataStoreSetting>* aValue) MOZ_OVERRIDE;
+
     virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) MOZ_OVERRIDE;
 
     virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable) MOZ_OVERRIDE;
 
     virtual bool RecvSystemMessageHandled() MOZ_OVERRIDE;
 
     virtual bool RecvNuwaReady() MOZ_OVERRIDE;
 
@@ -595,16 +604,17 @@ private:
     int32_t mNumDestroyingTabs;
     // True only while this is ready to be used to host remote tabs.
     // This must not be used for new purposes after mIsAlive goes to
     // false, but some previously scheduled IPC traffic may still pass
     // through.
     bool mIsAlive;
 
     bool mSendPermissionUpdates;
+    bool mSendDataStoreInfos;
     bool mIsForBrowser;
     bool mIsNuwaProcess;
 
     // These variables track whether we've called Close(), CloseWithError()
     // and KillHard() on our channel.
     bool mCalledClose;
     bool mCalledCloseWithError;
     bool mCalledKillHard;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -257,16 +257,24 @@ union MaybePrefValue {
 };
 
 struct PrefSetting {
   nsCString name;
   MaybePrefValue defaultValue;
   MaybePrefValue userValue;
 };
 
+struct DataStoreSetting {
+  nsString name;
+  nsString originURL;
+  nsString manifestURL;
+  bool readOnly;
+  bool enabled;
+};
+
 intr protocol PContent
 {
     parent opens PCompositor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     child opens PBackground;
 
     manages PAsmJSCacheEntry;
@@ -333,16 +341,19 @@ child:
 
     /**
      * Notify the AudioChannelService in the child processes.
      */
     async AudioChannelNotify();
 
     async SpeakerManagerNotify();
 
+    async DataStoreNotify(uint32_t aAppId, nsString aName,
+                          nsString aManifestURL);
+
     /**
      * Dump this process's GC and CC logs to the provided files.
      *
      * For documentation on the other args, see dumpGCAndCCLogsToFile in
      * nsIMemoryInfoDumper.idl
      */
     PCycleCollectWithLogs(bool dumpAllTraces,
                           FileDescriptor gcLog,
@@ -545,16 +556,19 @@ parent:
     sync AudioChannelRegisterType(AudioChannel aChannel, bool aWithVideo);
     sync AudioChannelUnregisterType(AudioChannel aChannel,
                                     bool aElementHidden,
                                     bool aWithVideo);
 
     async AudioChannelChangedNotification();
     async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
 
+    sync DataStoreGetStores(nsString aName, Principal aPrincipal)
+        returns (DataStoreSetting[] dataStores);
+
     async FilePathUpdateNotify(nsString aType,
                                nsString aStorageName,
                                nsString aFilepath,
                                nsCString aReason);
     // get nsIVolumeService to broadcast volume information
     async BroadcastVolume(nsString volumeName);
 
     // Notify the parent that the child has finished handling a system message.