Bug 1675349: Replace plugin behavior with a basic fallback r=jmathies,mixedpuppy
authorDavid Parks <daparks@mozilla.com>
Wed, 18 Nov 2020 15:55:34 +0000
changeset 557827 9036b58142b50ecf80a42c6e8968a387a84c51cd
parent 557826 739b53fbd7214daa7c71e79c95705189c666a674
child 557828 c0ff7dbb807e2c2e57fbcdae68b8b70942886b04
push id37962
push userapavel@mozilla.com
push dateWed, 18 Nov 2020 21:51:58 +0000
treeherdermozilla-central@9d797387f57c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmathies, mixedpuppy
bugs1675349
milestone85.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 1675349: Replace plugin behavior with a basic fallback r=jmathies,mixedpuppy The browser currently only enables plugin behavior for Flash and our internal test plugins. This patch replaces support for those plugins with a simple fallback that shows a transparent region where the plugin would have been. It removes the file system search(es) for the plugin dynamic libraries and short-circuits the logic to determine if plugins should do something special -- all implementations now behave the same in the presence of plugin elements. The new behavior is: 1. If the <object> or <embed> element lists a type of something other than "x-shockwave-flash" or "x-test" then the behavior is unchanged. This means that non-plugin types behave properly and unknown types (for example, typos) are also unaffected (they reduce to 0x0 elements). 2. If the <object> element has an HTML fallback in the DOM (see spec for <object> elements) then the fallback is always shown. 3. Otherwise, the element is shown as a transparent region with the size specified in attributes. Differential Revision: https://phabricator.services.mozilla.com/D95902
browser/actors/PluginChild.jsm
dom/base/nsContentUtils.cpp
dom/base/nsIObjectLoadingContent.idl
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
dom/events/EventStates.h
dom/plugins/base/PluginFinder.cpp
dom/plugins/base/PluginFinder.h
dom/plugins/base/moz.build
dom/plugins/base/nsPluginDirServiceProvider.cpp
dom/plugins/base/nsPluginDirServiceProvider.h
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
layout/style/res/pluginproblem.css
servo/components/style/element_state.rs
servo/components/style/gecko/non_ts_pseudo_class_list.rs
servo/components/style/gecko/wrapper.rs
toolkit/content/widgets/pluginProblem.js
toolkit/mozapps/extensions/internal/PluginProvider.jsm
toolkit/pluginproblem/content/pluginProblemContent.css
--- a/browser/actors/PluginChild.jsm
+++ b/browser/actors/PluginChild.jsm
@@ -271,16 +271,21 @@ class PluginChild extends JSWindowActorC
       overlay.removeAttribute("sizing");
       overlay.setAttribute("notext", "notext");
     } else {
       overlayDisplay = OVERLAY_DISPLAY.FULL;
       overlay.removeAttribute("sizing");
       overlay.removeAttribute("notext");
     }
 
+    if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_BLOCK_ALL) {
+      overlay.setAttribute("blockall", "blockall");
+      return OVERLAY_DISPLAY.HIDDEN;
+    }
+
     // The hit test below only works with correct layout information,
     // don't do it if layout needs flush.
     // We also don't want to access scrollWidth/scrollHeight if
     // the layout needs flush.
     if (layoutNeedsFlush) {
       return overlayDisplay;
     }
 
@@ -379,16 +384,18 @@ class PluginChild extends JSWindowActorC
         return "PluginOutdated";
       case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
       case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY_QUIET:
         return "PluginClickToPlay";
       case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
         return "PluginVulnerableUpdatable";
       case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
         return "PluginVulnerableNoUpdate";
+      case Ci.nsIObjectLoadingContent.PLUGIN_BLOCK_ALL:
+        return "PluginBlockAll";
       default:
         // Not all states map to a handler
         return null;
     }
   }
 
   handleEvent(event) {
     // Ignore events for other frames.
@@ -470,16 +477,17 @@ class PluginChild extends JSWindowActorC
     }
 
     let shouldShowNotification = false;
     switch (eventType) {
       case "PluginCrashed":
         this.onPluginCrashed(pluginElement, event);
         break;
 
+      case "PluginBlockAll":
       case "PluginNotFound": {
         /* NOP */
         break;
       }
 
       case "PluginBlocklisted":
       case "PluginOutdated":
         shouldShowNotification = true;
@@ -712,16 +720,17 @@ class PluginChild extends JSWindowActorC
     // Have to check that the target is not the link to update the plugin
     if (
       !(
         ChromeUtils.getClassName(event.originalTarget) === "HTMLAnchorElement"
       ) &&
       event.originalTarget.getAttribute("anonid") != "closeIcon" &&
       event.originalTarget.id != "closeIcon" &&
       !overlay.hasAttribute("dismissed") &&
+      !overlay.hasAttribute("blockall") &&
       event.button == 0 &&
       event.isTrusted
     ) {
       this.showClickToPlayNotification(plugin, true);
       event.stopPropagation();
       event.preventDefault();
     }
   }
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -9731,28 +9731,21 @@ uint32_t nsContentUtils::HtmlObjectConte
   if (aMIMEType.LowerCaseEqualsLiteral("application/pdf") && IsPDFJSEnabled()) {
     return nsIObjectLoadingContent::TYPE_DOCUMENT;
   }
 
   if (HtmlObjectContentSupportsDocument(aMIMEType, aContent)) {
     return nsIObjectLoadingContent::TYPE_DOCUMENT;
   }
 
-  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
-  if (pluginHost) {
-    nsCOMPtr<nsIPluginTag> tag = PluginTagForType(aMIMEType, aNoFakePlugin);
-    if (tag) {
-      if (!aNoFakePlugin &&
-          nsCOMPtr<nsIFakePluginTag>(do_QueryInterface(tag))) {
-        return nsIObjectLoadingContent::TYPE_FAKE_PLUGIN;
-      }
-
-      // ShouldPlay will handle checking for disabled plugins
-      return nsIObjectLoadingContent::TYPE_PLUGIN;
-    }
+  bool isPlugin = nsPluginHost::GetSpecialType(aMIMEType) !=
+                  nsPluginHost::eSpecialType_None;
+  if (isPlugin) {
+    // ShouldPlay will handle checking for disabled plugins
+    return nsIObjectLoadingContent::TYPE_PLUGIN;
   }
 
   return nsIObjectLoadingContent::TYPE_NULL;
 }
 
 /* static */
 already_AddRefed<nsISerialEventTarget> nsContentUtils::GetEventTargetByLoadInfo(
     nsILoadInfo* aLoadInfo, TaskCategory aCategory) {
--- a/dom/base/nsIObjectLoadingContent.idl
+++ b/dom/base/nsIObjectLoadingContent.idl
@@ -60,16 +60,19 @@ interface nsIObjectLoadingContent : nsIS
   // The plugin is disabled until the user clicks on it
   const unsigned long PLUGIN_CLICK_TO_PLAY        = 8;
   // The plugin is vulnerable (update available)
   const unsigned long PLUGIN_VULNERABLE_UPDATABLE = 9;
   // The plugin is vulnerable (no update available)
   const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10;
   // The plugin is click-to-play, but the user won't see overlays
   const unsigned long PLUGIN_CLICK_TO_PLAY_QUIET  = 11;
+  // Plugins are no longer supported.  The plugin should not load and should
+  // be represented by a transparent element.
+  const unsigned long PLUGIN_BLOCK_ALL            = 12;
 
   // Plugins-specific permission indicating that we want to prompt the user
   // to decide whether they want to allow a plugin, but to do so in a less
   // intrusive way than PROMPT_ACTION would entail. At the time of writing,
   // this means hiding all in-content plugin overlays, but still showing the
   // plugin badge in the URL bar.
   const unsigned long PLUGIN_PERMISSION_PROMPT_ACTION_QUIET = 8;
 
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -91,16 +91,17 @@
 #include "mozilla/dom/HTMLEmbedElement.h"
 #include "mozilla/dom/HTMLObjectElement.h"
 #include "mozilla/dom/UserActivation.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/net/DocumentChannel.h"
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/StaticPrefs_plugins.h"
 #include "mozilla/StaticPrefs_security.h"
 #include "nsChannelClassifier.h"
 #include "nsFocusManager.h"
 #include "ReferrerInfo.h"
 
 #ifdef XP_WIN
 // Thanks so much, Microsoft! :(
 #  ifdef CreateEvent
@@ -1287,16 +1288,18 @@ EventStates nsObjectLoadingContent::Obje
         case eFallbackUnsupported:
         case eFallbackOutdated:
         case eFallbackAlternate:
           return NS_EVENT_STATE_BROKEN;
         case eFallbackVulnerableUpdatable:
           return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
         case eFallbackVulnerableNoUpdate:
           return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
+        case eFallbackBlockAllPlugins:
+          return NS_EVENT_STATE_HANDLER_NOPLUGINS;
       }
   }
   MOZ_ASSERT_UNREACHABLE("unknown type?");
   return NS_EVENT_STATE_LOADING;
 }
 
 void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
                                                       nsIURI* aBaseURI,
@@ -2076,21 +2079,21 @@ nsresult nsObjectLoadingContent::LoadObj
     LOG(("OBJLC [%p]: Enable content blocking", this));
     mType = eType_Loading;
   }
 
   // If we're a plugin but shouldn't start yet, load fallback with
   // reason click-to-play instead. Items resolved as Image/Document
   // will not be checked for previews, as well as invalid plugins
   // (they will not have the mContentType set).
