Bug 1596090 - avoid sending plugin content to every content process whenever a content process is created, r=handyman
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Sat, 16 Nov 2019 00:21:49 +0000
changeset 502305 74ac84aa60fd048101ff962b8441334a3770116a
parent 502304 df333402f12666918a136e961c4f0bb0c6ffc40a
child 502306 ee0fdf5558a849da1045f3fe3c9b6f7a6eb76859
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershandyman
bugs1596090
milestone72.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 1596090 - avoid sending plugin content to every content process whenever a content process is created, r=handyman Depends on D52845 Differential Revision: https://phabricator.services.mozilla.com/D52846
dom/ipc/ContentParent.cpp
dom/media/doctor/moz.build
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2724,17 +2724,17 @@ bool ContentParent::InitInternal(Process
     nsTArray<JSWindowActorInfo> infos;
     actorSvc->GetJSWindowActorInfos(infos);
     Unused << SendInitJSWindowActorInfos(infos);
   }
 
   // Start up nsPluginHost and run FindPlugins to cache the plugin list.
   // If this isn't our first content process, just send over cached list.
   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
-  pluginHost->SendPluginsToContent();
+  pluginHost->SendPluginsToContent(this);
   MaybeEnableRemoteInputEventQueue();
 
   return true;
 }
 
 bool ContentParent::IsAlive() const {
   return mLifecycleState == LifecycleState::ALIVE;
 }
--- a/dom/media/doctor/moz.build
+++ b/dom/media/doctor/moz.build
@@ -3,16 +3,19 @@
 # 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/.
 
 TEST_DIRS += [
     'gtest',
 ]
 
+# Needed for plugin IPC types required by nsPluginHost
+include('/ipc/chromium/chromium-config.mozbuild')
+
 EXPORTS += [
     'DDLogCategory.h',
     'DDLoggedTypeTraits.h',
     'DDLogObject.h',
     'DDLogValue.h',
     'DecoderDoctorDiagnostics.h',
     'DecoderDoctorLogger.h',
 ]
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -200,17 +200,17 @@ class BlocklistPromiseHandler final
         // it to re-create plugin tags, and in any case can cause re-entrancy
         // because it would do more async blocklist lookups. Just make sure
         // we write the blocklist info.
         PluginFinder::WritePluginInfo(host->mFlashOnly, host->mPlugins);
 
         // We update blocklist info in content processes asynchronously
         // by just sending a new plugin list to content.
         host->IncrementChromeEpoch();
-        host->SendPluginsToContent();
+        host->BroadcastPluginsToContent();
       }
 
       // Now notify observers that we're done updating plugin state.
       nsCOMPtr<nsIObserverService> obsService =
           mozilla::services::GetObserverService();
       if (obsService) {
         obsService->NotifyObservers(
             nullptr, "plugin-blocklist-updates-finished", nullptr);
@@ -465,17 +465,17 @@ nsresult nsPluginHost::ActuallyReloadPlu
   mPluginsLoaded = false;
 
   // load them again
   rv = LoadPlugins();
 
   if (XRE_IsParentProcess()) {
     // If the plugin list changed, update content. If the plugin list changed
     // for the content process, it will also reload plugins.
-    SendPluginsToContent();
+    BroadcastPluginsToContent();
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins End\n"));
 
   return rv;
 }
 
 #define NS_RETURN_UASTRING_SIZE 128
@@ -625,16 +625,18 @@ nsresult nsPluginHost::UnloadPlugins() {
 
   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mPlugins, mNext);
 
   // Lets remove any of the temporary files that we created.
   if (sPluginTempDir) {
     sPluginTempDir->Remove(true);
     NS_RELEASE(sPluginTempDir);
   }
+  mSerializablePlugins.Clear();
+  mSerializableFakePlugins.Clear();
 
   mPluginsLoaded = false;
 
   return NS_OK;
 }
 
 void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag) {
   bool hasInstance = false;
@@ -1922,17 +1924,17 @@ nsresult nsPluginHost::LoadPlugins() {
         if (aPluginsChanged) {
           self->ClearNonRunningPlugins();
           while (aPlugins) {
             RefPtr<nsPluginTag> pluginTag = aPlugins;
             aPlugins = aPlugins->mNext;
             self->AddPluginTag(pluginTag);
           }
           self->IncrementChromeEpoch();
-          self->SendPluginsToContent();
+          self->BroadcastPluginsToContent();
         }
 
         // Do blocklist queries immediately after.
         for (auto pair : aBlocklistRequests) {
           RefPtr<nsPluginTag> pluginTag = pair.second();
           bool shouldSoftblock = pair.first();
           self->UpdatePluginBlocklistState(pluginTag, shouldSoftblock);
         }
@@ -2072,72 +2074,96 @@ nsresult nsPluginHost::SetPluginsInConte
       obsService->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
     }
   }
 
   mPluginsLoaded = true;
   return NS_OK;
 }
 
