Bug 1343731 - Remove the sync IPC during DataStorage initialization; r=keeler,billm
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 25 Feb 2017 11:14:04 -0500
changeset 347200 bf33ec027cea3933857e578f37e2e577f0cb1e85
parent 347199 966b6ec41dfcbf2bdaa1d74ce24d6ebae8e643ed
child 347201 c1978f7d49c440ad6831e84e6808b64400af4a40
push id31491
push usercbook@mozilla.com
push dateMon, 13 Mar 2017 14:24:00 +0000
treeherdermozilla-central@8d9fd089cabd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler, billm
bugs1343731, 1215723
milestone55.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 1343731 - Remove the sync IPC during DataStorage initialization; r=keeler,billm Instead of initializing DataStorage objects on demand in the content process, we initialize them at content process startup by getting the parent to send down the information about the existing DataStorages at child process startup. After that point, the dynamic change notifications added in bug 1215723 will take care of keeping the information in sync.
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
ipc/ipdl/sync-messages.ini
security/manager/ssl/DataStorage.cpp
security/manager/ssl/DataStorage.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1023,16 +1023,18 @@ ContentChild::InitXPCOM(const XPCOMInitD
   // The stylesheet cache is not ready yet. Store this URL for future use.
   nsCOMPtr<nsIURI> ucsURL = DeserializeURI(aXPCOMInit.userContentSheetURL());
   nsLayoutStylesheetCache::SetUserContentCSSURL(ucsURL);
 
   // This will register cross-process observer.
   mozilla::dom::time::InitializeDateCacheCleaner();
 
   GfxInfoBase::SetFeatureStatus(aXPCOMInit.gfxFeatureStatus());
+
+  DataStorage::SetCachedStorageEntries(aXPCOMInit.dataStorage());
 }
 
 mozilla::ipc::IPCResult
 ContentChild::RecvRequestMemoryReport(const uint32_t& aGeneration,
                                       const bool& aAnonymize,
                                       const bool& aMinimizeMemoryUsage,
                                       const MaybeFileDesc& aDMDFile)
 {
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2198,16 +2198,29 @@ ContentParent::InitInternal(ProcessPrior
       dom::GfxInfoFeatureStatus gfxFeatureStatus;
       gfxFeatureStatus.feature() = i;
       gfxFeatureStatus.status() = status;
       gfxFeatureStatus.failureId() = failureId;
       xpcomInit.gfxFeatureStatus().AppendElement(gfxFeatureStatus);
     }
   }
 
+  // Ensure the SSS is initialized before we try to use its storage.
+  nsCOMPtr<nsISiteSecurityService> sss = do_GetService("@mozilla.org/ssservice;1");
+
+  nsTArray<nsString> storageFiles;
+  DataStorage::GetAllFileNames(storageFiles);
+  for (auto& file : storageFiles) {
+    dom::DataStorageEntry entry;
+    entry.filename() = file;
+    RefPtr<DataStorage> storage = DataStorage::Get(file);
+    storage->GetAll(&entry.items());
+    xpcomInit.dataStorage().AppendElement(Move(entry));
+  }
+
   Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache);
 
   if (aSendRegisteredChrome) {
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryChrome* chromeRegistry =
       static_cast<nsChromeRegistryChrome*>(registrySvc.get());
     chromeRegistry->SendRegisteredChrome(this);
   }