-  FallbackType clickToPlayReason;
-  if (!mActivated && IsPluginType(mType) && !ShouldPlay(clickToPlayReason)) {
-    LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
+  FallbackType noPlayReason;
+  if (!mActivated && IsPluginType(mType) && !ShouldPlay(noPlayReason)) {
+    LOG(("OBJLC [%p]: Marking plugin as do-not-play", this));
     mType = eType_Null;
-    fallbackType = clickToPlayReason;
+    fallbackType = noPlayReason;
   }
 
   if (!mActivated && IsPluginType(mType)) {
     // Object passed ShouldPlay, so it should be considered
     // activated until it changes content type
     LOG(("OBJLC [%p]: Object implicitly activated", this));
     mActivated = true;
   }
@@ -2228,18 +2231,19 @@ nsresult nsObjectLoadingContent::LoadObj
   }
 
   // If we didn't load anything, handle switching to fallback state
   if (mType == eType_Null) {
     LOG(("OBJLC [%p]: Loading fallback, type %u", this, fallbackType));
     NS_ASSERTION(!mFrameLoader && !mInstanceOwner,
                  "switched to type null but also loaded something");
 
-    // Don't fire error events if we're falling back to click-to-play; instead
-    // pretend like this is a really slow-loading plug-in instead.
+    // Don't fire error events if we're falling back to click-to-play or if we
+    // are blocking all plugins; pretend like this is a really slow-loading
+    // plug-in instead.
     if (fallbackType != eFallbackClickToPlay &&
         fallbackType != eFallbackClickToPlayQuiet) {
       MaybeFireErrorEvent();
     }
 
     if (mChannel) {
       // If we were loading with a channel but then failed over, throw it away
       CloseChannel();
@@ -2599,21 +2603,21 @@ void nsObjectLoadingContent::NotifyState
     // This will trigger frame construction
     EventStates changedBits = aOldState ^ newState;
     {
       nsAutoScriptBlocker scriptBlocker;
       doc->ContentStateChanged(thisEl, changedBits);
     }
 
     // Create/destroy plugin problem UAWidget.
-    const EventStates pluginProblemState = NS_EVENT_STATE_HANDLER_BLOCKED |
-                                           NS_EVENT_STATE_HANDLER_CRASHED |
-                                           NS_EVENT_STATE_TYPE_CLICK_TO_PLAY |
-                                           NS_EVENT_STATE_VULNERABLE_UPDATABLE |
-                                           NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
+    const EventStates pluginProblemState =
+        NS_EVENT_STATE_HANDLER_BLOCKED | NS_EVENT_STATE_HANDLER_CRASHED |
+        NS_EVENT_STATE_TYPE_CLICK_TO_PLAY |
+        NS_EVENT_STATE_VULNERABLE_UPDATABLE |
+        NS_EVENT_STATE_VULNERABLE_NO_UPDATE | NS_EVENT_STATE_HANDLER_NOPLUGINS;
 
     bool hadProblemState = !(aOldState & pluginProblemState).IsEmpty();
     bool hasProblemState = !(newState & pluginProblemState).IsEmpty();
 
     if (hadProblemState && !hasProblemState) {
       thisEl->NotifyUAWidgetTeardown();
     } else if (!hadProblemState && hasProblemState) {
       thisEl->AttachAndSetUAShadowRoot();
@@ -2764,17 +2768,18 @@ nsNPAPIPluginInstance* nsObjectLoadingCo
 
   nsCOMPtr<nsIContent> thisContent =
       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   // The first time content script attempts to access placeholder content, fire
   // an event.  Fallback types >= eFallbackClickToPlay are plugin-replacement
   // types, see header.
   if (callerIsContentJS && !mScriptRequested && InActiveDocument(thisContent) &&
-      mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
+      mType == eType_Null && mFallbackType >= eFallbackClickToPlay &&
+      mFallbackType <= eFallbackClickToPlayQuiet) {
     nsCOMPtr<nsIRunnable> ev =
         new nsSimplePluginEvent(thisContent, u"PluginScripted"_ns);
     nsresult rv = NS_DispatchToCurrentThread(ev);
     if (NS_FAILED(rv)) {
       MOZ_ASSERT_UNREACHABLE("failed to dispatch PluginScripted event");
     }
     mScriptRequested = true;
   } else if (callerIsContentJS && mType == eType_Plugin && !mInstanceOwner &&
@@ -2870,17 +2875,18 @@ void nsObjectLoadingContent::LoadFallbac
 
   bool thisIsObject = thisContent->IsHTMLElement(nsGkAtoms::object);
 
   // Do a depth-first traverse of node tree with the current element as root,
   // looking for <embed> or <object> elements that might now need to load.
   nsTArray<nsINodeList*> childNodes;
   if (thisContent->IsHTMLElement(nsGkAtoms::object) &&
       (aType == eFallbackUnsupported || aType == eFallbackDisabled ||
-       aType == eFallbackBlocklisted || aType == eFallbackAlternate)) {
+       aType == eFallbackBlocklisted || aType == eFallbackAlternate ||
+       aType == eFallbackBlockAllPlugins)) {
     for (nsIContent* child = thisContent->GetFirstChild(); child;) {
       // When we advance to our next child, we don't want to traverse subtrees
       // under descendant <object> and <embed> elements; those will handle
       // those subtrees themselves if they end up falling back.
       bool skipChildDescendants = false;
       if (aType != eFallbackAlternate &&
           !child->IsHTMLElement(nsGkAtoms::param) &&
           nsStyleUtil::IsSignificantChild(child, false)) {
@@ -3019,17 +3025,18 @@ void nsObjectLoadingContent::PlayPlugin(
   if (!mActivated) {
     mActivated = true;
     LOG(("OBJLC [%p]: Activated by user", this));
   }
 
   // If we're in a click-to-play state, reload.
   // Fallback types >= eFallbackClickToPlay are plugin-replacement types, see
   // header
-  if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
+  if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay &&
+      mFallbackType <= eFallbackClickToPlayQuiet) {
     aRv = LoadObject(true, true);
   }
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::Reload(bool aClearActivation) {
   if (aClearActivation) {
     mActivated = false;
@@ -3126,172 +3133,21 @@ bool nsObjectLoadingContent::ShouldBlock
       StaticPrefs::browser_safebrowsing_blockedURIs_enabled()) {
     return true;
   }
 
   return false;
 }
 
 bool nsObjectLoadingContent::ShouldPlay(FallbackType& aReason) {
-  nsresult rv;
-
-  if (BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) {
-    // We no longer support loading plugins in the parent process.
-    aReason = eFallbackDisabled;
-    return false;
-  }
-
-  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
-
-  // Order of checks:
-  // * Assume a default of click-to-play
-  // * If globally disabled, per-site permissions cannot override.
-  // * If blocklisted, override the reason with the blocklist reason
-  // * Check if the flash blocking status for this page denies flash from
-  // loading.
-  // * Check per-site permissions and follow those if specified.
-  // * Honor per-plugin disabled permission
-  // * Blocklisted plugins are forced to CtP
-  // * Check per-plugin permission and follow that.
-
-  aReason = eFallbackClickToPlay;
-
-  uint32_t enabledState = nsIPluginTag::STATE_DISABLED;
-  pluginHost->GetStateForType(mContentType, nsPluginHost::eExcludeNone,
-                              &enabledState);
-  if (nsIPluginTag::STATE_DISABLED == enabledState) {
-    aReason = eFallbackDisabled;
-    return false;
-  }
-
-  // Before we check permissions, get the blocklist state of this plugin to set
-  // the fallback reason correctly. In the content process this will involve
-  // an ipc call to chrome.
-  uint32_t blocklistState = nsIBlocklistService::STATE_BLOCKED;
-  pluginHost->GetBlocklistStateForType(mContentType, nsPluginHost::eExcludeNone,
-                                       &blocklistState);
-  if (blocklistState == nsIBlocklistService::STATE_BLOCKED) {
-    // no override possible
-    aReason = eFallbackBlocklisted;
-    return false;
-  }
-
-  if (blocklistState ==
-      nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
-    aReason = eFallbackVulnerableUpdatable;
-  } else if (blocklistState ==
-             nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
-    aReason = eFallbackVulnerableNoUpdate;
-  }
-
-  // Document and window lookup
-  nsCOMPtr<nsIContent> thisContent =
-      do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
-  MOZ_ASSERT(thisContent);
-  Document* ownerDoc = thisContent->OwnerDoc();
-
-  nsCOMPtr<nsPIDOMWindowOuter> window = ownerDoc->GetWindow();
-  if (!window) {
-    return false;
-  }
-  nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetInProcessTop();
-  NS_ENSURE_TRUE(topWindow, false);
-  nsCOMPtr<Document> topDoc = topWindow->GetDoc();
-  NS_ENSURE_TRUE(topDoc, false);
-
-  // Check the flash blocking status for this page (this applies to Flash only)
-  FlashClassification documentClassification = FlashClassification::Unknown;
-  if (IsFlashMIME(mContentType)) {
-    documentClassification = ownerDoc->DocumentFlashClassification();
-  }
-  if (documentClassification == FlashClassification::Denied) {
-    aReason = eFallbackDisabled;
-    return false;
-  }
-
-  // Check the permission manager for permission based on the principal of
-  // the toplevel content.
-  nsCOMPtr<nsIPermissionManager> permissionManager =
-      services::GetPermissionManager();
-  NS_ENSURE_TRUE(permissionManager, false);
-
-  // For now we always say that the system principal uses click-to-play since
-  // that maintains current behavior and we have tests that expect this.  What
-  // we really should do is disable plugins entirely in pages that use the
-  // system principal, i.e. in chrome pages. That way the click-to-play code
-  // here wouldn't matter at all. Bug 775301 is tracking this.
-  if (!topDoc->NodePrincipal()->IsSystemPrincipal()) {
-    nsAutoCString permissionString;
-    rv = pluginHost->GetPermissionStringForType(
-        mContentType, nsPluginHost::eExcludeNone, permissionString);
-    NS_ENSURE_SUCCESS(rv, false);
-    uint32_t permission;
-    rv = permissionManager->TestPermissionFromPrincipal(
-        topDoc->NodePrincipal(), permissionString, &permission);
-    NS_ENSURE_SUCCESS(rv, false);
-    switch (permission) {
-      case nsIPermissionManager::ALLOW_ACTION:
-        if (PreferFallback(false /* isPluginClickToPlay */)) {
-          aReason = eFallbackAlternate;
-          return false;
-        }
-
-        return true;
-      case nsIPermissionManager::DENY_ACTION:
-        aReason = eFallbackDisabled;
-        return false;
-      case PLUGIN_PERMISSION_PROMPT_ACTION_QUIET:
-        if (PreferFallback(true /* isPluginClickToPlay */)) {
-          aReason = eFallbackAlternate;
-        } else {
-          aReason = eFallbackClickToPlayQuiet;
-        }
-
-        return false;
-      case nsIPermissionManager::PROMPT_ACTION:
-        if (PreferFallback(true /* isPluginClickToPlay */)) {
-          // False is already returned in this case, but
-          // it's important to correctly set aReason too.
-          aReason = eFallbackAlternate;
-        }
-
-        return false;
-      case nsIPermissionManager::UNKNOWN_ACTION:
-        break;
-      default:
-        MOZ_ASSERT(false);
-        return false;
-    }
-  }
-
-  // No site-specific permissions. Vulnerable plugins are automatically CtP
-  if (blocklistState ==
-          nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
-      blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
-    return false;
-  }
-
-  if (PreferFallback(enabledState == nsIPluginTag::STATE_CLICKTOPLAY)) {
-    aReason = eFallbackAlternate;
-    return false;
-  }
-
-  // On the following switch we don't need to handle the case where
-  // documentClassification is FlashClassification::Denied because
-  // that's already handled above.
-  switch (enabledState) {
-    case nsIPluginTag::STATE_ENABLED:
-      return true;
-    case nsIPluginTag::STATE_CLICKTOPLAY:
-      if (documentClassification == FlashClassification::Allowed) {
-        return true;
-      }
-      return false;
-  }
-  MOZ_CRASH("Unexpected enabledState");
+  MOZ_ASSERT(!BrowserTabsRemoteAutostart() || !XRE_IsParentProcess());
+
+  // We no longer support plugins.  Always fall back to our placeholder.
+  aReason = eFallbackBlockAllPlugins;
+  return false;
 }
 
 bool nsObjectLoadingContent::FavorFallbackMode(bool aIsPluginClickToPlay) {
   if (!IsFlashMIME(mContentType)) {
     return false;
   }
 
   nsAutoCString prefString;
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -99,16 +99,18 @@ class nsObjectLoadingContent : public ns
     eFallbackVulnerableUpdatable =
         nsIObjectLoadingContent::PLUGIN_VULNERABLE_UPDATABLE,
     // The plugin is vulnerable (no update available)
     eFallbackVulnerableNoUpdate =
         nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE,
     // The plugin is click-to-play, but the user won't see overlays
     eFallbackClickToPlayQuiet =
         nsIObjectLoadingContent::PLUGIN_CLICK_TO_PLAY_QUIET,
+    // Plugins are no longer supported.  Content is just a transparent rect.
+    eFallbackBlockAllPlugins = nsIObjectLoadingContent::PLUGIN_BLOCK_ALL,
   };
 
   nsObjectLoadingContent();
   virtual ~nsObjectLoadingContent();
 
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIOBJECTLOADINGCONTENT
--- a/dom/events/EventStates.h
+++ b/dom/events/EventStates.h
@@ -289,16 +289,19 @@ class EventStates {
 #define NS_EVENT_STATE_AUTOFILL_PREVIEW NS_DEFINE_EVENT_STATE_MACRO(51)
 // There's a free bit here.
 // Modal <dialog> element
 #define NS_EVENT_STATE_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(53)
 // Inert subtrees
 #define NS_EVENT_STATE_MOZINERT NS_DEFINE_EVENT_STATE_MACRO(54)
 // Topmost Modal <dialog> element in top layer
 #define NS_EVENT_STATE_TOPMOST_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(55)
+// Handler for empty element that represents plugin instances in builds
+// where plugin support is removed..
+#define NS_EVENT_STATE_HANDLER_NOPLUGINS NS_DEFINE_EVENT_STATE_MACRO(56)
 /**
  * NOTE: do not go over 63 without updating EventStates::InternalType!
  */
 
 #define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
 
 #define DIR_ATTR_STATES                                        \
   (NS_EVENT_STATE_HAS_DIR_ATTR | NS_EVENT_STATE_DIR_ATTR_LTR | \
deleted file mode 100644
--- a/dom/plugins/base/PluginFinder.cpp
+++ /dev/null
@@ -1,1237 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/* PluginFinder.cpp - manages finding plugins on disk, and keeping plugin
- * lists in the host updated. */
-
-#include "PluginFinder.h"
-
-#include "nsIBlocklistService.h"
-#include "nsIFile.h"
-#include "nsIXULRuntime.h"
-#if defined(XP_MACOSX)
-#  include "nsILocalFileMac.h"
-#endif
-#include "nsIWritablePropertyBag2.h"
-
-#include "mozilla/ClearOnShutdown.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Result.h"
-#include "mozilla/ResultExtensions.h"
-#include "mozilla/Telemetry.h"
-
-#include "nscore.h"
-#include "prio.h"
-
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsComponentManagerUtils.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsPluginDirServiceProvider.h"
-#include "nsPluginHost.h"
-#include "nsPluginLogging.h"
-#include "nsPluginManifestLineReader.h"
-#include "nsPrintfCString.h"
-#include "nsUnicharUtils.h"
-#include "nsThreadUtils.h"
-#include "xpcpublic.h"
-
-using namespace mozilla;
-
-static const char* kPluginRegistryVersion = "0.19";
-
-StaticRefPtr<nsIFile> sPluginRegFile;
-
-#define kPluginRegistryFilename "pluginreg.dat"_ns
-
-#define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_) \
-  {                                                   \
-    while (list_) {                                   \
-      type_ temp = list_->mNext_;                     \
-      list_->mNext_ = nullptr;                        \
-      list_ = temp;                                   \
-    }                                                 \
-  }
-
-/* to cope with short read */
-/* we should probably put this into a global library now that this is the second
-   time we need this. */
-static int32_t busy_beaver_PR_Read(PRFileDesc* fd, void* start, int32_t len) {
-  int n;
-  int32_t remaining = len;
-
-  while (remaining > 0) {
-    n = PR_Read(fd, start, remaining);
-    if (n < 0) {
-      /* may want to repeat if errno == EINTR */
-      if ((len - remaining) == 0)  // no octet is ever read
-        return -1;
-      break;
-    }
-    remaining -= n;
-    char* cp = (char*)start;
-    cp += n;
-    start = cp;
-  }
-  return len - remaining;
-}
-
-NS_IMPL_ISUPPORTS0(nsInvalidPluginTag)
-
-nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath,
-                                       int64_t aLastModifiedTime)
-    : mFullPath(aFullPath),
-      mLastModifiedTime(aLastModifiedTime),
-      mSeen(false) {}
-
-nsInvalidPluginTag::~nsInvalidPluginTag() = default;
-
-// flat file reg funcs
-static bool ReadSectionHeader(nsPluginManifestLineReader& reader,
-                              const char* token) {
-  do {
-    if (*reader.LinePtr() == '[') {
-      char* p = reader.LinePtr() + (reader.LineLength() - 1);
-      if (*p != ']') break;
-      *p = 0;
-
-      char* values[1];
-      if (1 != reader.ParseLine(values, 1)) break;
-      // ignore the leading '['
-      if (PL_strcmp(values[0] + 1, token)) {
-        break;  // it's wrong token
-      }
-      return true;
-    }
-  } while (reader.NextLine());
-  return false;
-}
-
-nsPluginTag* PluginFinder::FirstPluginWithPath(const nsCString& path) {
-  for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
-    if (tag->mFullPath.Equals(path)) {
-      return tag;
-    }
-  }
-  return nullptr;
-}
-
-NS_IMPL_ISUPPORTS(PluginFinder, nsIRunnable, nsIAsyncShutdownBlocker)
-
-// nsIAsyncShutdownBlocker
-nsresult PluginFinder::GetName(nsAString& aName) {
-  aName.AssignLiteral("PluginFinder: finding plugins to load");
-  return NS_OK;
-}
-
-NS_IMETHODIMP PluginFinder::BlockShutdown(
-    nsIAsyncShutdownClient* aBarrierClient) {
-  // Finding plugins isn't interruptable, but we can attempt to prevent loading
-  // the plugins in nsPluginHost.
-  mShutdown = true;
-  return NS_OK;
-}
-
-NS_IMETHODIMP PluginFinder::GetState(nsIPropertyBag** aBagOut) {
-  MOZ_ASSERT(aBagOut);
-  nsCOMPtr<nsIWritablePropertyBag2> propertyBag =
-      do_CreateInstance("@mozilla.org/hash-property-bag;1");
-
-  if (NS_WARN_IF(!propertyBag)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  propertyBag->SetPropertyAsBool(u"Finding"_ns, !mFinishedFinding);
-  propertyBag->SetPropertyAsBool(u"CreatingList"_ns, mCreateList);
-  propertyBag->SetPropertyAsBool(u"FlashOnly"_ns, mFlashOnly);
-  propertyBag->SetPropertyAsBool(u"HavePlugins"_ns, !!mPlugins);
-  propertyBag.forget(aBagOut);
-  return NS_OK;
-}
-
-PluginFinder::PluginFinder(bool aFlashOnly)
-    : mFlashOnly(aFlashOnly),
-      mCreateList(false),
-      mPluginsChanged(false),
-      mFinishedFinding(false),
-      mCalledOnMainthread(false),  // overwritten from Run()
-      mShutdown(false) {}
-
-nsresult PluginFinder::DoFullSearch(const FoundPluginCallback& aCallback) {
-  MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
-  mCreateList = true;
-  mFoundPluginCallback = std::move(aCallback);
-
-  nsresult rv = EnsurePluginReg();
-  // We pass this back to the caller, and ignore all other errors.
-  if (rv == NS_ERROR_NOT_AVAILABLE) {
-    return rv;
-  }
-
-  // Figure out plugin directories:
-  MOZ_TRY(DeterminePluginDirs());
-  // If we're only interested in flash, provide an initial update from
-  // cache. We'll do a scan async, away from the main thread, and if
-  // there are updates then we'll pass them in.
-  if (mFlashOnly) {
-    ReadFlashInfo();
-    // Don't do a blocklist check until we're done scanning,
-    // as the version might change anyway.
-    nsTArray<std::pair<bool, RefPtr<nsPluginTag>>> arr;
-    mFoundPluginCallback(!!mPlugins, mPlugins, arr);
-    // We've passed ownership of the flash plugin to the host, so make sure
-    // we don't accidentally try to use it when we leave the mainthread.
-    mPlugins = nullptr;
-  }
-  return NS_OK;
-}
-
-nsresult PluginFinder::HavePluginsChanged(
-    const PluginChangeCallback& aCallback) {
-  MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
-  mChangeCallback = std::move(aCallback);
-
-  nsresult rv = EnsurePluginReg();
-  // We pass this back to the caller, and ignore all other errors.
-  if (rv == NS_ERROR_NOT_AVAILABLE) {
-    return rv;
-  }
-
-  // Read cached flash info if in flash-only mode.
-  if (mFlashOnly) {
-    ReadFlashInfo();
-  }
-
-  // Figure out plugin directories:
-  MOZ_TRY(DeterminePluginDirs());
-  return NS_OK;
-}
-
-nsresult PluginFinder::Run() {
-  if (!mFinishedFinding) {
-    mCalledOnMainthread = NS_IsMainThread();
-    mFinishedFinding = true;
-    FindPlugins();  // Will call WritePluginInfo()
-    if (!mCalledOnMainthread) {
-      return NS_DispatchToMainThread(this);
-    }
-  }
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!mShutdown) {
-    // Write flash info here because we can only do so when on the main thread.
-    // pluginreg.dat got written in FindPlugins if mPluginsChanged is true.
-    if (mFlashOnly && mPluginsChanged) {
-      WriteFlashInfo(mPlugins);
-    }
-    if (mCreateList) {
-      mFoundPluginCallback(mPluginsChanged, mPlugins, mPluginBlocklistRequests);
-    } else {
-      mChangeCallback(mPluginsChanged);
-    }
-  }
-
-  // The host will adopt these plugin tag instances when given them,
-  // so we should delete our references.
-  mPlugins = nullptr;  // Don't iterate over these as the host needs them.
-  NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
-  NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
-
-  // We need to tell the host we're done. We're on the main thread,
-  // but we could still be in the process of creating the pluginhost,
-  // if we were called synchronously. In that case, the host is
-  // responsible for cleaning us up, as we can't tell it to do so.
-  // So if we were called *async*, tell the host we're done:
-  if (mCreateList && !mCalledOnMainthread) {
-    RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
-    host->FindingFinished();
-  }
-  return NS_OK;
-}
-
-nsresult PluginFinder::ReadFlashInfo() {
-  nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
-  if (!runtime) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIPrefBranch> prefs = Preferences::GetRootBranch();
-  nsAutoCString arch;
-  nsresult rv = prefs->GetCharPref("plugin.flash.arch", arch);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsAutoCString ourArch;
-  rv = runtime->GetXPCOMABI(ourArch);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  // Bail if we've changed architectures.
-  if (!ourArch.Equals(arch)) {
-    return NS_OK;
-  }
-
-  nsAutoCString version;
-  rv = prefs->GetCharPref("plugin.flash.version", version);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  nsAutoCString path;
-  rv = prefs->GetCharPref("plugin.flash.path", path);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  nsCOMPtr<nsIFile> pluginFile;
-#ifdef XP_WIN
-  // "native" files don't use utf-8 paths, convert:
-  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), false,
-                       getter_AddRefs(pluginFile));
-#else
-  rv = NS_NewNativeLocalFile(path, false, getter_AddRefs(pluginFile));
-#endif
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsAutoString filename;
-  rv = pluginFile->GetLeafName(filename);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  int32_t blocklistState;
-  rv = Preferences::GetInt("plugin.flash.blockliststate", &blocklistState);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  int32_t lastModLo;
-  int32_t lastModHi;
-  rv = Preferences::GetInt("plugin.flash.lastmod_lo", &lastModLo);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  rv = Preferences::GetInt("plugin.flash.lastmod_hi", &lastModHi);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  int64_t lastMod =
-      (int64_t)(((uint64_t)lastModHi) << 32 | (uint32_t)lastModLo);
-
-  nsAutoCString desc;
-  rv = prefs->GetCharPref("plugin.flash.desc", desc);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  const char* const mimetypes[3] = {"application/x-shockwave-flash",
-                                    "application/x-futuresplash", nullptr};
-  const char* const extensions[3] = {"swf", "spl", nullptr};
-  const int32_t mimetypecount = 2;
-  // For some reason, the descriptions are different between Windows and
-  // Linux/Mac:
-#ifdef XP_WIN
-  const char* const mimedescriptions[3] = {"Adobe Flash movie",
-                                           "FutureSplash movie", nullptr};
-#else
-  const char* const mimedescriptions[3] = {"Shockwave Flash",
-                                           "FutureSplash Player", nullptr};
-#endif
-
-  MOZ_ASSERT((!mPlugins) && (!mCachedPlugins));
-  // We will pass this to the host:
-  RefPtr<nsPluginTag> tag = new nsPluginTag(
-      "Shockwave Flash", desc.get(), NS_ConvertUTF16toUTF8(filename).get(),
-      path.get(), version.get(), mimetypes, mimedescriptions, extensions,
-      mimetypecount, lastMod, blocklistState, true);
-  mPlugins = tag;
-  // And keep this in cache:
-  RefPtr<nsPluginTag> cachedTag = new nsPluginTag(
-      "Shockwave Flash", desc.get(), NS_ConvertUTF16toUTF8(filename).get(),
-      path.get(), version.get(), mimetypes, mimedescriptions, extensions,
-      mimetypecount, lastMod, blocklistState, true);
-  mCachedPlugins = cachedTag;
-  return NS_OK;
-}
-
-/* static */ nsresult PluginFinder::WriteFlashInfo(nsPluginTag* aPlugins) {
-  nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
-  if (!runtime) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (!aPlugins) {
-    Preferences::ClearUser("plugin.flash.arch");
-    Preferences::ClearUser("plugin.flash.blockliststate");
-    Preferences::ClearUser("plugin.flash.desc");
-    Preferences::ClearUser("plugin.flash.lastmod");
-    Preferences::ClearUser("plugin.flash.path");
-    Preferences::ClearUser("plugin.flash.version");
-    return NS_OK;
-  }
-  nsPluginTag* tag = aPlugins;
-
-  nsAutoCString arch;
-  nsresult rv = runtime->GetXPCOMABI(arch);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsCOMPtr<nsIPrefBranch> prefs = Preferences::GetRootBranch();
-  prefs->SetCharPref("plugin.flash.arch", arch);
-
-  nsAutoCString path;
-  tag->GetFullpath(path);
-  prefs->SetCharPref("plugin.flash.path", path);
-
-  int64_t lastModifiedTime;
-  tag->GetLastModifiedTime(&lastModifiedTime);
-  uint32_t lastModHi = ((uint64_t)lastModifiedTime) >> 32;
-  Preferences::SetInt("plugin.flash.lastmod_hi", (int32_t)lastModHi);
-  uint32_t lastModLo = ((uint64_t)lastModifiedTime) & 0xffffffff;
-  Preferences::SetInt("plugin.flash.lastmod_lo", (int32_t)lastModLo);
-
-  nsAutoCString version;
-  tag->GetVersion(version);
-  prefs->SetCharPref("plugin.flash.version", version);
-
-  nsAutoCString desc;
-  tag->GetDescription(desc);
-  prefs->SetCharPref("plugin.flash.desc", desc);
-
-  uint32_t blocklistState;
-  tag->GetBlocklistState(&blocklistState);
-  Preferences::SetInt("plugin.flash.blockliststate", blocklistState);
-  return NS_OK;
-}
-
-namespace {
-
-int64_t GetPluginLastModifiedTime(const nsCOMPtr<nsIFile>& localfile) {
-  PRTime fileModTime = 0;
-
-#if defined(XP_MACOSX)
-  // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
-  // is a much better guide to when it was last modified than the date of
-  // its package directory.  See bug 313700.
-  nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
-  if (localFileMac) {
-    localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
-  } else {
-    localfile->GetLastModifiedTime(&fileModTime);
-  }
-#else
-  localfile->GetLastModifiedTime(&fileModTime);
-#endif
-
-  return fileModTime;
-}
-
-struct CompareFilesByTime {
-  bool LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const {
-    return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
-  }
-
-  bool Equals(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const {
-    return GetPluginLastModifiedTime(a) == GetPluginLastModifiedTime(b);
-  }
-};
-
-}  // namespace
-
-bool PluginFinder::ShouldAddPlugin(const nsPluginInfo& info) {
-  if (!info.fName ||
-      (strcmp(info.fName, "Shockwave Flash") != 0 && mFlashOnly)) {
-    return false;
-  }
-  for (uint32_t i = 0; i < info.fVariantCount; ++i) {
-    if (info.fMimeTypeArray[i] &&
-        (!strcmp(info.fMimeTypeArray[i], "application/x-shockwave-flash") ||
-         !strcmp(info.fMimeTypeArray[i],
-                 "application/x-shockwave-flash-test"))) {
-      return true;
-    }
-    if (mFlashOnly) {
-      continue;
-    }
-    if (info.fMimeTypeArray[i] &&
-        (!strcmp(info.fMimeTypeArray[i], "application/x-test") ||
-         !strcmp(info.fMimeTypeArray[i], "application/x-Second-Test"))) {
-      return true;
-    }
-  }
-#ifdef PLUGIN_LOGGING
-  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
-             ("ShouldAddPlugin : Ignoring non-flash plugin library %s\n",
-              aPluginTag->FileName().get()));
-#endif  // PLUGIN_LOGGING
-  return false;
-}
-
-nsresult PluginFinder::ScanPluginsDirectory(nsIFile* pluginsDir,
-                                            bool* aPluginsChanged) {
-  MOZ_ASSERT(XRE_IsParentProcess());
-
-  NS_ENSURE_ARG_POINTER(aPluginsChanged);
-  nsresult rv;
-
-  *aPluginsChanged = false;
-
-#ifdef PLUGIN_LOGGING
-  nsAutoCString dirPath;
-  pluginsDir->GetNativePath(dirPath);
-  PLUGIN_LOG(PLUGIN_LOG_BASIC,
-             ("PluginFinder::ScanPluginsDirectory dir=%s\n", dirPath.get()));
-#endif
-
-  nsCOMPtr<nsIDirectoryEnumerator> iter;
-  rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
-  if (NS_FAILED(rv)) return rv;
-
-  AutoTArray<nsCOMPtr<nsIFile>, 6> pluginFiles;
-
-  nsCOMPtr<nsIFile> dirEntry;
-  while (NS_SUCCEEDED(iter->GetNextFile(getter_AddRefs(dirEntry))) &&
-         dirEntry) {
-    // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll
-    // crash. See bug 197855.
-    dirEntry->Normalize();
-
-    if (nsPluginsDir::IsPluginFile(dirEntry)) {
-      pluginFiles.AppendElement(dirEntry);
-    }
-  }
-
-  pluginFiles.Sort(CompareFilesByTime());
-
-  for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
-    nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
-
-    nsString utf16FilePath;
-    rv = localfile->GetPath(utf16FilePath);
-    if (NS_FAILED(rv)) continue;
-
-    const int64_t fileModTime = GetPluginLastModifiedTime(localfile);
-
-    // Look for it in our cache
-    NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
-    RefPtr<nsPluginTag> pluginTag;
-    RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
-
-    bool seenBefore = false;
-    uint32_t blocklistState = nsIBlocklistService::STATE_NOT_BLOCKED;
-
-    if (pluginTag) {
-      seenBefore = true;
-      blocklistState = pluginTag->GetBlocklistState();
-      // If plugin changed, delete cachedPluginTag and don't use cache
-      if (fileModTime != pluginTag->mLastModifiedTime) {
-        // Plugins has changed. Don't use cached plugin info.
-        pluginTag = nullptr;
-
-        // plugin file changed, flag this fact
-        *aPluginsChanged = true;
-      }
-
-      // If we're not creating a list and we already know something changed then
-      // we're done.
-      if (!mCreateList) {
-        if (*aPluginsChanged) {
-          return NS_OK;
-        }
-        continue;
-      }
-    }
-
-    bool isKnownInvalidPlugin = false;
-    for (RefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
-         invalidPlugins; invalidPlugins = invalidPlugins->mNext) {
-      // If already marked as invalid, ignore it
-      if (invalidPlugins->mFullPath.Equals(filePath.get()) &&
-          invalidPlugins->mLastModifiedTime == fileModTime) {
-        if (mCreateList) {
-          invalidPlugins->mSeen = true;
-        }
-        isKnownInvalidPlugin = true;
-        break;
-      }
-    }
-    if (isKnownInvalidPlugin) {
-      continue;
-    }
-
-    // if it is not found in cache info list or has been changed, create a new
-    // one
-    if (!pluginTag) {
-      nsPluginFile pluginFile(localfile);
-
-      // create a tag describing this plugin.
-      PRLibrary* library = nullptr;
-      nsPluginInfo info;
-      memset(&info, 0, sizeof(info));
-      nsresult res;
-      // Opening a block for the telemetry AutoTimer
-      {
-        Telemetry::AutoTimer<Telemetry::PLUGIN_LOAD_METADATA> telemetry;
-        res = pluginFile.GetPluginInfo(info, &library);
-      }
-      // if we don't have mime type don't proceed, this is not a plugin
-      if (NS_FAILED(res) || !info.fMimeTypeArray || !ShouldAddPlugin(info)) {
-        RefPtr<nsInvalidPluginTag> invalidTag =
-            new nsInvalidPluginTag(filePath.get(), fileModTime);
-        pluginFile.FreePluginInfo(info);
-
-        if (mCreateList) {
-          invalidTag->mSeen = true;
-        }
-        invalidTag->mNext = mInvalidPlugins;
-        if (mInvalidPlugins) {
-          mInvalidPlugins->mPrev = invalidTag;
-        }
-        mInvalidPlugins = invalidTag;
-
-        // Mark aPluginsChanged so pluginreg is rewritten
-        *aPluginsChanged = true;
-        continue;
-      }
-
-      pluginTag = new nsPluginTag(&info, fileModTime, blocklistState);
-      pluginTag->mLibrary = library;
-      pluginFile.FreePluginInfo(info);
-
-      // We'll need to do a blocklist request later.
-      mPluginBlocklistRequests.AppendElement(
-          std::make_pair(!seenBefore, pluginTag));
-
-      // Plugin unloading is tag-based. If we created a new tag and loaded
-      // the library in the process then we want to attempt to unload it here.
-      // Only do this if the pref is set for aggressive unloading.
-      if (UnloadPluginsASAP()) {
-        if (NS_IsMainThread()) {
-          pluginTag->TryUnloadPlugin(false);
-        } else {
-          nsCOMPtr<nsIRunnable> unloadRunnable =
-              mozilla::NewRunnableMethod<bool>(
-                  "nsPluginTag::TryUnloadPlugin", pluginTag,
-                  &nsPluginTag::TryUnloadPlugin, false);
-          NS_DispatchToMainThread(unloadRunnable);
-        }
-      }
-    }
-
-    // do it if we still want it
-    if (!seenBefore) {
-      // We have a valid new plugin so report that plugins have changed.
-      *aPluginsChanged = true;
-    }
-
-    // Don't add the same plugin again if it hasn't changed
-    if (nsPluginTag* duplicate = FirstPluginWithPath(pluginTag->mFullPath)) {
-      if (pluginTag->mLastModifiedTime == duplicate->mLastModifiedTime) {
-        continue;
-      }
-    }
-
-    // If we're not creating a plugin list, simply looking for changes,
-    // then we're done.
-    if (!mCreateList) {
-      return NS_OK;
-    }
-
-    pluginTag->mNext = mPlugins;
-    mPlugins = pluginTag;
-  }
-
-  return NS_OK;
-}
-
-// if mCreateList is false we will just scan for plugins
-// and see if any changes have been made to the plugins.
-// This is needed in ReloadPlugins to prevent possible recursive reloads
-nsresult PluginFinder::FindPlugins() {
-  Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
-
-  // Read cached plugins info. We ignore failures, as we can proceed
-  // without a pluginreg file.
-  ReadPluginInfo();
-
-  for (nsIFile* pluginDir : mPluginDirs) {
-    if (!pluginDir) {
-      continue;
-    }
-    // Ensure we have a directory; if this isn't a directory, try the parent.
-    // We do this because in some cases items in this list of supposed plugin
-    // directories can be individual plugin files instead of directories.
-    bool isDir = false;
-    nsCOMPtr<nsIFile> parent;
-    if (NS_FAILED(pluginDir->IsDirectory(&isDir)) || !isDir) {
-      pluginDir->GetParent(getter_AddRefs(parent));
-      pluginDir = parent;
-      if (!pluginDir) {
-        continue;
-      }
-    }
-    // pluginDir not existing will be handled transparently in
-    // ScanPluginsDirectory
-
-    // don't pass mPluginsChanged directly, to prevent its
-    // possible reset in subsequent ScanPluginsDirectory calls
-    bool pluginschanged = false;
-    ScanPluginsDirectory(pluginDir, &pluginschanged);
-
-    if (pluginschanged) {
-      mPluginsChanged = true;
-      if (!mCreateList) {
-        // We're just looking for changes, so we can stop looking.
-        break;
-      }
-    }
-  }
-
-  // if we are just looking for possible changes,
-  // no need to proceed if changes are detected
-  if (!mCreateList && mPluginsChanged) {
-    NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
-    NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
-    return NS_OK;
-  }
-
-  // We should also consider plugins to have changed if any plugins have been
-  // removed. We'll know if any were removed if they weren't taken out of the
-  // cached plugins list during our scan, thus we can assume something was
-  // removed if the cached plugins list contains anything.
-  if (!mPluginsChanged && mCachedPlugins) {
-    mPluginsChanged = true;
-  }
-
-  // Remove unseen invalid plugins
-  RefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
-  while (invalidPlugins) {
-    if (!invalidPlugins->mSeen) {
-      RefPtr<nsInvalidPluginTag> invalidPlugin = invalidPlugins;
-
-      if (invalidPlugin->mPrev) {
-        invalidPlugin->mPrev->mNext = invalidPlugin->mNext;
-      } else {
-        mInvalidPlugins = invalidPlugin->mNext;
-      }
-      if (invalidPlugin->mNext) {
-        invalidPlugin->mNext->mPrev = invalidPlugin->mPrev;
-      }
-
-      invalidPlugins = invalidPlugin->mNext;
-
-      invalidPlugin->mPrev = nullptr;
-      invalidPlugin->mNext = nullptr;
-    } else {
-      invalidPlugins->mSeen = false;
-      invalidPlugins = invalidPlugins->mNext;
-    }
-  }
-
-  // if we are not creating the list, there is no need to proceed
-  if (!mCreateList) {
-    NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
-    NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
-    return NS_OK;
-  }
-
-  // if we are creating the list, it is already done;
-  // update the plugins info cache if changes are detected
-  if (mPluginsChanged) {
-    WritePluginInfo(mFlashOnly, mPlugins, mInvalidPlugins);
-  }
-
-  return NS_OK;
-}
-
-/* static */ nsresult PluginFinder::WritePluginInfo(
-    bool aFlashOnly, nsPluginTag* aPlugins,
-    nsInvalidPluginTag* aInvalidPlugins) {
-  MOZ_ASSERT(XRE_IsParentProcess());
-  // We can't write to prefs from non-main threads. Run() will update prefs
-  // from the main thread if we're flash only.
-  // We can't separate this out completely because the blocklist updates
-  // from nsPluginHost expect to be able to write here.
-  if (NS_IsMainThread() && aFlashOnly) {
-    WriteFlashInfo(aPlugins);
-  }
-
-  if (!sPluginRegFile) return NS_ERROR_FAILURE;
-
-  // Get the tmp file by getting the parent and then re-appending
-  // kPluginRegistryFilename followed by `.tmp`.
-  nsCOMPtr<nsIFile> pluginReg;
-  nsresult rv = sPluginRegFile->GetParent(getter_AddRefs(pluginReg));
-  if (NS_FAILED(rv)) return rv;
-
-  nsAutoCString filename(kPluginRegistryFilename);
-  filename.AppendLiteral(".tmp");
-  rv = pluginReg->AppendNative(filename);
-  if (NS_FAILED(rv)) return rv;
-
-  PRFileDesc* fd = nullptr;
-  rv = pluginReg->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
-                                   0600, &fd);
-  if (NS_FAILED(rv)) return rv;
-
-  nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
-  if (!runtime) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsAutoCString arch;
-  rv = runtime->GetXPCOMABI(arch);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  PR_fprintf(fd, "Generated File. Do not edit.\n");
-
-  PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c%c\nArch%c%s%c%c\n",
-             PLUGIN_REGISTRY_FIELD_DELIMITER, kPluginRegistryVersion,
-             aFlashOnly ? 't' : 'f', PLUGIN_REGISTRY_FIELD_DELIMITER,
-             PLUGIN_REGISTRY_END_OF_LINE_MARKER,
-             PLUGIN_REGISTRY_FIELD_DELIMITER, arch.get(),
-             PLUGIN_REGISTRY_FIELD_DELIMITER,
-             PLUGIN_REGISTRY_END_OF_LINE_MARKER);
-
-  // Store all plugins in the mPlugins list - all plugins currently in use.
-  PR_fprintf(fd, "\n[PLUGINS]\n");
-
-  // Do not write plugin info if we're in flash-only mode.
-  for (nsPluginTag* tag = aPlugins; !aFlashOnly && tag; tag = tag->mNext) {
-    // store each plugin info into the registry
-    // filename & fullpath are on separate line
-    // because they can contain field delimiter char
-    PR_fprintf(
-        fd, "%s%c%c\n%s%c%c\n%s%c%c\n", (tag->FileName().get()),
-        PLUGIN_REGISTRY_FIELD_DELIMITER, PLUGIN_REGISTRY_END_OF_LINE_MARKER,
-        (tag->mFullPath.get()), PLUGIN_REGISTRY_FIELD_DELIMITER,
-        PLUGIN_REGISTRY_END_OF_LINE_MARKER, (tag->Version().get()),
-        PLUGIN_REGISTRY_FIELD_DELIMITER, PLUGIN_REGISTRY_END_OF_LINE_MARKER);
-
-    // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension|blocklistState
-    PR_fprintf(fd, "%lld%c%d%c%lu%c%d%c%d%c%c\n", tag->mLastModifiedTime,
-               PLUGIN_REGISTRY_FIELD_DELIMITER,
-               false,  // did store whether or not to unload in-process plugins
-               PLUGIN_REGISTRY_FIELD_DELIMITER,
-               0,  // legacy field for flags
-               PLUGIN_REGISTRY_FIELD_DELIMITER, false,
-               PLUGIN_REGISTRY_FIELD_DELIMITER, tag->BlocklistState(),
-               PLUGIN_REGISTRY_FIELD_DELIMITER,
-               PLUGIN_REGISTRY_END_OF_LINE_MARKER);
-
-    // description, name & mtypecount are on separate line
-    PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n", (tag->Description().get()),
-               PLUGIN_REGISTRY_FIELD_DELIMITER,
-               PLUGIN_REGISTRY_END_OF_LINE_MARKER, (tag->Name().get()),
-               PLUGIN_REGISTRY_FIELD_DELIMITER,
-               PLUGIN_REGISTRY_END_OF_LINE_MARKER, tag->MimeTypes().Length());
-
-    // Add in each mimetype this plugin supports
-    for (uint32_t i = 0; i < tag->MimeTypes().Length(); i++) {
-      PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n", i, PLUGIN_REGISTRY_FIELD_DELIMITER,
-                 (tag->MimeTypes()[i].get()), PLUGIN_REGISTRY_FIELD_DELIMITER,
-                 (tag->MimeDescriptions()[i].get()),
-                 PLUGIN_REGISTRY_FIELD_DELIMITER, (tag->Extensions()[i].get()),
-                 PLUGIN_REGISTRY_FIELD_DELIMITER,
-                 PLUGIN_REGISTRY_END_OF_LINE_MARKER);
-    }
-  }
-
-  PR_fprintf(fd, "\n[INVALID]\n");
-
-  RefPtr<nsInvalidPluginTag> invalidPlugins = aInvalidPlugins;
-  while (invalidPlugins) {
-    // fullPath
-    PR_fprintf(
-        fd, "%s%c%c\n",
-        (!invalidPlugins->mFullPath.IsEmpty() ? invalidPlugins->mFullPath.get()
-                                              : ""),
-        PLUGIN_REGISTRY_FIELD_DELIMITER, PLUGIN_REGISTRY_END_OF_LINE_MARKER);
-
-    // lastModifiedTimeStamp
-    PR_fprintf(fd, "%lld%c%c\n", invalidPlugins->mLastModifiedTime,
-               PLUGIN_REGISTRY_FIELD_DELIMITER,
-               PLUGIN_REGISTRY_END_OF_LINE_MARKER);
-
-    invalidPlugins = invalidPlugins->mNext;
-  }
-
-  PRStatus prrc;
-  prrc = PR_Close(fd);
-  if (prrc != PR_SUCCESS) {
-    // we should obtain a refined value based on prrc;
-    rv = NS_ERROR_FAILURE;
-    MOZ_ASSERT(false, "PR_Close() failed.");
-    return rv;
-  }
-  rv = pluginReg->MoveToNative(nullptr, kPluginRegistryFilename);
-  return rv;
-}
-
-/* static */ nsresult PluginFinder::EnsurePluginReg() {
-  if (sPluginRegFile) {
-    return NS_OK;
-  }
-
-  if (!NS_IsMainThread()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsresult rv;
-  nsCOMPtr<nsIProperties> directoryService(
-      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
-  if (NS_FAILED(rv)) return rv;
-
-  nsCOMPtr<nsIFile> pluginRegFile;
-  directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
-                        getter_AddRefs(pluginRegFile));
-
-  if (!pluginRegFile) {
-    // There is no profile yet, this will tell us if there is going to be one
-    // in the future.
-    directoryService->Get(NS_APP_PROFILE_DIR_STARTUP, NS_GET_IID(nsIFile),
-                          getter_AddRefs(pluginRegFile));
-    if (!pluginRegFile) {
-      return NS_ERROR_FAILURE;
-    }
-
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  pluginRegFile->AppendNative(kPluginRegistryFilename);
-  sPluginRegFile = pluginRegFile;
-  ClearOnShutdown(&sPluginRegFile);
-  return NS_OK;
-}
-
-nsresult PluginFinder::DeterminePluginDirs() {
-  nsresult rv;
-  nsCOMPtr<nsIProperties> dirService(
-      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Get the app-defined list of plugin dirs.
-  nsCOMPtr<nsISimpleEnumerator> dirEnum;
-  MOZ_TRY(dirService->Get(NS_APP_PLUGINS_DIR_LIST,
-                          NS_GET_IID(nsISimpleEnumerator),
-                          getter_AddRefs(dirEnum)));
-
-  // Add any paths from MOZ_PLUGIN_PATH first.
-#if defined(XP_WIN) || defined(XP_LINUX)
-#  ifdef XP_WIN
-#    define PATH_SEPARATOR ';'
-#  else
-#    define PATH_SEPARATOR ':'
-#  endif
-  const char* pathsenv = PR_GetEnv("MOZ_PLUGIN_PATH");
-  if (pathsenv) {
-    const nsDependentCString pathsStr(pathsenv);
-    nsCCharSeparatedTokenizer paths(pathsStr, PATH_SEPARATOR);
-    while (paths.hasMoreTokens()) {
-      auto pathStr = paths.nextToken();
-      nsCOMPtr<nsIFile> pathFile;
-      rv = NS_NewNativeLocalFile(pathStr, true, getter_AddRefs(pathFile));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        continue;
-      }
-
-      bool exists;
-      if (pathFile && NS_SUCCEEDED(pathFile->Exists(&exists)) && exists) {
-        mPluginDirs.AppendElement(pathFile);
-      }
-    }
-  }
-#endif  // defined(XP_WIN) || defined(XP_LINUX)
-
-  bool hasMore = false;
-  while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
-    nsCOMPtr<nsISupports> supports;
-    nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
-    if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
-      if (NS_SUCCEEDED(rv)) {
-        mPluginDirs.AppendElement(nextDir);
-      }
-    }
-  }
-
-  // In tests, load plugins from the profile.
-  if (xpc::IsInAutomation()) {
-    nsCOMPtr<nsIFile> profDir;
-    rv = dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
-                         getter_AddRefs(profDir));
-    if (NS_SUCCEEDED(rv)) {
-      profDir->Append(u"plugins"_ns);
-      mPluginDirs.AppendElement(profDir);
-    }
-  }
-
-  // Get the directories from the windows registry. Note: these can
-  // be files instead of directories. We'll have to filter them later.
-#ifdef XP_WIN
-  bool bScanPLIDs = Preferences::GetBool("plugin.scan.plid.all", false);
-  if (bScanPLIDs) {
-    GetPLIDDirectories(mPluginDirs);
-  }
-#endif /* XP_WIN */
-  return NS_OK;
-}
-
-nsresult PluginFinder::ReadPluginInfo() {
-  MOZ_ASSERT(XRE_IsParentProcess());
-  // Non-flash-only (for tests that use other plugins) and updates to the list
-  // sadly still use the main thread - but assert about the flash startup case:
-  if (mFlashOnly && mCreateList) {
-    MOZ_ASSERT(!NS_IsMainThread());
-  } else {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
-
-  nsresult rv = EnsurePluginReg();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Cloning ensures we don't have a stat cache and get an
-  // accurate filesize.
-  nsCOMPtr<nsIFile> pluginReg;
-  rv = sPluginRegFile->Clone(getter_AddRefs(pluginReg));
-  if (NS_FAILED(rv)) return rv;
-
-  int64_t fileSize;
-  rv = pluginReg->GetFileSize(&fileSize);
-  if (NS_FAILED(rv)) return rv;
-
-  if (fileSize > INT32_MAX) {
-    return NS_ERROR_FAILURE;
-  }
-  int32_t flen = int32_t(fileSize);
-  if (flen == 0) {
-    NS_WARNING("Plugins Registry Empty!");
-    return NS_OK;  // ERROR CONDITION
-  }
-
-  nsPluginManifestLineReader reader;
-  char* registry = reader.Init(flen);
-  if (!registry) return NS_ERROR_OUT_OF_MEMORY;
-
-  PRFileDesc* fd = nullptr;
-  rv = pluginReg->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
-  if (NS_FAILED(rv)) return rv;
-
-  // set rv to return an error on goto out
-  rv = NS_ERROR_FAILURE;
-
-  // We know how many octes we are supposed to read.
-  // So let use the busy_beaver_PR_Read version.
-  int32_t bread = busy_beaver_PR_Read(fd, registry, flen);
-
-  PRStatus prrc;
-  prrc = PR_Close(fd);
-  if (prrc != PR_SUCCESS) {
-    // Strange error: this is one of those "Should not happen" error.
-    // we may want to report something more refined than  NS_ERROR_FAILURE.
-    MOZ_ASSERT(false, "PR_Close() failed.");
-    return rv;
-  }
-
-  // short read error, so to speak.
-  if (flen > bread) return rv;
-
-  if (!ReadSectionHeader(reader, "HEADER")) return rv;
-
-  if (!reader.NextLine()) return rv;
-
-  char* values[6];
-
-  // VersionLiteral, kPluginRegistryVersion
-  if (2 != reader.ParseLine(values, 2)) return rv;
-
-  // VersionLiteral
-  if (PL_strcmp(values[0], "Version")) return rv;
-
-  // If we're reading an old registry, ignore it
-  // If we flipped the flash-only pref, ignore it
-  nsAutoCString expectedVersion(kPluginRegistryVersion);
-  expectedVersion.Append(mFlashOnly ? 't' : 'f');
-
-  if (!expectedVersion.Equals(values[1])) {
-    return rv;
-  }
-
-  char* archValues[6];
-  if (!reader.NextLine()) {
-    return rv;
-  }
-
-  // ArchLiteral, Architecture
-  if (2 != reader.ParseLine(archValues, 2)) {
-    return rv;
-  }
-
-  // ArchLiteral
-  if (PL_strcmp(archValues[0], "Arch")) {
-    return rv;
-  }
-
-  nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
-  if (!runtime) {
-    return rv;
-  }
-
-  nsAutoCString arch;
-  if (NS_FAILED(runtime->GetXPCOMABI(arch))) {
-    return rv;
-  }
-
-  // If this is a registry from a different architecture then don't attempt to
-  // read it
-  if (PL_strcmp(archValues[1], arch.get())) {
-    return rv;
-  }
-
-  if (!ReadSectionHeader(reader, "PLUGINS")) return rv;
-
-  while (reader.NextLine()) {
-    if (*reader.LinePtr() == '[') {
-      break;
-    }
-    // Ignore all listed plugins if we're in flash-only mode.
-    // In that case, we're only reading this file to find invalid plugin info
-    // so we can avoid reading/loading those.
-    if (mFlashOnly) {
-      continue;
-    }
-
-    const char* filename = reader.LinePtr();
-    if (!reader.NextLine()) return rv;
-
-    const char* fullpath = reader.LinePtr();
-    if (!reader.NextLine()) return rv;
-
-    const char* version;
-    version = reader.LinePtr();
-    if (!reader.NextLine()) return rv;
-
-    // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension|blocklistState
-    if (5 != reader.ParseLine(values, 5)) return rv;
-
-    int64_t lastmod = nsCRT::atoll(values[0]);
-    uint16_t blocklistState = atoi(values[4]);
-    if (!reader.NextLine()) return rv;
-
-    char* description = reader.LinePtr();
-    if (!reader.NextLine()) return rv;
-
-    const char* name = reader.LinePtr();
-    if (!reader.NextLine()) return rv;
-
-    const long PLUGIN_REG_MIMETYPES_ARRAY_SIZE = 12;
-    const long PLUGIN_REG_MAX_MIMETYPES = 1000;
-
-    long mimetypecount = std::strtol(reader.LinePtr(), nullptr, 10);
-    if (mimetypecount == LONG_MAX || mimetypecount == LONG_MIN ||
-        mimetypecount >= PLUGIN_REG_MAX_MIMETYPES || mimetypecount < 0) {
-      return NS_ERROR_FAILURE;
-    }
-
-    char* stackalloced[PLUGIN_REG_MIMETYPES_ARRAY_SIZE * 3];
-    char** mimetypes;
-    char** mimedescriptions;
-    char** extensions;
-    char** heapalloced = 0;
-    if (mimetypecount > PLUGIN_REG_MIMETYPES_ARRAY_SIZE - 1) {
-      heapalloced = new char*[mimetypecount * 3];
-      mimetypes = heapalloced;
-    } else {
-      mimetypes = stackalloced;
-    }
-    mimedescriptions = mimetypes + mimetypecount;
-    extensions = mimedescriptions + mimetypecount;
-
-    int mtr = 0;  // mimetype read
-    for (; mtr < mimetypecount; mtr++) {
-      if (!reader.NextLine()) break;
-
-      // line number|mimetype|description|extension
-      if (4 != reader.ParseLine(values, 4)) break;
-      int line = atoi(values[0]);
-      if (line != mtr) break;
-      mimetypes[mtr] = values[1];
-      mimedescriptions[mtr] = values[2];
-      extensions[mtr] = values[3];
-    }
-
-    if (mtr != mimetypecount) {
-      delete[] heapalloced;
-      return rv;
-    }
-
-    RefPtr<nsPluginTag> tag = new nsPluginTag(
-        name, description, filename, fullpath, version,
-        (const char* const*)mimetypes, (const char* const*)mimedescriptions,
-        (const char* const*)extensions, mimetypecount, lastmod, blocklistState,
-        true);
-
-    delete[] heapalloced;
-
-    // Import flags from registry into prefs for old registry versions
-    MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
-            ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n",
-             tag->FileName().get()));
-
-    tag->mNext = mCachedPlugins;
-    mCachedPlugins = tag;
-  }
-
-  if (!ReadSectionHeader(reader, "INVALID")) {
-    return rv;
-  }
-
-  while (reader.NextLine()) {
-    const char* fullpath = reader.LinePtr();
-    if (!reader.NextLine()) {
-      return rv;
-    }
-
-    const char* lastModifiedTimeStamp = reader.LinePtr();
-    int64_t lastmod = nsCRT::atoll(lastModifiedTimeStamp);
-
-    RefPtr<nsInvalidPluginTag> invalidTag =
-        new nsInvalidPluginTag(fullpath, lastmod);
-
-    invalidTag->mNext = mInvalidPlugins;
-    if (mInvalidPlugins) {
-      mInvalidPlugins->mPrev = invalidTag;
-    }
-    mInvalidPlugins = invalidTag;
-  }
-
-  return NS_OK;
-}
-
-void PluginFinder::RemoveCachedPluginsInfo(const char* filePath,
-                                           nsPluginTag** result) {
-  RefPtr<nsPluginTag> prev;
-  RefPtr<nsPluginTag> tag = mCachedPlugins;
-  while (tag) {
-    if (tag->mFullPath.Equals(filePath)) {
-      // Found it. Remove it from our list
-      if (prev)
-        prev->mNext = tag->mNext;
-      else
-        mCachedPlugins = tag->mNext;
-      tag->mNext = nullptr;
-      *result = tag;
-      NS_ADDREF(*result);
-      break;
-    }
-    prev = tag;
-    tag = tag->mNext;
-  }
-}
deleted file mode 100644
--- a/dom/plugins/base/PluginFinder.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 PluginFinder_h_
-#define PluginFinder_h_
-
-#include "nsIRunnable.h"
-#include "mozilla/RefPtr.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsTArray.h"
-#include "nsPluginTags.h"
-#include "mozilla/StaticPrefs_dom.h"
-#include "nsIAsyncShutdown.h"
-
-class nsIFile;
-class nsPluginHost;
-
-class nsInvalidPluginTag : public nsISupports {
-  virtual ~nsInvalidPluginTag();
-
- public:
-  explicit nsInvalidPluginTag(const char* aFullPath,
-                              int64_t aLastModifiedTime = 0);
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-
-  nsCString mFullPath;
-  int64_t mLastModifiedTime;
-  bool mSeen;
-
-  RefPtr<nsInvalidPluginTag> mPrev;
-  RefPtr<nsInvalidPluginTag> mNext;
-};
-
-static inline bool UnloadPluginsASAP() {
-  return mozilla::StaticPrefs::dom_ipc_plugins_unloadTimeoutSecs() == 0;
-}
-
-/**
- * Class responsible for discovering plugins on disk, in part based
- * on cached information stored in pluginreg.dat and in the prefs.
- *
- * This runnable is designed to be used as a one-shot. It's created
- * when the pluginhost wants to find plugins, and the next time it
- * wants to do so, it should create a new one.
- */
-class PluginFinder final : public nsIRunnable, public nsIAsyncShutdownBlocker {
-  ~PluginFinder() = default;
-
- public:
-  explicit PluginFinder(bool aFlashOnly);
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIRUNNABLE
-  NS_DECL_NSIASYNCSHUTDOWNBLOCKER
-
-  typedef std::function<void(
-      bool /* aPluginsChanged */, RefPtr<nsPluginTag> /* aNewPlugins */,
-      nsTArray<
-          std::pair<bool, RefPtr<nsPluginTag>>>&) /* aBlocklistRequestPairs */>
-      FoundPluginCallback;
-  typedef std::function<void(bool /* aPluginsChanged */)> PluginChangeCallback;
-
-  // The expectation is that one (and only one) of these gets called
-  // by the plugin host. We can't easily do the work in the constructor
-  // because in some cases we'll fail early (e.g. if we're called before
-  // the profile is ready) and want to signal that to the consumer via
-  // the nsresult return value, which we can't do in a constructor.
-  nsresult DoFullSearch(const FoundPluginCallback& aCallback);
-  nsresult HavePluginsChanged(const PluginChangeCallback& aCallback);
-
-  static nsresult WritePluginInfo(
-      bool aFlashOnly, nsPluginTag* aPlugins,
-      nsInvalidPluginTag* aInvalidPlugins = nullptr);
-
- private:
-  nsPluginTag* FirstPluginWithPath(const nsCString& path);
-  bool ShouldAddPlugin(const nsPluginInfo& aInfo);
-
-  nsresult ReadFlashInfo();
-  static nsresult WriteFlashInfo(nsPluginTag* aPlugins);
-  static nsresult EnsurePluginReg();
-
-  nsresult ReadPluginInfo();
-  nsresult ReadPluginInfoFromDisk();
-
-  nsresult DeterminePluginDirs();
-
-  nsresult ScanPluginsDirectory(nsIFile* aPluginsDir, bool* aPluginsChanged);
-  nsresult FindPlugins();
-
-  void RemoveCachedPluginsInfo(const char* filePath, nsPluginTag** result);
-
-  nsTArray<nsCOMPtr<nsIFile>> mPluginDirs;
-
-  // The plugins we've found on disk (to be passed to the host)
-  RefPtr<nsPluginTag> mPlugins;
-  // The plugin whose metadata we found in cache
-  RefPtr<nsPluginTag> mCachedPlugins;
-  // Any invalid plugins our cache info made us aware of prior to actually
-  // examining the disk; this is a performance optimization to avoid trying
-  // to load files that aren't plugins on every browser startup.
-  RefPtr<nsInvalidPluginTag> mInvalidPlugins;
-
-  // The bool (shouldSoftBlock) indicates whether we should disable the plugin
-  // if it's soft-blocked in the blocklist
-  // The plugintag is a reference to the actual plugin whose blocklist state
-  // needs checking.
-  nsTArray<std::pair<bool, RefPtr<nsPluginTag>>> mPluginBlocklistRequests;
-
-  FoundPluginCallback mFoundPluginCallback;
-  PluginChangeCallback mChangeCallback;
-  RefPtr<nsPluginHost> mHost;
-
-  bool mFlashOnly;
-  bool mCreateList;
-  bool mPluginsChanged;
-  bool mFinishedFinding;
-  bool mCalledOnMainthread;
-  bool mShutdown;
-};
-
-#endif
--- a/dom/plugins/base/moz.build
+++ b/dom/plugins/base/moz.build
@@ -18,44 +18,41 @@ XPIDL_MODULE = "plugin"
 
 EXPORTS += [
     "npapi.h",
     "npfunctions.h",
     "npruntime.h",
     "nptypes.h",
     "nsJSNPRuntime.h",
     "nsNPAPIPluginInstance.h",
-    "nsPluginDirServiceProvider.h",
     "nsPluginHost.h",
     "nsPluginInstanceOwner.h",
     "nsPluginLogging.h",
     "nsPluginNativeWindow.h",
     "nsPluginsCID.h",
     "nsPluginsDir.h",
     "nsPluginTags.h",
 ]
 
 UNIFIED_SOURCES += [
     "nsJSNPRuntime.cpp",
     "nsNPAPIPluginInstance.cpp",
     "nsNPAPIPluginStreamListener.cpp",
     "nsPluginInstanceOwner.cpp",
     "nsPluginStreamListenerPeer.cpp",
     "nsPluginTags.cpp",
-    "PluginFinder.cpp",
 ]
 
 SOURCES += [
     "nsNPAPIPlugin.cpp",  # Conflict with X11 headers
     "nsPluginHost.cpp",  # Conflict with NS_NPAPIPLUGIN_CALLBACK
 ]
 
 if CONFIG["OS_ARCH"] == "WINNT":
     UNIFIED_SOURCES += [
-        "nsPluginDirServiceProvider.cpp",
         "nsPluginNativeWindowWin.cpp",
         "nsPluginsDirWin.cpp",
     ]
 elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
     UNIFIED_SOURCES += [
         "nsPluginNativeWindow.cpp",
     ]
     SOURCES += [
deleted file mode 100644
--- a/dom/plugins/base/nsPluginDirServiceProvider.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 "nsPluginDirServiceProvider.h"
-
-#include "nsCRT.h"
-#include "nsIFile.h"
-
-#include <windows.h>
-#include "nsIWindowsRegKey.h"
-
-using namespace mozilla;
-
-/* static */ nsresult GetPLIDDirectories(nsTArray<nsCOMPtr<nsIFile>>& aDirs) {
-  GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, aDirs);
-  GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
-                                aDirs);
-  return NS_OK;
-}
-
-/* static */ nsresult GetPLIDDirectoriesWithRootKey(
-    uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs) {
-  nsCOMPtr<nsIWindowsRegKey> regKey =
-      do_CreateInstance("@mozilla.org/windows-registry-key;1");
-  NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE);
-
-  nsresult rv = regKey->Open(aKey, u"Software\\MozillaPlugins"_ns,
-                             nsIWindowsRegKey::ACCESS_READ);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  uint32_t childCount = 0;
-  regKey->GetChildCount(&childCount);
-
-  for (uint32_t index = 0; index < childCount; ++index) {
-    nsAutoString childName;
-    rv = regKey->GetChildName(index, childName);
-    if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr<nsIWindowsRegKey> childKey;
-      rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE,
-                             getter_AddRefs(childKey));
-      if (NS_SUCCEEDED(rv) && childKey) {
-        nsAutoString path;
-        rv = childKey->ReadStringValue(u"Path"_ns, path);
-        if (NS_SUCCEEDED(rv)) {
-          // We deliberately do not do any further checks here on whether
-          // these are actually directories, whether they even exist, or
-          // whether they are duplicates. The pluginhost code will do them.
-          // This allows the whole process to avoid mainthread IO.
-          nsCOMPtr<nsIFile> localFile;
-          rv = NS_NewLocalFile(path, true, getter_AddRefs(localFile));
-          if (NS_SUCCEEDED(rv) && localFile) {
-            aDirs.AppendElement(localFile);
-          }
-        }
-      }
-    }
-  }
-  return NS_OK;
-}
deleted file mode 100644
--- a/dom/plugins/base/nsPluginDirServiceProvider.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 nsPluginDirServiceProvider_h_
-#define nsPluginDirServiceProvider_h_
-
-#ifdef XP_WIN
-#  include "nsCOMPtr.h"
-#  include "nsTArray.h"
-
-static nsresult GetPLIDDirectories(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
-
-static nsresult GetPLIDDirectoriesWithRootKey(
-    uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs);
-
-#endif  // XP_WIN
-#endif  // nsPluginDirServiceProvider_h_
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -72,18 +72,16 @@
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #include "nsIImageLoadingContent.h"
 #include "nsVersionComparator.h"
 #include "ReferrerInfo.h"
 
 #include "mozilla/dom/Promise.h"
 
-#include "PluginFinder.h"
-
 #if defined(XP_WIN)
 #  include "nsIWindowMediator.h"
 #  include "nsIBaseWindow.h"
 #  include "windows.h"
 #  include "winbase.h"
 #endif
 #if (MOZ_WIDGET_GTK)
 #  include <gdk/gdk.h>
@@ -177,24 +175,16 @@ class BlocklistPromiseHandler final
     sPendingBlocklistStateRequests--;
     // If this was the only remaining pending request, check if we need to write
     // state and if so update the child processes.
     if (!sPendingBlocklistStateRequests) {
       if (sPluginBlocklistStatesChangedSinceLastWrite) {
         sPluginBlocklistStatesChangedSinceLastWrite = false;
 
         RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
-        // XXXgijs This will wipe invalid plugin info. That's unfortunate, but
-        // there's no easy way around this - re-running FindPlugins will only
-        // keep invalid plugin info around long enough to use it if we force
-        // 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->BroadcastPluginsToContent();
       }
 
       // Now notify observers that we're done updating plugin state.
       nsCOMPtr<nsIObserverService> obsService =
@@ -260,27 +250,21 @@ bool BlocklistPromiseHandler::sPluginBlo
     false;
 uint32_t BlocklistPromiseHandler::sPendingBlocklistStateRequests = 0;
 }  // namespace mozilla::plugins
 
 nsPluginHost::nsPluginHost()
     : mPluginsLoaded(false),
       mOverrideInternalTypes(false),
       mPluginsDisabled(false),
-      mFlashOnly(true),
-      mDoReloadOnceFindingFinished(false),
-      mAddedFinderShutdownBlocker(false),
       mPluginEpoch(0) {
   // check to see if pref is set at startup to let plugins take over in
   // full page mode for certain image mime types that we handle internally
   mOverrideInternalTypes =
       Preferences::GetBool("plugin.override_internal_types", false);
-  if (xpc::IsInAutomation()) {
-    mFlashOnly = Preferences::GetBool("plugin.load_flash_only", true);
-  }
 
   bool waylandBackend = false;
 #if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
   GdkDisplay* display = gdk_display_get_default();
   if (display) {
     waylandBackend = !GDK_IS_X11_DISPLAY(display);
   }
 #endif
@@ -361,66 +345,18 @@ bool nsPluginHost::IsRunningPlugin(nsPlu
       return true;
     }
   }
 
   return false;
 }
 
 nsresult nsPluginHost::ReloadPlugins() {
-  PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins Begin\n"));
-
-  // If we're calling this from a content process, forward the reload request to
-  // the parent process. If plugins actually changed, it will notify us
-  // asynchronously later.
-  if (XRE_IsContentProcess()) {
-    Unused
-        << mozilla::dom::ContentChild::GetSingleton()->SendMaybeReloadPlugins();
-    // In content processes, always signal that plugins have not changed. We
-    // will never know if they changed here unless we make slow synchronous
-    // calls. This information will hopefully only be wrong once, as if there
-    // has been a plugin update, we expect to have gotten notification from the
-    // parent process and everything should be updated by the next time this is
-    // called. See Bug 1337058 for more info.
-    return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
-  }
-  // this will create the initial plugin list out of cache
-  // if it was not created yet
-  if (!mPluginsLoaded) return LoadPlugins();
-
-  // We're already in the process of finding more plugins. Do it again once
-  // done (because maybe things have changed since we started looking).
-  if (mPendingFinder) {
-    mDoReloadOnceFindingFinished = true;
-    return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
-  }
-
-  // we are re-scanning plugins. New plugins may have been added, also some
-  // plugins may have been removed, so we should probably shut everything down
-  // but don't touch running (active and not stopped) plugins
-
-  // check if plugins changed, no need to do anything else
-  // if no changes to plugins have been made
-  // We're doing this on the main thread, and we checked mPendingFinder
-  // above, so we don't need to do anything else to ensure we don't re-enter.
-  // Future work may make this asynchronous and do the finding away from
-  // the mainthread for the reload case, too, (in which case we should use
-  // mPendingFinder instead of a local copy, and update PluginFinder) but at
-  // the moment this is less important than the initial finding on startup.
-  RefPtr<PluginFinder> pf = new PluginFinder(mFlashOnly);
-  bool pluginschanged;
-  MOZ_TRY(pf->HavePluginsChanged([&pluginschanged](bool aPluginsChanged) {
-    pluginschanged = aPluginsChanged;
-  }));
-  pf->Run();
-
-  // if no changed detected, return an appropriate error code
-  if (!pluginschanged) return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
-
-  return ActuallyReloadPlugins();
+  PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins\n"));
+  return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
 }
 
 void nsPluginHost::ClearNonRunningPlugins() {
   // shutdown plugins and kill the list if there are no running plugins
   RefPtr<nsPluginTag> prev;
   RefPtr<nsPluginTag> next;
 
   for (RefPtr<nsPluginTag> p = mPlugins; p != nullptr;) {
@@ -632,45 +568,18 @@ void nsPluginHost::OnPluginInstanceDestr
   bool hasInstance = false;
   for (uint32_t i = 0; i < mInstances.Length(); i++) {
     if (TagForPlugin(mInstances[i]->GetPlugin()) == aPluginTag) {
       hasInstance = true;
       break;
     }
   }
 
-  // We have some options for unloading plugins if they have no instances.
-  //
-  // Unloading plugins immediately can be bad - some plugins retain state
-  // between instances even when there are none. This is largely limited to
-  // going from one page to another, so state is retained without an instance
-  // for only a very short period of time. In order to allow this to work
-  // we don't unload plugins immediately by default. This is supported
-  // via a hidden user pref though.
-  //
-  // Another reason not to unload immediately is that loading is expensive,
-  // and it is better to leave popular plugins loaded.
-  //
-  // Our default behavior is to try to unload a plugin after a pref-controlled
-  // delay once its last instance is destroyed. This seems like a reasonable
-  // compromise that allows us to reclaim memory while allowing short state
-  // retention and avoid perf hits for loading popular plugins.
   if (!hasInstance) {
-    if (UnloadPluginsASAP()) {
-      aPluginTag->TryUnloadPlugin(false);
-    } else {
-      if (aPluginTag->mUnloadTimer) {
-        aPluginTag->mUnloadTimer->Cancel();
-      } else {
-        aPluginTag->mUnloadTimer = NS_NewTimer();
-      }
-      uint32_t unloadTimeout = StaticPrefs::dom_ipc_plugins_unloadTimeoutSecs();
-      aPluginTag->mUnloadTimer->InitWithCallback(this, 1000 * unloadTimeout,
-                                                 nsITimer::TYPE_ONE_SHOT);
-    }
+    aPluginTag->TryUnloadPlugin(false);
   }
 }
 
 nsresult nsPluginHost::InstantiatePluginInstance(
     const nsACString& aMimeType, nsIURI* aURL, nsObjectLoadingContent* aContent,
     nsPluginInstanceOwner** aOwner) {
   NS_ENSURE_ARG_POINTER(aOwner);
 
@@ -1823,179 +1732,34 @@ uint32_t nsPluginHost::ChromeEpochForCon
   return mPluginEpoch;
 }
 
 void nsPluginHost::SetChromeEpochForContent(uint32_t aEpoch) {
   MOZ_ASSERT(XRE_IsContentProcess());
   mPluginEpoch = aEpoch;
 }
 
-#ifdef XP_WIN
-static void WatchRegKey(uint32_t aRoot, nsCOMPtr<nsIWindowsRegKey>& aKey) {
-  if (aKey) {
-    return;
-  }
-
-  aKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
-  if (!aKey) {
-    return;
-  }
-  nsresult rv = aKey->Open(
-      aRoot, u"Software\\MozillaPlugins"_ns,
-      nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::ACCESS_NOTIFY);
-  if (NS_FAILED(rv)) {
-    aKey = nullptr;
-    return;
-  }
-  aKey->StartWatching(true);
-}
-#endif
-
 already_AddRefed<nsIAsyncShutdownClient> GetProfileChangeTeardownPhase() {
   nsCOMPtr<nsIAsyncShutdownService> asyncShutdownSvc =
       services::GetAsyncShutdownService();
   MOZ_ASSERT(asyncShutdownSvc);
   if (NS_WARN_IF(!asyncShutdownSvc)) {
     return nullptr;
   }
 
   nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase;
   DebugOnly<nsresult> rv =
       asyncShutdownSvc->GetProfileChangeTeardown(getter_AddRefs(shutdownPhase));
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   return shutdownPhase.forget();
 }
 
-nsresult nsPluginHost::LoadPlugins() {
-  // This should only be run in the parent process. On plugin list change, we'll
-  // update observers in the content process as part of SetPluginsInContent
-  if (XRE_IsContentProcess()) {
-    return NS_OK;
-  }
-  // do not do anything if it is already done
-  // use ReloadPlugins() to enforce loading
-  if (mPluginsLoaded) return NS_OK;
-
-  // Uh oh, someone's forcing us to load plugins, but we're already in the
-  // process of doing so. Schedule a reload for when we're done:
-  if (mPendingFinder) {
-    mDoReloadOnceFindingFinished = true;
-    return NS_OK;
-  }
-
-  if (mPluginsDisabled) return NS_OK;
-
-#ifdef XP_WIN
-  WatchRegKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, mRegKeyHKLM);
-  WatchRegKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, mRegKeyHKCU);
-#endif
-
-  // This is a runnable. The main part of its work will be done away from the
-  // main thread.
-  mPendingFinder = new PluginFinder(mFlashOnly);
-  mDoReloadOnceFindingFinished = false;
-  mAddedFinderShutdownBlocker = false;
-  RefPtr<nsPluginHost> self = this;
-  // Note that if we're in flash only mode, which is the default, then the
-  // callback will be called twice. Once for flash (or nothing, if we're not
-  // (yet) aware of flash being present), and then again after we've actually
-  // looked for it on disk.
-  nsresult rv = mPendingFinder->DoFullSearch(
-      [self](bool aPluginsChanged, RefPtr<nsPluginTag> aPlugins,
-             const nsTArray<std::pair<bool, RefPtr<nsPluginTag>>>&
-                 aBlocklistRequests) {
-        MOZ_ASSERT(NS_IsMainThread(),
-                   "Callback should only be called on the main thread.");
-        self->mPluginsLoaded = true;
-        if (aPluginsChanged) {
-          self->ClearNonRunningPlugins();
-          while (aPlugins) {
-            RefPtr<nsPluginTag> pluginTag = aPlugins;
-            aPlugins = aPlugins->mNext;
-            self->AddPluginTag(pluginTag);
-          }
-          self->IncrementChromeEpoch();
-          self->BroadcastPluginsToContent();
-        }
-
-        // Do blocklist queries immediately after.
-        for (auto pair : aBlocklistRequests) {
-          RefPtr<nsPluginTag> pluginTag = pair.second;
-          bool shouldSoftblock = pair.first;
-          self->UpdatePluginBlocklistState(pluginTag, shouldSoftblock);
-        }
-
-        if (aPluginsChanged) {
-          nsCOMPtr<nsIObserverService> obsService =
-              mozilla::services::GetObserverService();
-          if (obsService) {
-            obsService->NotifyObservers(nullptr, "plugins-list-updated",
-                                        nullptr);
-          }
-        }
-      });
-  // Deal with the profile not being ready yet by returning NS_OK - we'll get
-  // the data later.
-  if (NS_FAILED(rv)) {
-    mPendingFinder = nullptr;
-    if (rv == NS_ERROR_NOT_AVAILABLE) {
-      return NS_OK;
-    }
-    return rv;
-  }
-  bool dispatched = false;
-
-  // If we're only looking for flash (the default), try to do so away from
-  // the main thread. Note that in this case, the callback may have been called
-  // already, from the cached plugin info.
-  if (mFlashOnly) {
-    // First add the shutdown blocker, to avoid the potential for race
-    // conditions.
-    nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase =
-        GetProfileChangeTeardownPhase();
-    if (shutdownPhase) {
-      rv = shutdownPhase->AddBlocker(mPendingFinder,
-                                     NS_LITERAL_STRING_FROM_CSTRING(__FILE__),
-                                     __LINE__, u""_ns);
-      mAddedFinderShutdownBlocker = NS_SUCCEEDED(rv);
-    }
-
-    nsCOMPtr<nsIEventTarget> target =
-        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
-    if (NS_SUCCEEDED(rv)) {
-      rv = target->Dispatch(mPendingFinder, nsIEventTarget::DISPATCH_NORMAL);
-      dispatched = NS_SUCCEEDED(rv);
-    }
-    // If we somehow failed to dispatch, remove the shutdown blocker.
-    if (mAddedFinderShutdownBlocker && !dispatched) {
-      shutdownPhase->RemoveBlocker(mPendingFinder);
-      mAddedFinderShutdownBlocker = false;
-    }
-  }
-  if (!dispatched) {
-    mPendingFinder->Run();
-    // We're running synchronously, so just remove the pending finder now.
-    mPendingFinder = nullptr;
-  }
-
-  return NS_OK;
-}
-
-void nsPluginHost::FindingFinished() {
-  if (mAddedFinderShutdownBlocker) {
-    nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase =
-        GetProfileChangeTeardownPhase();
-    shutdownPhase->RemoveBlocker(mPendingFinder);
-    mAddedFinderShutdownBlocker = false;
-  }
-  mPendingFinder = nullptr;
-  if (mDoReloadOnceFindingFinished) {
-    Unused << ReloadPlugins();
-  }
-}
+nsresult nsPluginHost::LoadPlugins() { return NS_OK; }
+
+void nsPluginHost::FindingFinished() {}
 
 nsresult nsPluginHost::SetPluginsInContent(
     uint32_t aPluginEpoch, nsTArray<mozilla::plugins::PluginTag>& aPlugins,
     nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins) {
   MOZ_ASSERT(XRE_IsContentProcess());
 
   nsTArray<PluginTag> plugins;
 
@@ -2884,19 +2648,17 @@ void nsPluginHost::DestroyRunningInstanc
 bool nsPluginHost::CanUsePluginForMIMEType(const nsACString& aMIMEType) {
   // We only support flash as a plugin, so if the mime types don't match for
   // those, exit before we start loading plugins.
   //
   // XXX: Remove test/java cases when bug 1351885 lands.
   if (nsPluginHost::GetSpecialType(aMIMEType) ==
           nsPluginHost::eSpecialType_Flash ||
       MimeTypeIsAllowedForFakePlugin(NS_ConvertUTF8toUTF16(aMIMEType)) ||
-      aMIMEType.LowerCaseEqualsLiteral("application/x-test") ||
-      aMIMEType.LowerCaseEqualsLiteral("application/x-second-test") ||
-      aMIMEType.LowerCaseEqualsLiteral("application/x-third-test")) {
+      aMIMEType.LowerCaseEqualsLiteral("application/x-test")) {
     return true;
   }
 
   return false;
 }
 
 // Runnable that does an async destroy of a plugin.
 
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -54,26 +54,23 @@ class nsNPAPIPluginStreamListener;
 class nsIPluginInstanceOwner;
 class nsIInputStream;
 class nsIStreamListener;
 #ifndef npapi_h_
 struct _NPP;
 typedef _NPP* NPP;
 #endif
 
-class PluginFinder;
-
 class nsPluginHost final : public nsIPluginHost,
                            public nsIObserver,
                            public nsITimerCallback,
                            public nsSupportsWeakReference,
                            public nsINamed {
   friend class nsPluginTag;
   friend class nsFakePluginTag;
-  friend class PluginFinder;
   virtual ~nsPluginHost();
 
  public:
   nsPluginHost();
 
   static already_AddRefed<nsPluginHost> GetInst();
 
   NS_DECL_ISUPPORTS
@@ -310,17 +307,16 @@ class nsPluginHost final : public nsIPlu
   uint32_t ChromeEpochForContent();
   void SetChromeEpochForContent(uint32_t aEpoch);
 
   void UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag);
 
   void ClearNonRunningPlugins();
   nsresult ActuallyReloadPlugins();
 
-  // 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;
@@ -328,24 +324,16 @@ class nsPluginHost final : public nsIPlu
   bool mPluginsLoaded;
 
   // set by pref plugin.override_internal_types
   bool mOverrideInternalTypes;
 
   // set by pref plugin.disable
   bool mPluginsDisabled;
 
-  // set by pref plugin.load_flash_only
-  bool mFlashOnly;
-
-  // Only one plugin finding operation should be run at a time.
-  RefPtr<PluginFinder> mPendingFinder;
-  bool mDoReloadOnceFindingFinished;
-  bool mAddedFinderShutdownBlocker;
-
   // Any instances in this array will have valid plugin objects via GetPlugin().
   // When removing an instance it might not die - be sure to null out it's
   // plugin.
   nsTArray<RefPtr<nsNPAPIPluginInstance>> mInstances;
 
   // An nsIFile for the pluginreg.dat file in the profile.
 #ifdef XP_WIN
   // In order to reload plugins when they change, we watch the registry via
--- a/layout/style/res/pluginproblem.css
+++ b/layout/style/res/pluginproblem.css
@@ -1,20 +1,12 @@
 /* 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/. */
 
 @namespace url(http://www.w3.org/1999/xhtml); /* set default namespace to HTML */
 
-embed:-moz-handler-blocked,
-embed:-moz-handler-crashed,
-embed:-moz-handler-clicktoplay,
-embed:-moz-handler-vulnerable-updatable,
-embed:-moz-handler-vulnerable-no-update,
-object:-moz-handler-blocked,
-object:-moz-handler-crashed,
-object:-moz-handler-clicktoplay,
-object:-moz-handler-vulnerable-updatable,
-object:-moz-handler-vulnerable-no-update {
+embed:-moz-handler-noplugins,
+object:-moz-handler-noplugins {
     display: inline-block;
     overflow: hidden;
-    opacity: 1 !important;
+    opacity: 0 !important;
 }
--- a/servo/components/style/element_state.rs
+++ b/servo/components/style/element_state.rs
@@ -139,16 +139,18 @@ bitflags! {
         ///
         /// https://html.spec.whatwg.org/multipage/#centered-alignment
         const IN_MODAL_DIALOG_STATE = 1 << 53;
 
         /// https://html.spec.whatwg.org/multipage/interaction.html#inert-subtrees
         const IN_MOZINERT_STATE = 1 << 54;
         /// State for the topmost dialog element in top layer
         const IN_TOPMOST_MODAL_DIALOG_STATE = 1 << 55;
+        /// Non-standard & undocumented.
+        const IN_HANDLER_NOPLUGINS = 1 << 56;
     }
 }
 
 bitflags! {
     /// Event-based document states.
     ///
     /// NB: Is important for this to remain in sync with Gecko's
     /// dom/base/Document.h.
--- a/servo/components/style/gecko/non_ts_pseudo_class_list.rs
+++ b/servo/components/style/gecko/non_ts_pseudo_class_list.rs
@@ -67,16 +67,18 @@ macro_rules! apply_non_ts_list {
 
                 ("-moz-handler-clicktoplay", MozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
                 ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
                 ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
 
                 ("-moz-handler-disabled", MozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
                 ("-moz-handler-blocked", MozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
                 ("-moz-handler-crashed", MozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
+                ("-moz-handler-noplugins", MozHandlerNoPlugins, IN_HANDLER_NOPLUGINS, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
+
                 ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _),
 
                 ("required", Required, IN_REQUIRED_STATE, _),
                 ("optional", Optional, IN_OPTIONAL_STATE, _),
                 ("valid", Valid, IN_VALID_STATE, _),
                 ("invalid", Invalid, IN_INVALID_STATE, _),
                 ("in-range", InRange, IN_INRANGE_STATE, _),
                 ("out-of-range", OutOfRange, IN_OUTOFRANGE_STATE, _),
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -2035,16 +2035,17 @@ impl<'le> ::selectors::Element for Gecko
             NonTSPseudoClass::FocusVisible |
             NonTSPseudoClass::MozDragOver |
             NonTSPseudoClass::MozDevtoolsHighlighted |
             NonTSPseudoClass::MozStyleeditorTransitioning |
             NonTSPseudoClass::MozFocusRing |
             NonTSPseudoClass::MozHandlerClickToPlay |
             NonTSPseudoClass::MozHandlerVulnerableUpdatable |
             NonTSPseudoClass::MozHandlerVulnerableNoUpdate |
+            NonTSPseudoClass::MozHandlerNoPlugins |
             NonTSPseudoClass::MozMathIncrementScriptLevel |
             NonTSPseudoClass::InRange |
             NonTSPseudoClass::OutOfRange |
             NonTSPseudoClass::Default |
             NonTSPseudoClass::MozSubmitInvalid |
             NonTSPseudoClass::MozUIInvalid |
             NonTSPseudoClass::MozMeterOptimum |
             NonTSPseudoClass::MozMeterSubOptimum |
--- a/toolkit/content/widgets/pluginProblem.js
+++ b/toolkit/content/widgets/pluginProblem.js
@@ -1,82 +1,40 @@
 /* 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";
 
 // This is a UA Widget. It runs in per-origin UA widget scope,
 // to be loaded by UAWidgetsChild.jsm.
-
+// This widget results in a hidden element that occupies room where the plugin
+// would be if we still supported plugins.
 this.PluginProblemWidget = class {
   constructor(shadowRoot) {
     this.shadowRoot = shadowRoot;
     this.element = shadowRoot.host;
     // ownerGlobal is chrome-only, not accessible to UA Widget script here.
     this.window = this.element.ownerDocument.defaultView; // eslint-disable-line mozilla/use-ownerGlobal
   }
 
   onsetup() {
     const parser = new this.window.DOMParser();
     parser.forceEnableDTD();
     let parserDoc = parser.parseFromString(
       `
       <!DOCTYPE bindings [
-        <!ENTITY % pluginproblemDTD SYSTEM "chrome://pluginproblem/locale/pluginproblem.dtd">
         <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
         <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
-        %pluginproblemDTD;
         %globalDTD;
         %brandDTD;
       ]>
       <div xmlns="http://www.w3.org/1999/xhtml" class="mainBox" id="main" chromedir="&locale.dir;">
         <link rel="stylesheet" type="text/css" href="chrome://pluginproblem/content/pluginProblemContent.css" />
-        <link rel="stylesheet" type="text/css" href="chrome://global/skin/plugins/pluginProblem.css" />
-        <div class="hoverBox">
-          <label>
-            <button class="icon" id="icon"/>
-            <div class="msg msgVulnerabilityStatus" id="vulnerabilityStatus"><!-- set at runtime --></div>
-            <div class="msg msgTapToPlay">&tapToPlayPlugin;</div>
-            <div class="msg msgClickToPlay" id="clickToPlay">&clickToActivatePlugin;</div>
-          </label>
-
-          <div class="msg msgBlocked">&blockedPlugin.label;</div>
-          <div class="msg msgCrashed">
-            <div class="msgCrashedText" id="crashedText"><!-- set at runtime --></div>
-            <!-- link href set at runtime -->
-            <div class="msgReload">&reloadPlugin.pre;<a class="reloadLink" id="reloadLink" href="">&reloadPlugin.middle;</a>&reloadPlugin.post;</div>
-          </div>
-
-          <div class="msg msgManagePlugins"><a class="action-link" id="managePluginsLink" href="">&managePlugins;</a></div>
-          <div class="submitStatus" id="submitStatus">
-            <div class="msg msgPleaseSubmit" id="pleaseSubmit">
-              <textarea class="submitComment"
-                        id="submitComment"
-                        placeholder="&report.comment;"/>
-              <div class="submitURLOptInBox">
-                <label><input class="submitURLOptIn" id="submitURLOptIn" type="checkbox"/> &report.pageURL;</label>
-              </div>
-              <div class="submitButtonBox">
-                <span class="helpIcon" id="helpIcon" role="link"/>
-                <input class="submitButton" type="button"
-                       id="submitButton"
-                       value="&report.please;"/>
-              </div>
-            </div>
-            <div class="msg msgSubmitting">&report.submitting;<span class="throbber"> </span></div>
-            <div class="msg msgSubmitted">&report.submitted;</div>
-            <div class="msg msgNotSubmitted">&report.disabled;</div>
-            <div class="msg msgSubmitFailed">&report.failed;</div>
-            <div class="msg msgNoCrashReport">&report.unavailable;</div>
-          </div>
-          <div class="msg msgCheckForUpdates"><a class="action-link" id="checkForUpdatesLink" href="">&checkForUpdates;</a></div>
       </div>
-      <button class="closeIcon" id="closeIcon" title="&hidePluginBtn.label;"/>
-    </div>
     `,
       "application/xml"
     );
     this.shadowRoot.importNodeAndAppendChildAt(
       this.shadowRoot,
       parserDoc.documentElement,
       true
     );
--- a/toolkit/mozapps/extensions/internal/PluginProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/PluginProvider.jsm
@@ -462,57 +462,25 @@ PluginWrapper.prototype = {
     return AddonManager.PENDING_NONE;
   },
 
   get operationsRequiringRestart() {
     return AddonManager.OP_NEEDS_RESTART_NONE;
   },
 
   get permissions() {
-    let {
-      tags: [tag],
-    } = pluginFor(this);
-    let permissions = 0;
-    if (tag.isEnabledStateLocked) {
-      return permissions;
-    }
-    if (!this.appDisabled) {
-      if (this.userDisabled !== true) {
-        permissions |= AddonManager.PERM_CAN_DISABLE;
-      }
-
-      if (this.userDisabled !== AddonManager.STATE_ASK_TO_ACTIVATE) {
-        permissions |= AddonManager.PERM_CAN_ASK_TO_ACTIVATE;
-      }
-
-      let blocklistState = this.blocklistState;
-      let isCTPBlocklisted =
-        blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE ||
-        blocklistState ==
-          Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE;
-      if (
-        this.userDisabled !== false &&
-        !isCTPBlocklisted &&
-        !this.isFlashPlugin
-      ) {
-        permissions |= AddonManager.PERM_CAN_ENABLE;
-      }
-    }
-    return permissions;
+    return 0;
   },
 
   get optionsType() {
-    return AddonManager.OPTIONS_TYPE_INLINE_BROWSER;
+    return null;
   },
 
   get optionsURL() {
-    return (
-      "chrome://mozapps/content/extensions/pluginPrefs.xhtml#id=" +
-      encodeURIComponent(this.id)
-    );
+    return null;
   },
 
   get updateDate() {
     return this.installDate;
   },
 
   get isCompatible() {
     return true;
--- a/toolkit/pluginproblem/content/pluginProblemContent.css
+++ b/toolkit/pluginproblem/content/pluginProblemContent.css
@@ -9,102 +9,15 @@
 }
 
 /* Do not change this without also changing the appropriate line in
  * browser-plugins.js (near where this file is mentioned). */
 :host(:not([width])), :host([width=""]) {
   height: 200px;
 }
 
-:host(:-moz-handler-clicktoplay) .mainBox,
-:host(:-moz-handler-vulnerable-updatable) .mainBox,
-:host(:-moz-handler-vulnerable-no-update) .mainBox,
-:host(:-moz-handler-blocked) .mainBox {
-  -moz-user-focus: normal;
-}
-
-:host(:-moz-handler-clicktoplay) .mainBox:focus,
-:host(:-moz-handler-vulnerable-updatable) .mainBox:focus,
-:host(:-moz-handler-vulnerable-no-update) .mainBox:focus,
-:host(:-moz-handler-blocked) .mainBox:focus {
-  outline: 1px dotted;
-}
-
 .mainBox {
   width: inherit;
   height: inherit;
   overflow: hidden;
-  direction: ltr;
-  unicode-bidi: embed;
-  /* used to block inherited properties */
-  text-transform: none;
-  text-indent: 0;
-  cursor: initial;
-  white-space: initial;
-  word-spacing: initial;
-  letter-spacing: initial;
-  line-height: initial;
-  visibility: hidden;
-}
-
-.visible {
-  visibility: visible;
-}
-
-/* Initialize the overlay with visibility:hidden to prevent flickering if
-* the plugin is too small to show the overlay */
-.mainBox > .hoverBox,
-.mainBox > .closeIcon {
+  cursor: inherit;
   visibility: hidden;
 }
-
-.visible > .hoverBox,
-.visible > .closeIcon {
-  visibility: visible;
-}
-
-.mainBox[chromedir="rtl"] {
-  direction: rtl;
-}
-
-:host(:-moz-handler-clicktoplay) .hoverBox,
-:host(:-moz-handler-vulnerable-updatable) .hoverBox,
-:host(:-moz-handler-vulnerable-no-update) .hoverBox {
-  cursor: pointer;
-}
-
-.hoverBox > label {
-  cursor: inherit;
-}
-.icon {
-  cursor: inherit;
-}
-
-.msg {
-  display: none;
-}
-
-:host(:-moz-handler-clicktoplay) .msgClickToPlay,
-:host(:-moz-handler-vulnerable-updatable) .msgVulnerabilityStatus,
-:host(:-moz-handler-vulnerable-updatable) .msgCheckForUpdates,
-:host(:-moz-handler-vulnerable-updatable) .msgClickToPlay,
-:host(:-moz-handler-vulnerable-no-update) .msgVulnerabilityStatus,
-:host(:-moz-handler-vulnerable-no-update) .msgClickToPlay,
-:host(:-moz-handler-blocked) .msgBlocked,
-:host(:-moz-handler-crashed) .msgCrashed {
-  display: block;
-}
-
-.submitStatus[status] {
-  display: -moz-box;
-  -moz-box-align: center;
-  -moz-box-pack: center;
-  height: 160px;
-}
-
-.submitStatus[status="noReport"]   .msgNoCrashReport,
-.submitStatus[status="please"]     .msgPleaseSubmit,
-.submitStatus[status="noSubmit"]   .msgNotSubmitted,
-.submitStatus[status="submitting"] .msgSubmitting,
-.submitStatus[status="success"]    .msgSubmitted,
-.submitStatus[status="failed"]     .msgSubmitFailed {
-  display: block;
-}