-nsresult nsPluginHost::SendPluginsToContent() {
-  MOZ_ASSERT(XRE_IsParentProcess());
-
-  nsTArray<PluginTag> pluginTags;
-  nsTArray<FakePluginTag> fakePluginTags;
-  // Load plugins so that the epoch is correct.
-  nsresult rv = LoadPlugins();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  uint32_t newPluginEpoch = ChromeEpoch();
-
+nsresult nsPluginHost::UpdateCachedSerializablePluginList() {
   nsTArray<nsCOMPtr<nsIInternalPluginTag>> plugins;
   GetPlugins(plugins, true);
+  mSerializablePlugins.Clear();
+  mSerializableFakePlugins.Clear();
 
   for (size_t i = 0; i < plugins.Length(); i++) {
     nsCOMPtr<nsIInternalPluginTag> basetag = plugins[i];
 
     nsCOMPtr<nsIFakePluginTag> faketag = do_QueryInterface(basetag);
     if (faketag) {
       /// FIXME-jsplugins - We need to add a nsIInternalPluginTag->AsNative() to
       /// avoid this hacky static cast
       nsFakePluginTag* tag = static_cast<nsFakePluginTag*>(basetag.get());
       mozilla::ipc::URIParams handlerURI;
       SerializeURI(tag->HandlerURI(), handlerURI);
-      fakePluginTags.AppendElement(FakePluginTag(
+      mSerializableFakePlugins.AppendElement(FakePluginTag(
           tag->Id(), handlerURI, tag->Name(), tag->Description(),
           tag->MimeTypes(), tag->MimeDescriptions(), tag->Extensions(),
           tag->GetNiceFileName(), tag->SandboxScript()));
       continue;
     }
 
     /// FIXME-jsplugins - We need to cleanup the various plugintag classes
     /// to be more sane and avoid this dance
     nsPluginTag* tag = static_cast<nsPluginTag*>(basetag.get());
 
     uint32_t blocklistState;
     if (NS_WARN_IF(NS_FAILED(tag->GetBlocklistState(&blocklistState)))) {
       return NS_ERROR_FAILURE;
     }
 
-    pluginTags.AppendElement(PluginTag(
+    mSerializablePlugins.AppendElement(PluginTag(
         tag->mId, tag->Name(), tag->Description(), tag->MimeTypes(),
         tag->MimeDescriptions(), tag->Extensions(), tag->mIsFlashPlugin,
         tag->mSupportsAsyncRender, tag->FileName(), tag->Version(),
         tag->mLastModifiedTime, tag->mSandboxLevel, blocklistState));
   }
+  return NS_OK;
+}
+
+nsresult nsPluginHost::BroadcastPluginsToContent() {
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  // Load plugins so that the epoch is correct.
+  nsresult rv = LoadPlugins();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = UpdateCachedSerializablePluginList();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  uint32_t newPluginEpoch = ChromeEpoch();
+
   nsTArray<dom::ContentParent*> parents;
   dom::ContentParent::GetAll(parents);
   for (auto p : parents) {
-    Unused << p->SendSetPluginList(newPluginEpoch, pluginTags, fakePluginTags);
+    Unused << p->SendSetPluginList(newPluginEpoch, mSerializablePlugins,
+                                   mSerializableFakePlugins);
   }
   return NS_OK;
 }
 
+nsresult nsPluginHost::SendPluginsToContent(dom::ContentParent* parent) {
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(parent);
+  // Load plugins so that the epoch is correct.
+  nsresult rv = LoadPlugins();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  Unused << parent->SendSetPluginList(ChromeEpoch(), mSerializablePlugins,
+                                      mSerializableFakePlugins);
+  return NS_OK;
+}
+
 void nsPluginHost::UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag) {
   if (!aPluginTag) {
     return;
   }
 
   // Update types with category manager
   nsAutoCString disableFullPage;
   Preferences::GetCString(kPrefDisableFullPage, disableFullPage);
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -22,28 +22,30 @@
 #include "nsINamed.h"
 #include "nsTObserverArray.h"
 #include "nsITimer.h"
 #include "nsPluginTags.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIIDNService.h"
 #include "nsCRT.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
+#include "mozilla/plugins/PluginTypes.h"
 
 #ifdef XP_WIN
 #  include <minwindef.h>
 #  include "nsIWindowsRegKey.h"
 #endif
 
 namespace mozilla {
 namespace plugins {
-class FakePluginTag;
-class PluginTag;
 class BlocklistPromiseHandler;
 }  // namespace plugins
+namespace dom {
+class ContentParent;
+}  // namespace dom
 }  // namespace mozilla
 
 class nsNPAPIPlugin;
 class nsIFile;
 class nsIChannel;
 class nsPluginNativeWindow;
 class nsObjectLoadingContent;
 class nsPluginInstanceOwner;
@@ -201,17 +203,18 @@ class nsPluginHost final : public nsIPlu
                                    nsIStreamListener** aStreamListener);
 
   void CreateWidget(nsPluginInstanceOwner* aOwner);
 
   nsresult EnumerateSiteData(const nsACString& domain,
                              const nsTArray<nsCString>& sites,
                              nsTArray<nsCString>& result, bool firstMatchOnly);
 
-  nsresult SendPluginsToContent();
+  nsresult UpdateCachedSerializablePluginList();
+  nsresult SendPluginsToContent(mozilla::dom::ContentParent* parent);
   nsresult SetPluginsInContent(
       uint32_t aPluginEpoch, nsTArray<mozilla::plugins::PluginTag>& aPlugins,
       nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins);
 
   void UpdatePluginBlocklistState(nsPluginTag* aPluginTag,
                                   bool aShouldSoftblock = false);
 
  private:
@@ -265,16 +268,18 @@ class nsPluginHost final : public nsIPlu
   // be filled in with the MIME type the plugin is registered for.
   nsPluginTag* FindNativePluginForExtension(const nsACString& aExtension,
                                             /* out */ nsACString& aMimeType,
                                             bool aCheckEnabled);
 
   nsresult FindStoppedPluginForURL(nsIURI* aURL,
                                    nsIPluginInstanceOwner* aOwner);
 
+  nsresult BroadcastPluginsToContent();
+
   // FIXME revisit, no ns prefix
   // Registers or unregisters the given mime type with the category manager
   enum nsRegisterType {
     ePluginRegister,
     ePluginUnregister,
     // Checks if this type should still be registered first
     ePluginMaybeUnregister
   };
@@ -313,16 +318,19 @@ class nsPluginHost final : public nsIPlu
 
   // Callback into the host from PluginFinder once it's done.
   void FindingFinished();
 
   RefPtr<nsPluginTag> mPlugins;
 
   nsTArray<RefPtr<nsFakePluginTag>> mFakePlugins;
 
+  AutoTArray<mozilla::plugins::PluginTag, 1> mSerializablePlugins;
+  nsTArray<mozilla::plugins::FakePluginTag> mSerializableFakePlugins;
+
   bool mPluginsLoaded;
 
   // set by pref plugin.override_internal_types
   bool mOverrideInternalTypes;
 
   // set by pref plugin.disable
   bool mPluginsDisabled;