@@ -2436,34 +2449,16 @@ ContentParent::RecvReadFontList(Infallib
 {
 #ifdef ANDROID
   gfxAndroidPlatform::GetPlatform()->GetSystemFontList(retValue);
 #endif
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvReadDataStorageArray(const nsString& aFilename,
-                                        InfallibleTArray<DataStorageItem>* aValues)
-{
-  // If we're shutting down, the DataStorage object may have been cleared
-  // already, and setting it up is pointless anyways since we're about to die.
-  if (mShutdownPending) {
-    return IPC_OK();
-  }
-
-  // Ensure the SSS is initialized before we try to use its storage.
-  nsCOMPtr<nsISiteSecurityService> sss = do_GetService("@mozilla.org/ssservice;1");
-
-  RefPtr<DataStorage> storage = DataStorage::Get(aFilename);
-  storage->GetAll(aValues);
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
 {
 #ifdef MOZ_PERMISSIONS
   nsCOMPtr<nsIPermissionManager> permissionManagerIface =
     services::GetPermissionManager();
   nsPermissionManager* permissionManager =
     static_cast<nsPermissionManager*>(permissionManagerIface.get());
   MOZ_ASSERT(permissionManager,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -893,19 +893,16 @@ private:
 
   virtual bool
   DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor) override;
 
   virtual mozilla::ipc::IPCResult RecvGetGfxVars(InfallibleTArray<GfxVarUpdate>* aVars) override;
 
   virtual mozilla::ipc::IPCResult RecvReadFontList(InfallibleTArray<FontListEntry>* retValue) override;
 
-  virtual mozilla::ipc::IPCResult RecvReadDataStorageArray(const nsString& aFilename,
-                                                           InfallibleTArray<DataStorageItem>* aValues) override;
-
   virtual mozilla::ipc::IPCResult RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions) override;
 
   virtual mozilla::ipc::IPCResult RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
                                                    const bool& aIsPrivateData,
                                                    const IPC::Principal& aRequestingPrincipal,
                                                    const int32_t& aWhichClipboard) override;
 
   virtual mozilla::ipc::IPCResult RecvGetClipboard(nsTArray<nsCString>&& aTypes,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -141,16 +141,21 @@ struct PrefSetting {
 };
 
 struct DataStorageItem {
   nsCString key;
   nsCString value;
   DataStorageType type;
 };
 
+struct DataStorageEntry {
+  DataStorageItem[] items;
+  nsString filename;
+};
+
 struct ClipboardCapabilities {
   bool supportsSelectionClipboard;
   bool supportsFindClipboard;
 };
 
 union FileDescOrError {
     FileDescriptor;
     nsresult;
@@ -252,16 +257,17 @@ struct XPCOMInitData
     nsString[] dictionaries;
     ClipboardCapabilities clipboardCaps;
     DomainPolicyClone domainPolicy;
     /* used on MacOSX only */
     FontFamilyListEntry[] fontFamilies;
     OptionalURIParams userContentSheetURL;
     PrefSetting[] prefs;
     GfxInfoFeatureStatus[] gfxFeatureStatus;
+    DataStorageEntry[] dataStorage;
 };
 
 /**
  * The PContent protocol is a top-level protocol between the UI process
  * and a content process. There is exactly one PContentParent/PContentChild pair
  * for each content process.
  */
 nested(upto inside_cpow) sync protocol PContent
@@ -727,19 +733,16 @@ parent:
     async LoadURIExternal(URIParams uri, PBrowser windowContext);
     async ExtProtocolChannelConnectParent(uint32_t registrarId);
 
     // PrefService message
     sync GetGfxVars() returns (GfxVarUpdate[] vars);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
-    sync ReadDataStorageArray(nsString aFilename)
-      returns (DataStorageItem[] retValue);
-
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     nested(inside_sync) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
                                         CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -769,18 +769,16 @@ description =
 [PContent::PURLClassifier]
 description =
 [PContent::ClassifyLocal]
 description =
 [PContent::GetGfxVars]
 description =
 [PContent::ReadFontList]
 description =
-[PContent::ReadDataStorageArray]
-description =
 [PContent::ReadPermissions]
 description =
 [PContent::GetClipboard]
 description =
 [PContent::ClipboardHasType]
 description =
 [PContent::GetSystemColors]
 description =
--- a/security/manager/ssl/DataStorage.cpp
+++ b/security/manager/ssl/DataStorage.cpp
@@ -81,18 +81,46 @@ DataStorage::GetIfExists(const nsString&
   if (!sDataStorages) {
     sDataStorages = new DataStorages();
   }
   RefPtr<DataStorage> storage;
   sDataStorages->Get(aFilename, getter_AddRefs(storage));
   return storage.forget();
 }
 
+// static
+void
+DataStorage::GetAllFileNames(nsTArray<nsString>& aItems)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!sDataStorages) {
+    return;
+  }
+  for (auto iter = sDataStorages->Iter(); !iter.Done(); iter.Next()) {
+    aItems.AppendElement(iter.Key());
+  }
+}
+
+// static
+void
+DataStorage::SetCachedStorageEntries(
+  const InfallibleTArray<mozilla::dom::DataStorageEntry>& aEntries)
+{
+  MOZ_ASSERT(XRE_IsContentProcess());
+
+  for (auto& entry : aEntries) {
+    RefPtr<DataStorage> storage = DataStorage::Get(entry.filename());
+    bool dataWillPersist = false;
+    storage->Init(dataWillPersist, &entry.items());
+  }
+}
+
 nsresult
-DataStorage::Init(bool& aDataWillPersist)
+DataStorage::Init(bool& aDataWillPersist,
+                  const InfallibleTArray<mozilla::dom::DataStorageItem>* aItems)
 {
   // Don't access the observer service or preferences off the main thread.
   if (!NS_IsMainThread()) {
     MOZ_ASSERT_UNREACHABLE("DataStorage::Init called off main thread");
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
   MutexAutoLock lock(mMutex);
@@ -101,33 +129,35 @@ DataStorage::Init(bool& aDataWillPersist
   if (mInitCalled) {
     return NS_OK;
   }
 
   mInitCalled = true;
 
   nsresult rv;
   if (XRE_IsParentProcess()) {
+    MOZ_ASSERT(!aItems);
+
     rv = NS_NewNamedThread("DataStorage", getter_AddRefs(mWorkerThread));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     rv = AsyncReadData(aDataWillPersist, lock);
     if (NS_FAILED(rv)) {
       return rv;
     }
   } else {
-    // In the child process, we ask the parent process for the data.
+    // In the child process, we use the data passed to us by the parent process
+    // to initialize.
     MOZ_ASSERT(XRE_IsContentProcess());
+    MOZ_ASSERT(aItems);
+
     aDataWillPersist = false;
-    InfallibleTArray<DataStorageItem> items;
-    dom::ContentChild::GetSingleton()->
-        SendReadDataStorageArray(mFilename, &items);
-    for (auto& item : items) {
+    for (auto& item : *aItems) {
       Entry entry;
       entry.mValue = item.value();
       rv = PutInternal(item.key(), entry, item.type(), lock);
       if (NS_FAILED(rv)) {
         return rv;
       }
     }
     mReady = true;
--- a/security/manager/ssl/DataStorage.h
+++ b/security/manager/ssl/DataStorage.h
@@ -17,16 +17,17 @@
 #include "nsIThread.h"
 #include "nsITimer.h"
 #include "nsRefPtrHashtable.h"
 #include "nsString.h"
 
 namespace mozilla {
 
 namespace dom {
+class DataStorageEntry;
 class DataStorageItem;
 }
 
 /**
  * DataStorage is a threadsafe, generic, narrow string-based hash map that
  * persists data on disk and additionally handles temporary and private data.
  * However, if used in a context where there is no profile directory, data
  * will not be persisted.
@@ -96,35 +97,46 @@ public:
 
   // If there is a profile directory, there is or will eventually be a file
   // by the name specified by aFilename there.
   static already_AddRefed<DataStorage> Get(const nsString& aFilename);
   static already_AddRefed<DataStorage> GetIfExists(const nsString& aFilename);
 
   // Initializes the DataStorage. Must be called before using.
   // aDataWillPersist returns whether or not data can be persistently saved.
-  nsresult Init(/*out*/bool& aDataWillPersist);
+  // aItems is used in the content process to initialize a cache of the items
+  // received from the parent process over IPC. nullptr must be passed for the
+  // parent process.
+  nsresult Init(/*out*/bool& aDataWillPersist,
+                const InfallibleTArray<mozilla::dom::DataStorageItem>*
+                  aItems = nullptr);
   // Given a key and a type of data, returns a value. Returns an empty string if
   // the key is not present for that type of data. If Get is called before the
   // "data-storage-ready" event is observed, it will block. NB: It is not
   // currently possible to differentiate between missing data and data that is
   // the empty string.
   nsCString Get(const nsCString& aKey, DataStorageType aType);
   // Give a key, value, and type of data, adds an entry as appropriate.
   // Updates existing entries.
   nsresult Put(const nsCString& aKey, const nsCString& aValue,
                DataStorageType aType);
   // Given a key and type of data, removes an entry if present.
   void Remove(const nsCString& aKey, DataStorageType aType);
   // Removes all entries of all types of data.
   nsresult Clear();
 
+  // Read all file names that we know about.
+  static void GetAllFileNames(nsTArray<nsString>& aItems);
+
   // Read all of the data items.
   void GetAll(InfallibleTArray<DataStorageItem>* aItems);
 
+  // Set the cached copy of our DataStorage entries in the content process.
+  static void SetCachedStorageEntries(const InfallibleTArray<mozilla::dom::DataStorageEntry>& aEntries);
+
 private:
   explicit DataStorage(const nsString& aFilename);
   virtual ~DataStorage();
 
   class Writer;
   class Reader;
 
   class Entry