Move WebRequest to the UI thread

Now that network service is launched, there is no reason to have
WebRequest run on the IO thread. This moves all WebRequest code and
the WebRequestProxyingURLLoaderFactory to the UI thread, which
eliminates thread hops. For more info, see the Chrome IO Thread
Simplification: Planning doc:
https://docs.google.com/document/d/1fowGQ8xWBv4YqHj_YbK-S3wpmJQDE7L0-GwNR_vAkHE/edit#

Change-Id: I5ba8954c5d91c98c96a66558ecb659b59ff4386c
Bug: 980774
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1682434
Reviewed-by: Karan Bhatia <[email protected]>
Reviewed-by: Lei Zhang <[email protected]>
Reviewed-by: Steven Holte <[email protected]>
Commit-Queue: Clark DuVall <[email protected]>
Cr-Commit-Position: refs/heads/master@{#679227}
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 774a509..a4f05021 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -616,7 +616,6 @@
     "error_map_unittest.cc",
     "event_listener_map_unittest.cc",
     "event_router_unittest.cc",
-    "extension_api_frame_id_map_unittest.cc",
     "extension_creator_filter_unittest.cc",
     "extension_creator_unittest.cc",
     "extension_event_histogram_value_unittest.cc",
diff --git a/extensions/browser/api/declarative/rules_registry_service.cc b/extensions/browser/api/declarative/rules_registry_service.cc
index e02df99..dedb8a3 100644
--- a/extensions/browser/api/declarative/rules_registry_service.cc
+++ b/extensions/browser/api/declarative/rules_registry_service.cc
@@ -29,15 +29,6 @@
 
 namespace {
 
-// Registers |web_request_rules_registry| on the IO thread.
-void RegisterToExtensionWebRequestEventRouterOnIO(
-    content::BrowserContext* browser_context,
-    int rules_registry_id,
-    scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) {
-  ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry(
-      browser_context, rules_registry_id, web_request_rules_registry);
-}
-
 void NotifyWithExtensionSafe(
     scoped_refptr<const Extension> extension,
     void (RulesRegistry::*notification_callback)(const Extension*),
@@ -68,18 +59,11 @@
 }
 
 void RulesRegistryService::Shutdown() {
-  // Release the references to all registries. This would happen soon during
-  // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to
-  // be the last to reference the WebRequestRulesRegistry objects, so that
-  // the posted task below causes their destruction on the IO thread, not on UI
-  // where the destruction of |*this| takes place.
+  // Release the references to all registries, and remove the default registry
+  // from ExtensionWebRequestEventRouter.
   rule_registries_.clear();
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&RegisterToExtensionWebRequestEventRouterOnIO,
-                     browser_context_,
-                     RulesRegistryService::kDefaultRulesRegistryID,
-                     scoped_refptr<WebRequestRulesRegistry>(NULL)));
+  ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry(
+      browser_context_, RulesRegistryService::kDefaultRulesRegistryID, nullptr);
 }
 
 static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService>>::
@@ -198,11 +182,8 @@
   web_request_cache_delegate->AddObserver(this);
   cache_delegates_.push_back(std::move(web_request_cache_delegate));
   RegisterRulesRegistry(web_request_rules_registry);
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&RegisterToExtensionWebRequestEventRouterOnIO,
-                     browser_context_, rules_registry_id,
-                     web_request_rules_registry));
+  ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry(
+      browser_context_, rules_registry_id, web_request_rules_registry);
   return web_request_rules_registry;
 }
 
diff --git a/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc b/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
index 90627ae..cdac88d 100644
--- a/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
+++ b/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
@@ -20,8 +20,6 @@
 #include "extensions/browser/api/declarative_net_request/utils.h"
 #include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/common/api/declarative_net_request.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/url_pattern.h"
@@ -41,8 +39,8 @@
 bool HasRegisteredRuleset(content::BrowserContext* context,
                           const ExtensionId& extension_id,
                           std::string* error) {
-  const auto* rules_monitor_service = BrowserContextKeyedAPIFactory<
-      declarative_net_request::RulesMonitorService>::Get(context);
+  const auto* rules_monitor_service =
+      declarative_net_request::RulesMonitorService::Get(context);
   DCHECK(rules_monitor_service);
 
   if (rules_monitor_service->HasRegisteredRuleset(extension_id))
@@ -52,16 +50,6 @@
   return false;
 }
 
-void UpdateAllowPagesOnIOThread(const ExtensionId& extension_id,
-                                URLPatternSet allowed_pages,
-                                InfoMap* info_map) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  DCHECK(info_map);
-
-  info_map->GetRulesetManager()->UpdateAllowedPages(extension_id,
-                                                    std::move(allowed_pages));
-}
-
 }  // namespace
 
 DeclarativeNetRequestUpdateAllowedPagesFunction::
@@ -107,24 +95,13 @@
   // Persist |new_set| as part of preferences.
   prefs->SetDNRAllowedPages(extension_id(), new_set.Clone());
 
-  // Update the new allowed set on the IO thread.
-  base::OnceClosure updated_allow_pages_io_task = base::BindOnce(
-      &UpdateAllowPagesOnIOThread, extension_id(), std::move(new_set),
-      base::RetainedRef(ExtensionSystem::Get(browser_context())->info_map()));
+  auto* rules_monitor_service =
+      declarative_net_request::RulesMonitorService::Get(browser_context());
+  DCHECK(rules_monitor_service);
+  rules_monitor_service->ruleset_manager()->UpdateAllowedPages(
+      extension_id(), std::move(new_set));
 
-  base::OnceClosure updated_allowed_pages_ui_reply = base::BindOnce(
-      &DeclarativeNetRequestUpdateAllowedPagesFunction::OnAllowedPagesUpdated,
-      this);
-  base::PostTaskWithTraitsAndReply(FROM_HERE, {content::BrowserThread::IO},
-                                   std::move(updated_allow_pages_io_task),
-                                   std::move(updated_allowed_pages_ui_reply));
-
-  return RespondLater();
-}
-
-void DeclarativeNetRequestUpdateAllowedPagesFunction::OnAllowedPagesUpdated() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  Respond(NoArguments());
+  return RespondNow(NoArguments());
 }
 
 bool DeclarativeNetRequestUpdateAllowedPagesFunction::PreRunValidation(
@@ -200,8 +177,8 @@
 DeclarativeNetRequestUpdateDynamicRulesFunction::UpdateDynamicRules(
     std::vector<api::declarative_net_request::Rule> rules,
     declarative_net_request::DynamicRuleUpdateAction action) {
-  auto* rules_monitor_service = BrowserContextKeyedAPIFactory<
-      declarative_net_request::RulesMonitorService>::Get(browser_context());
+  auto* rules_monitor_service =
+      declarative_net_request::RulesMonitorService::Get(browser_context());
   DCHECK(rules_monitor_service);
   DCHECK(extension());
 
diff --git a/extensions/browser/api/declarative_net_request/declarative_net_request_api.h b/extensions/browser/api/declarative_net_request/declarative_net_request_api.h
index ef77525..c3b7f3c 100644
--- a/extensions/browser/api/declarative_net_request/declarative_net_request_api.h
+++ b/extensions/browser/api/declarative_net_request/declarative_net_request_api.h
@@ -44,8 +44,6 @@
   bool PreRunValidation(std::string* error) override;
 
  private:
-  void OnAllowedPagesUpdated();
-
   DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestUpdateAllowedPagesFunction);
 };
 
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
index 7cfd6c35..ffac35c 100644
--- a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
+++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
@@ -21,15 +21,13 @@
 #include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_matcher.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_source.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_prefs_factory.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_factory.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/browser/warning_service.h"
 #include "extensions/browser/warning_service_factory.h"
 #include "extensions/browser/warning_set.h"
@@ -49,70 +47,6 @@
     BrowserContextKeyedAPIFactory<RulesMonitorService>>::Leaky g_factory =
     LAZY_INSTANCE_INITIALIZER;
 
-void LoadRulesetOnIOThread(ExtensionId extension_id,
-                           std::unique_ptr<CompositeMatcher> matcher,
-                           URLPatternSet allowed_pages,
-                           InfoMap* info_map,
-                           void* browser_context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  DCHECK(info_map);
-
-  RulesetManager* manager = info_map->GetRulesetManager();
-  bool increment_extra_headers = !manager->HasAnyExtraHeadersMatcher() &&
-                                 matcher->HasAnyExtraHeadersMatcher();
-  manager->AddRuleset(extension_id, std::move(matcher),
-                      std::move(allowed_pages));
-
-  if (increment_extra_headers) {
-    ExtensionWebRequestEventRouter::GetInstance()
-        ->IncrementExtraHeadersListenerCount(browser_context);
-  }
-}
-
-void UnloadRulesetOnIOThread(ExtensionId extension_id,
-                             InfoMap* info_map,
-                             void* browser_context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  DCHECK(info_map);
-
-  RulesetManager* manager = info_map->GetRulesetManager();
-  bool had_extra_headers_matcher = manager->HasAnyExtraHeadersMatcher();
-  info_map->GetRulesetManager()->RemoveRuleset(extension_id);
-
-  if (had_extra_headers_matcher && !manager->HasAnyExtraHeadersMatcher()) {
-    ExtensionWebRequestEventRouter::GetInstance()
-        ->DecrementExtraHeadersListenerCount(browser_context);
-  }
-}
-
-void UpdateRulesetMatcherOnIOThread(
-    ExtensionId extension_id,
-    std::unique_ptr<RulesetMatcher> ruleset_matcher,
-    InfoMap* info_map,
-    void* browser_context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  DCHECK(info_map);
-
-  RulesetManager* manager = info_map->GetRulesetManager();
-  bool had_extra_headers_matcher = manager->HasAnyExtraHeadersMatcher();
-
-  CompositeMatcher* matcher =
-      info_map->GetRulesetManager()->GetMatcherForExtension(extension_id);
-  DCHECK(matcher);
-  matcher->AddOrUpdateRuleset(std::move(ruleset_matcher));
-
-  bool has_extra_headers_matcher = manager->HasAnyExtraHeadersMatcher();
-  if (had_extra_headers_matcher == has_extra_headers_matcher)
-    return;
-  if (has_extra_headers_matcher) {
-    ExtensionWebRequestEventRouter::GetInstance()
-        ->IncrementExtraHeadersListenerCount(browser_context);
-  } else {
-    ExtensionWebRequestEventRouter::GetInstance()
-        ->DecrementExtraHeadersListenerCount(browser_context);
-  }
-}
-
 }  // namespace
 
 // Helper to bridge tasks to FileSequenceHelper. Lives on the UI thread.
@@ -171,6 +105,13 @@
   return g_factory.Pointer();
 }
 
+// static
+RulesMonitorService* RulesMonitorService::Get(
+    content::BrowserContext* browser_context) {
+  return BrowserContextKeyedAPIFactory<RulesMonitorService>::Get(
+      browser_context);
+}
+
 bool RulesMonitorService::HasAnyRegisteredRulesets() const {
   return !extensions_with_rulesets_.empty();
 }
@@ -206,11 +147,11 @@
     content::BrowserContext* browser_context)
     : registry_observer_(this),
       file_sequence_bridge_(std::make_unique<FileSequenceBridge>()),
-      info_map_(ExtensionSystem::Get(browser_context)->info_map()),
       prefs_(ExtensionPrefs::Get(browser_context)),
       extension_registry_(ExtensionRegistry::Get(browser_context)),
       warning_service_(WarningService::Get(browser_context)),
-      context_(browser_context) {
+      context_(browser_context),
+      ruleset_manager_(browser_context) {
   registry_observer_.Add(extension_registry_);
 }
 
@@ -219,7 +160,7 @@
 /* Description of thread hops for various scenarios:
 
    On ruleset load success:
-      - UI -> File -> UI -> IO.
+      - UI -> File -> UI.
       - The File sequence might reindex the ruleset while parsing JSON OOP.
 
    On ruleset load failure:
@@ -227,12 +168,11 @@
       - The File sequence might reindex the ruleset while parsing JSON OOP.
 
    On ruleset unload:
-      - UI -> IO.
+      - UI.
 
    On dynamic rules update.
-                            |-> IPC to extension
-      - UI -> File -> UI -> |
-                            |-> IO
+
+      - UI -> File -> UI -> IPC to extension
 */
 
 void RulesMonitorService::OnExtensionLoaded(
@@ -286,11 +226,7 @@
 
   DCHECK(IsAPIAvailable());
 
-  base::OnceClosure unload_ruleset_on_io_task =
-      base::BindOnce(&UnloadRulesetOnIOThread, extension->id(),
-                     base::RetainedRef(info_map_), context_);
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
-                           std::move(unload_ruleset_on_io_task));
+  UnloadRuleset(extension->id());
 }
 
 void RulesMonitorService::OnExtensionUninstalled(
@@ -369,14 +305,9 @@
     return;
 
   extensions_with_rulesets_.insert(load_data.extension_id);
-
-  base::OnceClosure load_ruleset_on_io =
-      base::BindOnce(&LoadRulesetOnIOThread, load_data.extension_id,
-                     std::make_unique<CompositeMatcher>(std::move(matchers)),
-                     prefs_->GetDNRAllowedPages(load_data.extension_id),
-                     base::RetainedRef(info_map_), context_);
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
-                           std::move(load_ruleset_on_io));
+  LoadRuleset(load_data.extension_id,
+              std::make_unique<CompositeMatcher>(std::move(matchers)),
+              prefs_->GetDNRAllowedPages(load_data.extension_id));
 }
 
 void RulesMonitorService::OnDynamicRulesUpdated(
@@ -414,12 +345,56 @@
     return;
   }
 
-  // Update the dynamic ruleset on the IO thread.
-  base::OnceClosure update_ruleset_on_io = base::BindOnce(
-      &UpdateRulesetMatcherOnIOThread, load_data.extension_id,
-      dynamic_ruleset.TakeMatcher(), base::RetainedRef(info_map_), context_);
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
-                           std::move(update_ruleset_on_io));
+  // Update the dynamic ruleset.
+  UpdateRuleset(load_data.extension_id, dynamic_ruleset.TakeMatcher());
+}
+
+void RulesMonitorService::UnloadRuleset(const ExtensionId& extension_id) {
+  bool had_extra_headers_matcher = ruleset_manager_.HasAnyExtraHeadersMatcher();
+  ruleset_manager_.RemoveRuleset(extension_id);
+
+  if (had_extra_headers_matcher &&
+      !ruleset_manager_.HasAnyExtraHeadersMatcher()) {
+    ExtensionWebRequestEventRouter::GetInstance()
+        ->DecrementExtraHeadersListenerCount(context_);
+  }
+}
+
+void RulesMonitorService::LoadRuleset(const ExtensionId& extension_id,
+                                      std::unique_ptr<CompositeMatcher> matcher,
+                                      URLPatternSet allowed_pages) {
+  bool increment_extra_headers =
+      !ruleset_manager_.HasAnyExtraHeadersMatcher() &&
+      matcher->HasAnyExtraHeadersMatcher();
+  ruleset_manager_.AddRuleset(extension_id, std::move(matcher),
+                              prefs_->GetDNRAllowedPages(extension_id));
+
+  if (increment_extra_headers) {
+    ExtensionWebRequestEventRouter::GetInstance()
+        ->IncrementExtraHeadersListenerCount(context_);
+  }
+}
+
+void RulesMonitorService::UpdateRuleset(
+    const ExtensionId& extension_id,
+    std::unique_ptr<RulesetMatcher> ruleset_matcher) {
+  bool had_extra_headers_matcher = ruleset_manager_.HasAnyExtraHeadersMatcher();
+
+  CompositeMatcher* matcher =
+      ruleset_manager_.GetMatcherForExtension(extension_id);
+  DCHECK(matcher);
+  matcher->AddOrUpdateRuleset(std::move(ruleset_matcher));
+
+  bool has_extra_headers_matcher = ruleset_manager_.HasAnyExtraHeadersMatcher();
+  if (had_extra_headers_matcher == has_extra_headers_matcher)
+    return;
+  if (has_extra_headers_matcher) {
+    ExtensionWebRequestEventRouter::GetInstance()
+        ->IncrementExtraHeadersListenerCount(context_);
+  } else {
+    ExtensionWebRequestEventRouter::GetInstance()
+        ->DecrementExtraHeadersListenerCount(context_);
+  }
 }
 
 }  // namespace declarative_net_request
@@ -430,8 +405,8 @@
     DeclareFactoryDependencies() {
   DependsOn(ExtensionRegistryFactory::GetInstance());
   DependsOn(ExtensionPrefsFactory::GetInstance());
-  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
   DependsOn(WarningServiceFactory::GetInstance());
+  DependsOn(PermissionHelper::GetFactoryInstance());
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.h b/extensions/browser/api/declarative_net_request/rules_monitor_service.h
index 45159f7..54c4c2a 100644
--- a/extensions/browser/api/declarative_net_request/rules_monitor_service.h
+++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/scoped_observer.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/common/extension_id.h"
@@ -24,7 +25,6 @@
 }  // namespace content
 
 namespace extensions {
-class InfoMap;
 class ExtensionPrefs;
 class ExtensionRegistry;
 class WarningService;
@@ -36,6 +36,7 @@
 }  // namespace api
 
 namespace declarative_net_request {
+class RulesetMatcher;
 enum class DynamicRuleUpdateAction;
 struct LoadRequestData;
 
@@ -46,6 +47,10 @@
 class RulesMonitorService : public BrowserContextKeyedAPI,
                             public ExtensionRegistryObserver {
  public:
+  // Returns the instance for |browser_context|. An instance is shared between
+  // an incognito and a regular context.
+  static RulesMonitorService* Get(content::BrowserContext* browser_context);
+
   // BrowserContextKeyedAPI implementation.
   static BrowserContextKeyedAPIFactory<RulesMonitorService>*
   GetFactoryInstance();
@@ -65,6 +70,8 @@
                           DynamicRuleUpdateAction action,
                           DynamicRuleUpdateUICallback callback);
 
+  RulesetManager* ruleset_manager() { return &ruleset_manager_; }
+
  private:
   class FileSequenceBridge;
 
@@ -79,6 +86,7 @@
   // BrowserContextKeyedAPI implementation.
   static const char* service_name() { return "RulesMonitorService"; }
   static const bool kServiceIsNULLWhileTesting = true;
+  static const bool kServiceRedirectedInIncognito = true;
 
   // ExtensionRegistryObserver implementation.
   void OnExtensionLoaded(content::BrowserContext* browser_context,
@@ -98,6 +106,13 @@
                              LoadRequestData load_data,
                              base::Optional<std::string> error);
 
+  void UnloadRuleset(const ExtensionId& extension_id);
+  void LoadRuleset(const ExtensionId& extension_id,
+                   std::unique_ptr<CompositeMatcher> matcher,
+                   URLPatternSet allowed_pages);
+  void UpdateRuleset(const ExtensionId& extension_id,
+                     std::unique_ptr<RulesetMatcher> ruleset_matcher);
+
   ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
       registry_observer_;
 
@@ -107,13 +122,14 @@
   std::unique_ptr<const FileSequenceBridge> file_sequence_bridge_;
 
   // Guaranteed to be valid through-out the lifetime of this instance.
-  InfoMap* const info_map_;
   ExtensionPrefs* const prefs_;
   ExtensionRegistry* const extension_registry_;
   WarningService* const warning_service_;
 
   content::BrowserContext* const context_;
 
+  declarative_net_request::RulesetManager ruleset_manager_;
+
   // Must be the last member variable. See WeakPtrFactory documentation for
   // details.
   base::WeakPtrFactory<RulesMonitorService> weak_factory_{this};
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index f843c013..49c8521 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -19,9 +19,11 @@
 #include "extensions/browser/api/declarative_net_request/constants.h"
 #include "extensions/browser/api/declarative_net_request/utils.h"
 #include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "extensions/browser/api/web_request/web_request_permissions.h"
-#include "extensions/browser/info_map.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/common/api/declarative_net_request.h"
 #include "extensions/common/api/declarative_net_request/utils.h"
 #include "extensions/common/constants.h"
@@ -224,8 +226,11 @@
 RulesetManager::Action::Action(Action&&) = default;
 RulesetManager::Action& RulesetManager::Action::operator=(Action&&) = default;
 
-RulesetManager::RulesetManager(const InfoMap* info_map) : info_map_(info_map) {
-  DCHECK(info_map_);
+RulesetManager::RulesetManager(content::BrowserContext* browser_context)
+    : browser_context_(browser_context),
+      prefs_(ExtensionPrefs::Get(browser_context)),
+      permission_helper_(PermissionHelper::Get(browser_context)) {
+  DCHECK(browser_context_);
 
   // RulesetManager can be created on any sequence.
   DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -243,7 +248,7 @@
 
   bool inserted;
   std::tie(std::ignore, inserted) =
-      rulesets_.emplace(extension_id, info_map_->GetInstallTime(extension_id),
+      rulesets_.emplace(extension_id, prefs_->GetInstallTime(extension_id),
                         std::move(matcher), std::move(allowed_pages));
   DCHECK(inserted) << "AddRuleset called twice in succession for "
                    << extension_id;
@@ -428,7 +433,7 @@
   // redirect url.
   for (const ExtensionRulesetData* ruleset : rulesets) {
     PageAccess page_access = WebRequestPermissions::CanExtensionAccessURL(
-        info_map_, ruleset->extension_id, request.url, tab_id,
+        permission_helper_, ruleset->extension_id, request.url, tab_id,
         crosses_incognito,
         WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR,
         request.initiator, request.type);
@@ -511,9 +516,9 @@
     // DO_NOT_CHECK_HOST is strictly less restrictive than
     // REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR.
     PageAccess page_access = WebRequestPermissions::CanExtensionAccessURL(
-        info_map_, ruleset.extension_id, request.url, tab_id, crosses_incognito,
-        WebRequestPermissions::DO_NOT_CHECK_HOST, request.initiator,
-        request.type);
+        permission_helper_, ruleset.extension_id, request.url, tab_id,
+        crosses_incognito, WebRequestPermissions::DO_NOT_CHECK_HOST,
+        request.initiator, request.type);
     DCHECK_NE(PageAccess::kWithheld, page_access);
     if (page_access != PageAccess::kAllowed)
       continue;
@@ -549,7 +554,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Ensure clients filter out sensitive requests.
-  DCHECK(!WebRequestPermissions::HideRequest(info_map_, request));
+  DCHECK(!WebRequestPermissions::HideRequest(permission_helper_, request));
 
   if (!IsAPIAvailable()) {
     DCHECK(rulesets_.empty());
@@ -573,7 +578,7 @@
   // Only extensions enabled in incognito should have access to requests in an
   // incognito context.
   if (is_incognito_context &&
-      !info_map_->IsIncognitoEnabled(ruleset.extension_id)) {
+      !util::IsIncognitoEnabled(ruleset.extension_id, browser_context_)) {
     return false;
   }
 
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.h b/extensions/browser/api/declarative_net_request/ruleset_manager.h
index d63ff0f..652fe90 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.h
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.h
@@ -20,8 +20,13 @@
 #include "extensions/common/url_pattern_set.h"
 #include "url/gurl.h"
 
+namespace content {
+class BrowserContext;
+}
+
 namespace extensions {
-class InfoMap;
+class ExtensionPrefs;
+class PermissionHelper;
 struct WebRequestInfo;
 
 namespace declarative_net_request {
@@ -64,7 +69,7 @@
     DISALLOW_COPY_AND_ASSIGN(Action);
   };
 
-  explicit RulesetManager(const InfoMap* info_map);
+  explicit RulesetManager(content::BrowserContext* browser_context);
   ~RulesetManager();
 
   // An observer used for testing purposes.
@@ -172,8 +177,12 @@
   // small.
   base::flat_set<ExtensionRulesetData> rulesets_;
 
-  // Non-owning pointer to InfoMap. Owns us.
-  const InfoMap* const info_map_;
+  // Non-owning pointer to BrowserContext.
+  content::BrowserContext* const browser_context_;
+
+  // Guaranteed to be valid through-out the lifetime of this instance.
+  ExtensionPrefs* const prefs_;
+  PermissionHelper* const permission_helper_;
 
   // Non-owning pointer to TestObserver.
   TestObserver* test_observer_ = nullptr;
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_action.cc b/extensions/browser/api/declarative_webrequest/webrequest_action.cc
index 76964c9..8f4bd447 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_action.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_action.cc
@@ -24,7 +24,6 @@
 #include "extensions/browser/api/web_request/web_request_permissions.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -470,14 +469,14 @@
 
 bool WebRequestAction::HasPermission(ApplyInfo* apply_info,
                                      const std::string& extension_id) const {
-  const InfoMap* extension_info_map = apply_info->extension_info_map;
+  PermissionHelper* permission_helper = apply_info->permission_helper;
   const WebRequestInfo* request = apply_info->request_data.request;
-  if (WebRequestPermissions::HideRequest(extension_info_map, *request))
+  if (WebRequestPermissions::HideRequest(permission_helper, *request))
     return false;
 
-  // In unit tests we don't have an extension_info_map object here and skip host
+  // In unit tests we don't have a permission_helper object here and skip host
   // permission checks.
-  if (!extension_info_map)
+  if (!permission_helper)
     return true;
 
   // The embedder can always access all hosts from within a <webview>.
@@ -499,7 +498,7 @@
   }
   // TODO(devlin): Pass in the real tab id here.
   return WebRequestPermissions::CanExtensionAccessURL(
-             extension_info_map, extension_id, request->url, -1,
+             permission_helper, extension_id, request->url, -1,
              apply_info->crosses_incognito, permission_check,
              request->initiator,
              request->type) == PermissionsData::PageAccess::kAllowed;
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_action.h b/extensions/browser/api/declarative_webrequest/webrequest_action.h
index 26fc9d0..17cd7f9 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_action.h
+++ b/extensions/browser/api/declarative_webrequest/webrequest_action.h
@@ -31,7 +31,7 @@
 
 namespace extensions {
 class Extension;
-class InfoMap;
+class PermissionHelper;
 struct WebRequestData;
 }
 
@@ -77,7 +77,7 @@
   // essentially a parameter pack, so the pointers refer to local structures of
   // whatever function is calling one of those methods.
   struct ApplyInfo {
-    const InfoMap* extension_info_map;
+    PermissionHelper* permission_helper;
     const WebRequestData& request_data;
     bool crosses_incognito;
     // Modified by each applied action:
@@ -112,7 +112,7 @@
   // Returns whether the specified extension has permission to execute this
   // action on |request|. Checks the host permission if the host permissions
   // strategy is STRATEGY_DEFAULT.
-  // |apply_info->extension_info_map| may only be NULL for during testing, in
+  // |apply_info->permission_helper| may only be nullptr for during testing, in
   // which case host permissions are ignored. |crosses_incognito| specifies
   // whether the request comes from a different profile than |extension_id|
   // but was processed because the extension is in spanning mode.
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
index 5164d53..733492e3 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
@@ -17,6 +17,8 @@
 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "extensions/browser/api/web_request/web_request_permissions.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension.h"
@@ -44,13 +46,10 @@
     int rules_registry_id)
     : RulesRegistry(browser_context,
                     declarative_webrequest_constants::kOnRequest,
-                    content::BrowserThread::IO,
+                    content::BrowserThread::UI,
                     cache_delegate,
                     rules_registry_id),
-      browser_context_(browser_context) {
-  if (browser_context_)
-    extension_info_map_ = ExtensionSystem::Get(browser_context_)->info_map();
-}
+      browser_context_(browser_context) {}
 
 std::set<const WebRequestRule*> WebRequestRulesRegistry::GetMatches(
     const WebRequestData& request_data_without_ids) const {
@@ -78,7 +77,7 @@
 }
 
 std::list<extension_web_request_api_helpers::EventResponseDelta>
-WebRequestRulesRegistry::CreateDeltas(const InfoMap* extension_info_map,
+WebRequestRulesRegistry::CreateDeltas(PermissionHelper* permission_helper,
                                       const WebRequestData& request_data,
                                       bool crosses_incognito) {
   if (webrequest_rules_.empty())
@@ -135,10 +134,9 @@
 
     std::list<extension_web_request_api_helpers::EventResponseDelta>
         rule_result;
-    WebRequestAction::ApplyInfo apply_info = {
-      extension_info_map, request_data, crosses_incognito, &rule_result,
-      &ignore_tags[extension_id]
-    };
+    WebRequestAction::ApplyInfo apply_info = {permission_helper, request_data,
+                                              crosses_incognito, &rule_result,
+                                              &ignore_tags[extension_id]};
     rule->Apply(&apply_info);
     result.splice(result.begin(), std::move(rule_result));
 
@@ -159,8 +157,9 @@
   std::string error;
   RulesVector new_webrequest_rules;
   new_webrequest_rules.reserve(rules.size());
-  const Extension* extension =
-      extension_info_map_->extensions().GetByID(extension_id);
+  const Extension* extension = ExtensionRegistry::Get(browser_context_)
+                                   ->enabled_extensions()
+                                   .GetByID(extension_id);
   RulesMap& registered_rules = webrequest_rules_[extension_id];
 
   for (auto* rule : rules) {
@@ -292,7 +291,7 @@
 
 base::Time WebRequestRulesRegistry::GetExtensionInstallationTime(
     const std::string& extension_id) const {
-  return extension_info_map_->GetInstallTime(extension_id);
+  return ExtensionPrefs::Get(browser_context_)->GetInstallTime(extension_id);
 }
 
 void WebRequestRulesRegistry::ClearCacheOnNavigation() {
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h
index 345a1b0..53c7c4b3 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h
+++ b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h
@@ -22,7 +22,6 @@
 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_action.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/common/extension_id.h"
 
 namespace content {
@@ -34,6 +33,7 @@
 }
 
 namespace extensions {
+class PermissionHelper;
 
 using WebRequestRule = DeclarativeRule<WebRequestCondition, WebRequestAction>;
 
@@ -81,7 +81,7 @@
   // Returns which modifications should be executed on the network request
   // according to the rules registered in this registry.
   std::list<extension_web_request_api_helpers::EventResponseDelta> CreateDeltas(
-      const InfoMap* extension_info_map,
+      PermissionHelper* permission_helper,
       const WebRequestData& request_data,
       bool crosses_incognito);
 
@@ -105,11 +105,6 @@
       const std::string& extension_id) const;
   virtual void ClearCacheOnNavigation();
 
-  void SetExtensionInfoMapForTesting(
-      scoped_refptr<InfoMap> extension_info_map) {
-    extension_info_map_ = extension_info_map;
-  }
-
   const std::set<const WebRequestRule*>&
   rules_with_untriggered_conditions_for_test() const {
     return rules_with_untriggered_conditions_;
@@ -177,7 +172,6 @@
   url_matcher::URLMatcher url_matcher_;
 
   content::BrowserContext* browser_context_;
-  scoped_refptr<InfoMap> extension_info_map_;
 
   DISALLOW_COPY_AND_ASSIGN(WebRequestRulesRegistry);
 };
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index 313465b..bac64cb 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -44,6 +44,7 @@
 }
 
 bool ExtensionsAPIClient::ShouldHideBrowserNetworkRequest(
+    content::BrowserContext* context,
     const WebRequestInfo& request) const {
   return false;
 }
@@ -160,4 +161,9 @@
   return nullptr;
 }
 
+std::vector<KeyedServiceBaseFactory*>
+ExtensionsAPIClient::GetFactoryDependencies() {
+  return {};
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index dd4f2bfa..1b6021c 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -98,8 +98,9 @@
                                         const std::string& header_name) const;
 
   // Returns true if the given |request| should be hidden from extensions. This
-  // should be invoked on the IO thread.
+  // should be invoked on the UI thread.
   virtual bool ShouldHideBrowserNetworkRequest(
+      content::BrowserContext* context,
       const WebRequestInfo& request) const;
 
   // Notifies that an extension failed to act on a network request because the
@@ -193,6 +194,10 @@
 
   virtual AutomationInternalApiDelegate* GetAutomationInternalApiDelegate();
 
+  // Gets keyed service factories that are used in the other methods on this
+  // class.
+  virtual std::vector<KeyedServiceBaseFactory*> GetFactoryDependencies();
+
   // NOTE: If this interface gains too many methods (perhaps more than 20) it
   // should be split into one interface per API.
 };
diff --git a/extensions/browser/api/web_request/BUILD.gn b/extensions/browser/api/web_request/BUILD.gn
index 8b67cc3..ce65fc5 100644
--- a/extensions/browser/api/web_request/BUILD.gn
+++ b/extensions/browser/api/web_request/BUILD.gn
@@ -11,6 +11,8 @@
   sources = [
     "form_data_parser.cc",
     "form_data_parser.h",
+    "permission_helper.cc",
+    "permission_helper.h",
     "upload_data_presenter.cc",
     "upload_data_presenter.h",
     "web_request_api.cc",
diff --git a/extensions/browser/api/web_request/permission_helper.cc b/extensions/browser/api/web_request/permission_helper.cc
new file mode 100644
index 0000000..39587f9
--- /dev/null
+++ b/extensions/browser/api/web_request/permission_helper.cc
@@ -0,0 +1,59 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/web_request/permission_helper.h"
+
+#include "base/no_destructor.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_registry_factory.h"
+#include "extensions/browser/extension_util.h"
+#include "extensions/browser/process_map_factory.h"
+
+namespace extensions {
+
+PermissionHelper::PermissionHelper(content::BrowserContext* context)
+    : browser_context_(context),
+      process_map_(ProcessMap::Get(context)),
+      extension_registry_(ExtensionRegistry::Get(context)) {}
+
+PermissionHelper::~PermissionHelper() {}
+
+// static
+PermissionHelper* PermissionHelper::Get(content::BrowserContext* context) {
+  return BrowserContextKeyedAPIFactory<PermissionHelper>::Get(context);
+}
+
+// static
+BrowserContextKeyedAPIFactory<PermissionHelper>*
+PermissionHelper::GetFactoryInstance() {
+  static base::NoDestructor<BrowserContextKeyedAPIFactory<PermissionHelper>>
+      instance;
+  return instance.get();
+}
+
+bool PermissionHelper::ShouldHideBrowserNetworkRequest(
+    const WebRequestInfo& request) const {
+  return ExtensionsAPIClient::Get()->ShouldHideBrowserNetworkRequest(
+      browser_context_, request);
+}
+
+bool PermissionHelper::CanCrossIncognito(const Extension* extension) const {
+  return extensions::util::CanCrossIncognito(extension, browser_context_);
+}
+
+template <>
+void BrowserContextKeyedAPIFactory<
+    PermissionHelper>::DeclareFactoryDependencies() {
+  DependsOn(ExtensionRegistryFactory::GetInstance());
+  DependsOn(ProcessMapFactory::GetInstance());
+  // Used in CanCrossIncognito().
+  DependsOn(ExtensionPrefsFactory::GetInstance());
+  // For ShouldHideBrowserNetworkRequest().
+  for (auto* factory : ExtensionsAPIClient::Get()->GetFactoryDependencies())
+    DependsOn(factory);
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/web_request/permission_helper.h b/extensions/browser/api/web_request/permission_helper.h
new file mode 100644
index 0000000..acebbcd
--- /dev/null
+++ b/extensions/browser/api/web_request/permission_helper.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_WEB_REQUEST_PERMISSION_HELPER_H_
+#define EXTENSIONS_BROWSER_API_WEB_REQUEST_PERMISSION_HELPER_H_
+
+#include "base/macros.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+
+namespace extensions {
+class ExtensionRegistry;
+class ProcessMap;
+struct WebRequestInfo;
+
+// Intermediate keyed service used to declare dependencies on other services
+// that are needed for WebRequest permissions.
+class PermissionHelper : public BrowserContextKeyedAPI {
+ public:
+  explicit PermissionHelper(content::BrowserContext* context);
+  ~PermissionHelper() override;
+
+  // Convenience method to get the PermissionHelper for a profile.
+  static PermissionHelper* Get(content::BrowserContext* context);
+
+  // BrowserContextKeyedAPI implementation.
+  static BrowserContextKeyedAPIFactory<PermissionHelper>* GetFactoryInstance();
+
+  bool ShouldHideBrowserNetworkRequest(const WebRequestInfo& request) const;
+  bool CanCrossIncognito(const Extension* extension) const;
+
+  const ProcessMap* process_map() const { return process_map_; }
+
+  const ExtensionRegistry* extension_registry() const {
+    return extension_registry_;
+  }
+
+ private:
+  friend class BrowserContextKeyedAPIFactory<PermissionHelper>;
+
+  content::BrowserContext* const browser_context_;
+  ProcessMap* const process_map_;
+  ExtensionRegistry* const extension_registry_;
+
+  // BrowserContextKeyedAPI implementation.
+  static const char* service_name() { return "PermissionHelper"; }
+  static const bool kServiceRedirectedInIncognito = true;
+
+  DISALLOW_COPY_AND_ASSIGN(PermissionHelper);
+};
+
+template <>
+void BrowserContextKeyedAPIFactory<
+    PermissionHelper>::DeclareFactoryDependencies();
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_WEB_REQUEST_PERMISSION_HELPER_H_
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 9316bb1..43bdedc 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -30,7 +30,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_context.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
@@ -39,11 +38,13 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/api/activity_log/web_request_constants.h"
 #include "extensions/browser/api/declarative/rules_registry_service.h"
+#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
 #include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
 #include "extensions/browser/api/web_request/web_request_event_details.h"
@@ -63,7 +64,6 @@
 #include "extensions/browser/guest_view/guest_view_events.h"
 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/browser/io_thread_extension_message_filter.h"
 #include "extensions/browser/runtime_data.h"
 #include "extensions/browser/warning_service.h"
@@ -152,10 +152,6 @@
     keys::kOnCompletedEvent,
 };
 
-// User data key for WebRequestAPI::ProxySet.
-const void* const kWebRequestProxySetUserDataKey =
-    &kWebRequestProxySetUserDataKey;
-
 const char* GetRequestStageAsString(
     ExtensionWebRequestEventRouter::EventTypes type) {
   switch (type) {
@@ -204,19 +200,15 @@
                    web_request_event_name) != web_request_events_end;
 }
 
-// Returns whether |request| has been triggered by an extension in
-// |extension_info_map|.
+// Returns whether |request| has been triggered by an extension enabled in
+// |context|.
 bool IsRequestFromExtension(const WebRequestInfo& request,
-                            const InfoMap* extension_info_map) {
+                            content::BrowserContext* context) {
   if (request.render_process_id == -1)
     return false;
 
-  // |extension_info_map| is NULL for system-level requests.
-  if (!extension_info_map)
-    return false;
-
   const std::set<std::string> extension_ids =
-      extension_info_map->process_map().GetExtensionsInProcess(
+      ProcessMap::Get(context)->GetExtensionsInProcess(
           request.render_process_id);
   if (extension_ids.empty())
     return false;
@@ -224,7 +216,8 @@
   // Treat hosted apps as normal web pages (crbug.com/526413).
   for (const std::string& extension_id : extension_ids) {
     const Extension* extension =
-        extension_info_map->extensions().GetByID(extension_id);
+        ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
+            extension_id);
     if (extension && !extension->is_hosted_app())
       return true;
   }
@@ -269,15 +262,13 @@
 // |web_view_instance_id| is a valid if |is_web_view_guest| is true.
 // |event_details| is passed to the event listener.
 void SendOnMessageEventOnUI(
-    void* browser_context_id,
+    content::BrowserContext* browser_context,
     const std::string& extension_id,
     bool is_web_view_guest,
     int web_view_instance_id,
     std::unique_ptr<WebRequestEventDetails> event_details) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  content::BrowserContext* browser_context =
-      reinterpret_cast<content::BrowserContext*>(browser_context_id);
   if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
     return;
 
@@ -311,13 +302,11 @@
 
 // Helper to dispatch the "onActionIgnored" event.
 void NotifyIgnoredActionsOnUI(
-    void* browser_context_id,
+    content::BrowserContext* browser_context,
     uint64_t request_id,
     extension_web_request_api_helpers::IgnoredActions ignored_actions) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  content::BrowserContext* browser_context =
-      reinterpret_cast<content::BrowserContext*>(browser_context_id);
   if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
     return;
 
@@ -378,11 +367,11 @@
 }
 
 // We hide events from the system context as well as sensitive requests.
-bool ShouldHideEvent(void* browser_context,
-                     const InfoMap* extension_info_map,
+bool ShouldHideEvent(content::BrowserContext* browser_context,
                      const WebRequestInfo& request) {
   return (!browser_context ||
-          WebRequestPermissions::HideRequest(extension_info_map, request));
+          WebRequestPermissions::HideRequest(
+              PermissionHelper::Get(browser_context), request));
 }
 
 // Returns true if we're in a Public Session and restrictions are enabled.
@@ -402,19 +391,6 @@
   return std::make_unique<WebRequestEventDetails>(request, extra_info_spec);
 }
 
-void MaybeProxyAuthRequestOnIO(
-    content::ResourceContext* resource_context,
-    const net::AuthChallengeInfo& auth_info,
-    scoped_refptr<net::HttpResponseHeaders> response_headers,
-    const content::GlobalRequestID& request_id,
-    WebRequestAPI::AuthRequestCallback callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  auto* proxies =
-      WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
-  proxies->MaybeProxyAuthRequest(auth_info, std::move(response_headers),
-                                 request_id, std::move(callback));
-}
-
 // Checks whether the extension has any permissions that would use the web
 // request API.
 bool HasAnyWebRequestPermissions(const Extension* extension) {
@@ -511,37 +487,27 @@
     int32_t request_id,
     AuthRequestCallback callback) {
   // Default implementation cancels the request.
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(std::move(callback), base::nullopt,
-                                          false /* should_cancel */));
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), base::nullopt,
+                                false /* should_cancel */));
 }
 
 WebRequestAPI::ProxySet::ProxySet() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 WebRequestAPI::ProxySet::~ProxySet() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
-
-WebRequestAPI::ProxySet* WebRequestAPI::ProxySet::GetFromResourceContext(
-    content::ResourceContext* resource_context) {
-  if (!resource_context->GetUserData(kWebRequestProxySetUserDataKey)) {
-    resource_context->SetUserData(kWebRequestProxySetUserDataKey,
-                                  std::make_unique<WebRequestAPI::ProxySet>());
-  }
-  return static_cast<WebRequestAPI::ProxySet*>(
-      resource_context->GetUserData(kWebRequestProxySetUserDataKey));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void WebRequestAPI::ProxySet::AddProxy(std::unique_ptr<Proxy> proxy) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   proxies_.insert(std::move(proxy));
 }
 
 void WebRequestAPI::ProxySet::RemoveProxy(Proxy* proxy) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   auto requests_it = proxy_to_request_id_map_.find(proxy);
   if (requests_it != proxy_to_request_id_map_.end()) {
@@ -591,15 +557,14 @@
     scoped_refptr<net::HttpResponseHeaders> response_headers,
     const content::GlobalRequestID& request_id,
     AuthRequestCallback callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   Proxy* proxy = GetProxyFromRequestId(request_id);
   if (!proxy) {
-    // The request=>proxy map is maintained on the IO thread so it is not an
-    // error to get here and have no proxy. In this situation run the |callback|
-    // which will display a dialog for the user to enter their auth credentials.
-    base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                             base::BindOnce(std::move(callback), base::nullopt,
-                                            false /* should_cancel */));
+    // Run the |callback| which will display a dialog for the user to enter
+    // their auth credentials.
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), base::nullopt,
+                                  false /* should_cancel */));
     return;
   }
 
@@ -609,8 +574,8 @@
 
 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
     : browser_context_(context),
-      info_map_(ExtensionSystem::Get(browser_context_)->info_map()),
       request_id_generator_(base::MakeRefCounted<RequestIDGenerator>()),
+      proxies_(std::make_unique<ProxySet>()),
       may_have_proxies_(MayHaveProxies()) {
   EventRouter* event_router = EventRouter::Get(browser_context_);
   for (size_t i = 0; i < base::size(kWebRequestEvents); ++i) {
@@ -630,6 +595,7 @@
 }
 
 void WebRequestAPI::Shutdown() {
+  proxies_.reset();
   EventRouter::Get(browser_context_)->UnregisterObserver(this);
   extensions::ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
 }
@@ -658,10 +624,12 @@
       details.browser_context, details.extension_id, details.event_name, 0, 0,
       details.worker_thread_id, details.service_worker_version_id);
 
+  // This PostTask is necessary even though we are already on the UI thread to
+  // allow cases where blocking listeners remove themselves inside the handler.
   // This Unretained is safe because the ExtensionWebRequestEventRouter
   // singleton is leaked.
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
       base::BindOnce(
           &ExtensionWebRequestEventRouter::RemoveEventListener,
           base::Unretained(ExtensionWebRequestEventRouter::GetInstance()), id,
@@ -727,17 +695,14 @@
          (browser_context->IsOffTheRecord() &&
           ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context) ==
               browser_context_));
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&WebRequestProxyingURLLoaderFactory::StartProxying,
-                     browser_context, browser_context->GetResourceContext(),
-                     // Match the behavior of the WebRequestInfo constructor
-                     // which takes a net::URLRequest*.
-                     is_navigation ? -1 : render_process_id, is_download,
-                     request_id_generator_, std::move(navigation_ui_data),
-                     base::Unretained(info_map_), std::move(proxied_request),
-                     std::move(target_factory_info),
-                     std::move(header_client_request)));
+  WebRequestProxyingURLLoaderFactory::StartProxying(
+      browser_context,
+      // Match the behavior of the WebRequestInfo constructor
+      // which takes a net::URLRequest*.
+      is_navigation ? -1 : render_process_id, is_download,
+      request_id_generator_, std::move(navigation_ui_data),
+      std::move(proxied_request), std::move(target_factory_info),
+      std::move(header_client_request), proxies_.get());
   return true;
 }
 
@@ -762,12 +727,8 @@
          (browser_context->IsOffTheRecord() &&
           ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context) ==
               browser_context_));
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&MaybeProxyAuthRequestOnIO,
-                     browser_context->GetResourceContext(), auth_info,
-                     std::move(response_headers), proxied_request_id,
-                     std::move(callback)));
+  proxies_->MaybeProxyAuthRequest(auth_info, std::move(response_headers),
+                                  proxied_request_id, std::move(callback));
   return true;
 }
 
@@ -782,21 +743,15 @@
   DCHECK(MayHaveProxies());
 
   const bool has_extra_headers =
-      ExtensionWebRequestEventRouter::GetInstance()
-          ->HasAnyExtraHeadersListenerOnUI(
-              frame->GetProcess()->GetBrowserContext());
+      ExtensionWebRequestEventRouter::GetInstance()->HasAnyExtraHeadersListener(
+          frame->GetProcess()->GetBrowserContext());
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(
-          &WebRequestProxyingWebSocket::StartProxying, std::move(factory), url,
-          site_for_cookies, user_agent, handshake_client.PassInterface(),
-          has_extra_headers, frame->GetProcess()->GetID(),
-          frame->GetRoutingID(), request_id_generator_,
-          frame->GetLastCommittedOrigin(),
-          frame->GetProcess()->GetBrowserContext(),
-          frame->GetProcess()->GetBrowserContext()->GetResourceContext(),
-          base::Unretained(info_map_)));
+  WebRequestProxyingWebSocket::StartProxying(
+      std::move(factory), url, site_for_cookies, user_agent,
+      handshake_client.PassInterface(), has_extra_headers,
+      frame->GetProcess()->GetID(), frame->GetRoutingID(),
+      request_id_generator_, frame->GetLastCommittedOrigin(),
+      frame->GetProcess()->GetBrowserContext(), proxies_.get());
 }
 
 void WebRequestAPI::ForceProxyForTesting() {
@@ -910,10 +865,6 @@
 
   // Changes requested by extensions.
   helpers::EventResponseDeltas response_deltas;
-
-  // Provider of meta data about extensions, only used and non-NULL for events
-  // that are delayed until the rules registry is ready.
-  const InfoMap* extension_info_map = nullptr;
 };
 
 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
@@ -1010,7 +961,7 @@
 }
 
 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     int rules_registry_id,
     scoped_refptr<WebRequestRulesRegistry> rules_registry) {
   RulesRegistryKey key(browser_context, rules_registry_id);
@@ -1021,8 +972,7 @@
 }
 
 int ExtensionWebRequestEventRouter::OnBeforeRequest(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     WebRequestInfo* request,
     net::CompletionOnceCallback callback,
     GURL* new_url,
@@ -1031,7 +981,7 @@
 
   DCHECK(should_collapse_initiator);
 
-  if (ShouldHideEvent(browser_context, extension_info_map, *request)) {
+  if (ShouldHideEvent(browser_context, *request)) {
     request->dnr_action.emplace(Action::Type::NONE);
     return net::OK;
   }
@@ -1048,8 +998,7 @@
   }
   request_time_tracker_->LogRequestStartTime(
       request->id, base::TimeTicks::Now(), has_listener,
-      HasExtraHeadersListenerForRequest(browser_context, extension_info_map,
-                                        request));
+      HasExtraHeadersListenerForRequest(browser_context, request));
 
   const bool is_incognito_context = IsIncognitoBrowserContext(browser_context);
 
@@ -1059,55 +1008,49 @@
   // request url, initiator and resource type, which should stay the same during
   // the diffierent network request stages. A redirect should cause another
   // OnBeforeRequest call.
-  // |extension_info_map| is null for system level requests.
-  if (extension_info_map) {
-    const Action& action =
-        extension_info_map->GetRulesetManager()->EvaluateRequest(
-            *request, is_incognito_context);
-    switch (action.type) {
-      case Action::Type::NONE:
-        break;
-      case Action::Type::BLOCK:
-        return net::ERR_BLOCKED_BY_CLIENT;
-      case Action::Type::COLLAPSE:
-        *should_collapse_initiator = true;
-        return net::ERR_BLOCKED_BY_CLIENT;
-      case Action::Type::REDIRECT:
-        DCHECK(action.redirect_url);
-        *new_url = action.redirect_url.value();
-        return net::OK;
-      case Action::Type::REMOVE_HEADERS:
-        // Unlike other actions, allow web request extensions to intercept the
-        // request here. The headers will be removed during subsequent request
-        // stages.
-        DCHECK(request->dnr_action.has_value());
-        DCHECK_EQ(request->dnr_action->type, Action::Type::REMOVE_HEADERS);
-        break;
-    }
-  } else {
-    request->dnr_action.emplace(Action::Type::NONE);
+  const Action& action =
+      declarative_net_request::RulesMonitorService::Get(browser_context)
+          ->ruleset_manager()
+          ->EvaluateRequest(*request, is_incognito_context);
+  switch (action.type) {
+    case Action::Type::NONE:
+      break;
+    case Action::Type::BLOCK:
+      return net::ERR_BLOCKED_BY_CLIENT;
+    case Action::Type::COLLAPSE:
+      *should_collapse_initiator = true;
+      return net::ERR_BLOCKED_BY_CLIENT;
+    case Action::Type::REDIRECT:
+      DCHECK(action.redirect_url);
+      *new_url = action.redirect_url.value();
+      return net::OK;
+    case Action::Type::REMOVE_HEADERS:
+      // Unlike other actions, allow web request extensions to intercept the
+      // request here. The headers will be removed during subsequent request
+      // stages.
+      DCHECK(request->dnr_action.has_value());
+      DCHECK_EQ(request->dnr_action->type, Action::Type::REMOVE_HEADERS);
+      break;
   }
 
   // Whether to initialized |blocked_requests_|.
   bool initialize_blocked_requests = false;
 
-  initialize_blocked_requests |=
-      ProcessDeclarativeRules(browser_context, extension_info_map,
-                              web_request::OnBeforeRequest::kEventName, request,
-                              ON_BEFORE_REQUEST, nullptr);
+  initialize_blocked_requests |= ProcessDeclarativeRules(
+      browser_context, web_request::OnBeforeRequest::kEventName, request,
+      ON_BEFORE_REQUEST, nullptr);
 
   int extra_info_spec = 0;
   RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map,
-      web_request::OnBeforeRequest::kEventName, request, &extra_info_spec);
+      browser_context, web_request::OnBeforeRequest::kEventName, request,
+      &extra_info_spec);
   if (!listeners.empty() && !GetAndSetSignaled(request->id, kOnBeforeRequest)) {
     std::unique_ptr<WebRequestEventDetails> event_details(
         CreateEventDetails(*request, extra_info_spec));
     event_details->SetRequestBody(request);
 
-    initialize_blocked_requests |=
-        DispatchEvent(browser_context, extension_info_map, request, listeners,
-                      std::move(event_details));
+    initialize_blocked_requests |= DispatchEvent(
+        browser_context, request, listeners, std::move(event_details));
   }
 
   if (!initialize_blocked_requests)
@@ -1129,12 +1072,11 @@
 }
 
 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     BeforeSendHeadersCallback callback,
     net::HttpRequestHeaders* headers) {
-  if (ShouldHideEvent(browser_context, extension_info_map, *request))
+  if (ShouldHideEvent(browser_context, *request))
     return net::OK;
 
   // Remove request headers for the Declarative Net Request API. It is given
@@ -1154,23 +1096,22 @@
 
   bool initialize_blocked_requests = false;
 
-  initialize_blocked_requests |= ProcessDeclarativeRules(
-      browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
-      request, ON_BEFORE_SEND_HEADERS, NULL);
+  initialize_blocked_requests |=
+      ProcessDeclarativeRules(browser_context, keys::kOnBeforeSendHeadersEvent,
+                              request, ON_BEFORE_SEND_HEADERS, nullptr);
 
   int extra_info_spec = 0;
-  RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
-      request, &extra_info_spec);
+  RawListeners listeners =
+      GetMatchingListeners(browser_context, keys::kOnBeforeSendHeadersEvent,
+                           request, &extra_info_spec);
   if (!listeners.empty() &&
       !GetAndSetSignaled(request->id, kOnBeforeSendHeaders)) {
     std::unique_ptr<WebRequestEventDetails> event_details(
         CreateEventDetails(*request, extra_info_spec));
     event_details->SetRequestHeaders(*headers);
 
-    initialize_blocked_requests |=
-        DispatchEvent(browser_context, extension_info_map, request, listeners,
-                      std::move(event_details));
+    initialize_blocked_requests |= DispatchEvent(
+        browser_context, request, listeners, std::move(event_details));
   }
 
   UMA_HISTOGRAM_ENUMERATION(
@@ -1198,11 +1139,10 @@
 }
 
 void ExtensionWebRequestEventRouter::OnSendHeaders(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     const net::HttpRequestHeaders& headers) {
-  if (ShouldHideEvent(browser_context, extension_info_map, *request))
+  if (ShouldHideEvent(browser_context, *request))
     return;
 
   if (GetAndSetSignaled(request->id, kOnSendHeaders))
@@ -1212,8 +1152,7 @@
 
   int extra_info_spec = 0;
   RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map, keys::kOnSendHeadersEvent, request,
-      &extra_info_spec);
+      browser_context, keys::kOnSendHeadersEvent, request, &extra_info_spec);
   if (listeners.empty())
     return;
 
@@ -1221,19 +1160,17 @@
       CreateEventDetails(*request, extra_info_spec));
   event_details->SetRequestHeaders(headers);
 
-  DispatchEvent(browser_context, extension_info_map, request, listeners,
-                std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, std::move(event_details));
 }
 
 int ExtensionWebRequestEventRouter::OnHeadersReceived(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     net::CompletionOnceCallback callback,
     const net::HttpResponseHeaders* original_response_headers,
     scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
     GURL* allowed_unsafe_redirect_url) {
-  if (ShouldHideEvent(browser_context, extension_info_map, *request))
+  if (ShouldHideEvent(browser_context, *request))
     return net::OK;
 
   // Handle header removal by the Declarative Net Request API. We filter these
@@ -1255,13 +1192,13 @@
   bool initialize_blocked_requests = false;
 
   initialize_blocked_requests |= ProcessDeclarativeRules(
-      browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
-      request, ON_HEADERS_RECEIVED, filtered_response_headers.get());
+      browser_context, keys::kOnHeadersReceivedEvent, request,
+      ON_HEADERS_RECEIVED, filtered_response_headers.get());
 
   int extra_info_spec = 0;
-  RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
-      request, &extra_info_spec);
+  RawListeners listeners =
+      GetMatchingListeners(browser_context, keys::kOnHeadersReceivedEvent,
+                           request, &extra_info_spec);
 
   if (!listeners.empty() &&
       !GetAndSetSignaled(request->id, kOnHeadersReceived)) {
@@ -1270,9 +1207,8 @@
     event_details->SetResponseHeaders(*request,
                                       filtered_response_headers.get());
 
-    initialize_blocked_requests |=
-        DispatchEvent(browser_context, extension_info_map, request, listeners,
-                      std::move(event_details));
+    initialize_blocked_requests |= DispatchEvent(
+        browser_context, request, listeners, std::move(event_details));
   }
 
   UMA_HISTOGRAM_ENUMERATION(
@@ -1302,8 +1238,7 @@
 
 net::NetworkDelegate::AuthRequiredResponse
 ExtensionWebRequestEventRouter::OnAuthRequired(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     const net::AuthChallengeInfo& auth_info,
     net::NetworkDelegate::AuthCallback callback,
@@ -1311,14 +1246,14 @@
   // No browser_context means that this is for authentication challenges in the
   // system context. Skip in that case. Also skip sensitive requests.
   if (!browser_context ||
-      WebRequestPermissions::HideRequest(extension_info_map, *request)) {
+      WebRequestPermissions::HideRequest(PermissionHelper::Get(browser_context),
+                                         *request)) {
     return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
   }
 
   int extra_info_spec = 0;
   RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map, keys::kOnAuthRequiredEvent, request,
-      &extra_info_spec);
+      browser_context, keys::kOnAuthRequiredEvent, request, &extra_info_spec);
   if (listeners.empty())
     return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
 
@@ -1327,7 +1262,7 @@
   event_details->SetResponseHeaders(*request, request->response_headers.get());
   event_details->SetAuthInfo(auth_info);
 
-  if (DispatchEvent(browser_context, extension_info_map, request, listeners,
+  if (DispatchEvent(browser_context, request, listeners,
                     std::move(event_details))) {
     BlockedRequest& blocked_request = blocked_requests_[request->id];
     blocked_request.event = kOnAuthRequired;
@@ -1341,11 +1276,10 @@
 }
 
 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     const GURL& new_location) {
-  if (ShouldHideEvent(browser_context, extension_info_map, *request))
+  if (ShouldHideEvent(browser_context, *request))
     return;
 
   if (GetAndSetSignaled(request->id, kOnBeforeRedirect))
@@ -1358,8 +1292,7 @@
 
   int extra_info_spec = 0;
   RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map, keys::kOnBeforeRedirectEvent,
-      request, &extra_info_spec);
+      browser_context, keys::kOnBeforeRedirectEvent, request, &extra_info_spec);
   if (listeners.empty())
     return;
 
@@ -1369,18 +1302,16 @@
   event_details->SetResponseSource(*request);
   event_details->SetString(keys::kRedirectUrlKey, new_location.spec());
 
-  DispatchEvent(browser_context, extension_info_map, request, listeners,
-                std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, std::move(event_details));
 }
 
 void ExtensionWebRequestEventRouter::OnResponseStarted(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     int net_error) {
   DCHECK_NE(net::ERR_IO_PENDING, net_error);
 
-  if (ShouldHideEvent(browser_context, extension_info_map, *request))
+  if (ShouldHideEvent(browser_context, *request))
     return;
 
   // OnResponseStarted is even triggered, when the request was cancelled.
@@ -1388,9 +1319,9 @@
     return;
 
   int extra_info_spec = 0;
-  RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map, keys::kOnResponseStartedEvent,
-      request, &extra_info_spec);
+  RawListeners listeners =
+      GetMatchingListeners(browser_context, keys::kOnResponseStartedEvent,
+                           request, &extra_info_spec);
   if (listeners.empty())
     return;
 
@@ -1399,13 +1330,11 @@
   event_details->SetResponseHeaders(*request, request->response_headers.get());
   event_details->SetResponseSource(*request);
 
-  DispatchEvent(browser_context, extension_info_map, request, listeners,
-                std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, std::move(event_details));
 }
 
 void ExtensionWebRequestEventRouter::OnCompleted(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     int net_error) {
   // We hide events from the system context as well as sensitive requests.
@@ -1413,7 +1342,8 @@
   // already signaled it and thus we have to signal the end of it. This is
   // risk-free because the handler cannot modify the request now.
   if (!browser_context ||
-      (WebRequestPermissions::HideRequest(extension_info_map, *request) &&
+      (WebRequestPermissions::HideRequest(
+           PermissionHelper::Get(browser_context), *request) &&
        !WasSignaled(*request))) {
     return;
   }
@@ -1428,9 +1358,8 @@
   ClearPendingCallbacks(*request);
 
   int extra_info_spec = 0;
-  RawListeners listeners =
-      GetMatchingListeners(browser_context, extension_info_map,
-                           keys::kOnCompletedEvent, request, &extra_info_spec);
+  RawListeners listeners = GetMatchingListeners(
+      browser_context, keys::kOnCompletedEvent, request, &extra_info_spec);
   if (listeners.empty())
     return;
 
@@ -1439,13 +1368,11 @@
   event_details->SetResponseHeaders(*request, request->response_headers.get());
   event_details->SetResponseSource(*request);
 
-  DispatchEvent(browser_context, extension_info_map, request, listeners,
-                std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, std::move(event_details));
 }
 
 void ExtensionWebRequestEventRouter::OnErrorOccurred(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     bool started,
     int net_error) {
@@ -1453,7 +1380,7 @@
   // ERR_WS_UPGRADE code (see WebSocketStreamRequestImpl::PerformUpgrade).
   // WebRequest API reports this as a completed request.
   if (net_error == net::ERR_WS_UPGRADE) {
-    OnCompleted(browser_context, extension_info_map, request, net_error);
+    OnCompleted(browser_context, request, net_error);
     return;
   }
 
@@ -1467,7 +1394,8 @@
   // already signaled it and thus we have to signal the end of it. This is
   // risk-free because the handler cannot modify the request now.
   if (!browser_context ||
-      (WebRequestPermissions::HideRequest(extension_info_map, *request) &&
+      (WebRequestPermissions::HideRequest(
+           PermissionHelper::Get(browser_context), *request) &&
        !WasSignaled(*request))) {
     return;
   }
@@ -1483,8 +1411,8 @@
 
   int extra_info_spec = 0;
   RawListeners listeners = GetMatchingListeners(
-      browser_context, extension_info_map,
-      web_request::OnErrorOccurred::kEventName, request, &extra_info_spec);
+      browser_context, web_request::OnErrorOccurred::kEventName, request,
+      &extra_info_spec);
   if (listeners.empty())
     return;
 
@@ -1496,17 +1424,15 @@
     event_details->SetBoolean(keys::kFromCache, request->response_from_cache);
   event_details->SetString(keys::kErrorKey, net::ErrorToString(net_error));
 
-  DispatchEvent(browser_context, extension_info_map, request, listeners,
-                std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, std::move(event_details));
 }
 
 void ExtensionWebRequestEventRouter::OnRequestWillBeDestroyed(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request) {
   ClearPendingCallbacks(*request);
   signaled_requests_.erase(request->id);
   request_time_tracker_->LogRequestEndTime(request->id, base::TimeTicks::Now());
-  pending_requests_for_frame_data_.erase(request);
 }
 
 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
@@ -1515,8 +1441,7 @@
 }
 
 bool ExtensionWebRequestEventRouter::DispatchEvent(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
     const RawListeners& listeners,
     std::unique_ptr<WebRequestEventDetails> event_details) {
@@ -1535,27 +1460,15 @@
     }
   }
 
-  if (request->frame_data) {
-    // We may already have FrameData if this is a browser-side navigation, or
-    // if the relevant FrameData was already cached on the IO thread at the time
-    // of request creation. In that case we can dispatch immediately.
-    event_details->SetFrameData(request->frame_data.value());
-    DispatchEventToListeners(browser_context, extension_info_map,
-                             std::move(listeners_to_dispatch),
-                             std::move(event_details));
-  } else {
-    // We don't have FrameData available yet, so fetch it asynchronously. This
-    // event will be dispatched once that operation completes. Unretained is
-    // safe here because the ExtensionWebRequestEventRouter singleton is leaked.
-    pending_requests_for_frame_data_.insert(request);
-    ExtensionApiFrameIdMap::Get()->GetFrameDataOnIO(
-        request->render_process_id, request->frame_id,
-        base::Bind(&ExtensionWebRequestEventRouter::OnFrameDataReceived,
-                   base::Unretained(this), browser_context, request,
-                   base::Passed(&event_details),
-                   base::RetainedRef(extension_info_map),
-                   base::Passed(&listeners_to_dispatch)));
+  // TODO(http://crbug.com/980774): Investigate if this is necessary.
+  if (!request->frame_data) {
+    content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
+        request->render_process_id, request->frame_id);
+    request->frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData(rfh);
   }
+  event_details->SetFrameData(request->frame_data.value());
+  DispatchEventToListeners(browser_context, std::move(listeners_to_dispatch),
+                           std::move(event_details));
 
   if (num_handlers_blocking > 0) {
     BlockedRequest& blocked_request = blocked_requests_[request->id];
@@ -1569,37 +1482,11 @@
   return false;
 }
 
-void ExtensionWebRequestEventRouter::OnFrameDataReceived(
-    void* browser_context,
-    const WebRequestInfo* request,
-    std::unique_ptr<WebRequestEventDetails> event_details,
-    const InfoMap* extension_info_map,
-    std::unique_ptr<ListenerIDs> listeners_to_dispatch,
-    const ExtensionApiFrameIdMap::FrameData& frame_data) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  // Store the |frame_data| in |request| so that the same frame_data can be
-  // persisted across the request lifetime. Requesting id every time isn't
-  // working if the frame host gets deleted during a request; see
-  // https://crbug.com/914232.
-  // Check with |pending_requests_for_frame_data_| to ensure that |request| is
-  // still alive.
-  if (pending_requests_for_frame_data_.count(request) > 0) {
-    request->frame_data = frame_data;
-    pending_requests_for_frame_data_.erase(request);
-  }
-  event_details->SetFrameData(frame_data);
-  DispatchEventToListeners(browser_context, extension_info_map,
-                           std::move(listeners_to_dispatch),
-                           std::move(event_details));
-}
-
 void ExtensionWebRequestEventRouter::DispatchEventToListeners(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     std::unique_ptr<ListenerIDs> listener_ids,
     std::unique_ptr<WebRequestEventDetails> event_details) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!listener_ids->empty());
   DCHECK(event_details.get());
 
@@ -1608,7 +1495,8 @@
   DCHECK(IsWebRequestEvent(event_name));
 
   Listeners& event_listeners = listeners_[browser_context][event_name];
-  void* cross_browser_context = GetCrossBrowserContext(browser_context);
+  content::BrowserContext* cross_browser_context =
+      GetCrossBrowserContext(browser_context);
   Listeners* cross_event_listeners =
       cross_browser_context ? &listeners_[cross_browser_context][event_name]
                             : nullptr;
@@ -1628,7 +1516,8 @@
     if (!listener)
       continue;
 
-    if (!listener->ipc_sender.get())
+    auto* rph = content::RenderProcessHost::FromID(id.render_process_id);
+    if (!rph)
       continue;
 
     // Filter out the optional keys that this listener didn't request.
@@ -1648,11 +1537,11 @@
       custom_event_details = event_details_filtered_copy.get();
     }
     args_filtered->Append(custom_event_details->GetFilteredDict(
-        listener->extra_info_spec, extension_info_map,
+        listener->extra_info_spec, PermissionHelper::Get(browser_context),
         listener->id.extension_id, crosses_incognito));
 
     EventRouter::DispatchEventToSender(
-        listener->ipc_sender.get(), browser_context, listener->id.extension_id,
+        rph, browser_context, listener->id.extension_id,
         listener->histogram_value, listener->id.sub_event_name,
         listener->id.render_process_id, listener->id.worker_thread_id,
         listener->id.service_worker_version_id, std::move(args_filtered),
@@ -1661,7 +1550,7 @@
 }
 
 void ExtensionWebRequestEventRouter::OnEventHandled(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const std::string& extension_id,
     const std::string& event_name,
     const std::string& sub_event_name,
@@ -1687,7 +1576,7 @@
 }
 
 bool ExtensionWebRequestEventRouter::AddEventListener(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const std::string& extension_id,
     const std::string& extension_name,
     events::HistogramValue histogram_value,
@@ -1698,8 +1587,7 @@
     int render_process_id,
     int web_view_instance_id,
     int worker_thread_id,
-    int64_t service_worker_version_id,
-    base::WeakPtr<IPC::Sender> ipc_sender) {
+    int64_t service_worker_version_id) {
   if (!IsWebRequestEvent(event_name))
     return false;
 
@@ -1719,7 +1607,6 @@
   listener->histogram_value = histogram_value;
   listener->filter = filter;
   listener->extra_info_spec = extra_info_spec;
-  listener->ipc_sender = ipc_sender;
   if (web_view_instance_id) {
     base::RecordAction(
         base::UserMetricsAction("WebView.WebRequest.AddListener"));
@@ -1736,14 +1623,14 @@
 }
 
 size_t ExtensionWebRequestEventRouter::GetListenerCountForTesting(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const std::string& event_name) {
   return listeners_[browser_context][event_name].size();
 }
 
 ExtensionWebRequestEventRouter::EventListener*
 ExtensionWebRequestEventRouter::FindEventListener(const EventListener::ID& id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::string event_name = EventRouter::GetBaseEventName(id.sub_event_name);
   Listeners& listeners = listeners_[id.browser_context][event_name];
   return FindEventListenerInContainer(id, listeners);
@@ -1764,7 +1651,7 @@
 void ExtensionWebRequestEventRouter::RemoveEventListener(
     const EventListener::ID& id,
     bool strict) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   std::string event_name = EventRouter::GetBaseEventName(id.sub_event_name);
   Listeners& listeners = listeners_[id.browser_context][event_name];
@@ -1796,10 +1683,10 @@
 }
 
 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     int render_process_id,
     int web_view_instance_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Iterate over all listeners of all WebRequest events to delete
   // any listeners that belong to the provided <webview>.
@@ -1823,7 +1710,8 @@
 }
 
 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
-    void* original_browser_context, void* otr_browser_context) {
+    content::BrowserContext* original_browser_context,
+    content::BrowserContext* otr_browser_context) {
   cross_browser_context_map_[original_browser_context] =
       std::make_pair(false, otr_browser_context);
   cross_browser_context_map_[otr_browser_context] =
@@ -1831,7 +1719,8 @@
 }
 
 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
-    void* original_browser_context, void* otr_browser_context) {
+    content::BrowserContext* original_browser_context,
+    content::BrowserContext* otr_browser_context) {
   cross_browser_context_map_.erase(otr_browser_context);
   cross_browser_context_map_.erase(original_browser_context);
 }
@@ -1842,36 +1731,34 @@
 }
 
 bool ExtensionWebRequestEventRouter::HasExtraHeadersListenerForRequest(
-    void* browser_context,
-    const extensions::InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request) {
   DCHECK(request);
-  if (ShouldHideEvent(browser_context, extension_info_map, *request))
+  if (ShouldHideEvent(browser_context, *request))
     return false;
 
   int extra_info_spec = 0;
   for (const char* name : kWebRequestExtraHeadersEventNames) {
-    GetMatchingListeners(browser_context, extension_info_map, name, request,
-                         &extra_info_spec);
+    GetMatchingListeners(browser_context, name, request, &extra_info_spec);
     if (extra_info_spec & ExtraInfoSpec::EXTRA_HEADERS)
       return true;
   }
 
-  // Check declarative net request API rulesets. Note |extension_info_map| can
-  // be null in unit tests.
-  return extension_info_map &&
-         extension_info_map->GetRulesetManager()
-             ->HasExtraHeadersMatcherForRequest(
-                 *request, IsIncognitoBrowserContext(browser_context));
+  // Check declarative net request API rulesets.
+  return declarative_net_request::RulesMonitorService::Get(browser_context)
+      ->ruleset_manager()
+      ->HasExtraHeadersMatcherForRequest(
+          *request, IsIncognitoBrowserContext(browser_context));
 }
 
 bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListener(
-    void* browser_context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    content::BrowserContext* browser_context) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (HasAnyExtraHeadersListenerImpl(browser_context))
     return true;
 
-  void* cross_browser_context = GetCrossBrowserContext(browser_context);
+  content::BrowserContext* cross_browser_context =
+      GetCrossBrowserContext(browser_context);
   if (cross_browser_context)
     return HasAnyExtraHeadersListenerImpl(cross_browser_context);
 
@@ -1879,8 +1766,8 @@
 }
 
 void ExtensionWebRequestEventRouter::IncrementExtraHeadersListenerCount(
-    void* browser_context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    content::BrowserContext* browser_context) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Try inserting the |browser_context| key, assuming it is not there. Note:
   // emplace returns a pair consisting of an iterator to the inserted element,
@@ -1895,18 +1782,10 @@
     result.first->second++;
     return;
   }
-
-  // An extra header listener was registered for the first time for this
-  // |browser_context|. Notify the UI thread.
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(
-          &ExtensionWebRequestEventRouter::UpdateExtraHeadersListenerOnUI,
-          base::Unretained(this), browser_context, true));
 }
 
 void ExtensionWebRequestEventRouter::DecrementExtraHeadersListenerCount(
-    void* browser_context) {
+    content::BrowserContext* browser_context) {
   auto it = extra_headers_listener_count_.find(browser_context);
   DCHECK(it != extra_headers_listener_count_.end());
   it->second--;
@@ -1915,49 +1794,13 @@
 
   DCHECK_EQ(0, it->second);
   extra_headers_listener_count_.erase(it);
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(
-          &ExtensionWebRequestEventRouter::UpdateExtraHeadersListenerOnUI,
-          base::Unretained(this), browser_context, false));
-}
-
-bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListenerOnUI(
-    content::BrowserContext* browser_context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (browser_contexts_with_extra_headers_.find(browser_context) !=
-      browser_contexts_with_extra_headers_.end())
-    return true;
-
-  if (browser_context->IsOffTheRecord()) {
-    auto* original_browser_context =
-        ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context);
-    if (browser_contexts_with_extra_headers_.find(original_browser_context) !=
-        browser_contexts_with_extra_headers_.end())
-      return true;
-  }
-
-  return false;
 }
 
 bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListenerImpl(
-    void* browser_context) {
+    content::BrowserContext* browser_context) {
   return base::Contains(extra_headers_listener_count_, browser_context);
 }
 
-void ExtensionWebRequestEventRouter::UpdateExtraHeadersListenerOnUI(
-    void* browser_context,
-    bool has_extra_headers_listeners) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  auto* browser_context_ptr =
-      static_cast<content::BrowserContext*>(browser_context);
-  if (has_extra_headers_listeners) {
-    browser_contexts_with_extra_headers_.insert(browser_context_ptr);
-  } else {
-    browser_contexts_with_extra_headers_.erase(browser_context_ptr);
-  }
-}
-
 bool ExtensionWebRequestEventRouter::IsPageLoad(
     const WebRequestInfo& request) const {
   return request.type == content::ResourceType::kMainFrame;
@@ -1969,8 +1812,8 @@
   callbacks_for_page_load_.clear();
 }
 
-void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
-    void* browser_context) const {
+content::BrowserContext* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
+    content::BrowserContext* browser_context) const {
   auto cross_browser_context = cross_browser_context_map_.find(browser_context);
   if (cross_browser_context == cross_browser_context_map_.end())
     return NULL;
@@ -1978,7 +1821,7 @@
 }
 
 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
-    void* browser_context) const {
+    content::BrowserContext* browser_context) const {
   auto cross_browser_context = cross_browser_context_map_.find(browser_context);
   if (cross_browser_context == cross_browser_context_map_.end())
     return false;
@@ -1992,9 +1835,8 @@
 }
 
 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const WebRequestInfo* request,
-    const InfoMap* extension_info_map,
     bool crosses_incognito,
     const std::string& event_name,
     bool is_request_from_extension,
@@ -2008,7 +1850,7 @@
 
   Listeners& listeners = listeners_[browser_context][web_request_event_name];
   for (std::unique_ptr<EventListener>& listener : listeners) {
-    if (!listener->ipc_sender.get()) {
+    if (!content::RenderProcessHost::FromID(listener->id.render_process_id)) {
       // The IPC sender has been deleted. This listener will be removed soon
       // via a call to RemoveEventListener. For now, just skip it.
       continue;
@@ -2056,7 +1898,8 @@
     if (!request->is_web_view) {
       PermissionsData::PageAccess access =
           WebRequestPermissions::CanExtensionAccessURL(
-              extension_info_map, listener->id.extension_id, request->url,
+              PermissionHelper::Get(browser_context), listener->id.extension_id,
+              request->url,
               request->frame_data ? request->frame_data->tab_id : -1,
               crosses_incognito,
               WebRequestPermissions::
@@ -2099,8 +1942,7 @@
 
 ExtensionWebRequestEventRouter::RawListeners
 ExtensionWebRequestEventRouter::GetMatchingListeners(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const std::string& event_name,
     const WebRequestInfo* request,
     int* extra_info_spec) {
@@ -2109,17 +1951,18 @@
   *extra_info_spec = 0;
 
   bool is_request_from_extension =
-      IsRequestFromExtension(*request, extension_info_map);
+      IsRequestFromExtension(*request, browser_context);
 
   RawListeners matching_listeners;
-  GetMatchingListenersImpl(browser_context, request, extension_info_map, false,
-                           event_name, is_request_from_extension,
-                           extra_info_spec, &matching_listeners);
-  void* cross_browser_context = GetCrossBrowserContext(browser_context);
+  GetMatchingListenersImpl(browser_context, request, false, event_name,
+                           is_request_from_extension, extra_info_spec,
+                           &matching_listeners);
+  content::BrowserContext* cross_browser_context =
+      GetCrossBrowserContext(browser_context);
   if (cross_browser_context) {
-    GetMatchingListenersImpl(cross_browser_context, request, extension_info_map,
-                             true, event_name, is_request_from_extension,
-                             extra_info_spec, &matching_listeners);
+    GetMatchingListenersImpl(cross_browser_context, request, true, event_name,
+                             is_request_from_extension, extra_info_spec,
+                             &matching_listeners);
   }
 
   return matching_listeners;
@@ -2277,7 +2120,7 @@
 }  // namespace
 
 void ExtensionWebRequestEventRouter::DecrementBlockCount(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const std::string& extension_id,
     const std::string& event_name,
     uint64_t request_id,
@@ -2313,7 +2156,7 @@
 }
 
 void ExtensionWebRequestEventRouter::SendMessages(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const BlockedRequest& blocked_request) {
   const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
   for (const auto& delta : deltas) {
@@ -2324,20 +2167,18 @@
       event_details->SetString(keys::kMessageKey, message);
       event_details->SetString(keys::kStageKey,
                                GetRequestStageAsString(blocked_request.event));
-      base::PostTaskWithTraits(
-          FROM_HERE, {BrowserThread::UI},
-          base::BindOnce(&SendOnMessageEventOnUI, browser_context,
-                         delta.extension_id,
-                         blocked_request.request->is_web_view,
-                         blocked_request.request->web_view_instance_id,
-                         std::move(event_details)));
+      SendOnMessageEventOnUI(browser_context, delta.extension_id,
+                             blocked_request.request->is_web_view,
+                             blocked_request.request->web_view_instance_id,
+                             std::move(event_details));
     }
   }
 }
 
-int ExtensionWebRequestEventRouter::ExecuteDeltas(void* browser_context,
-                                                  const WebRequestInfo* request,
-                                                  bool call_callback) {
+int ExtensionWebRequestEventRouter::ExecuteDeltas(
+    content::BrowserContext* browser_context,
+    const WebRequestInfo* request,
+    bool call_callback) {
   BlockedRequest& blocked_request = blocked_requests_[request->id];
   CHECK_EQ(0, blocked_request.num_handlers_blocking);
   helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
@@ -2396,10 +2237,8 @@
   SendMessages(browser_context, blocked_request);
 
   if (!ignored_actions.empty()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&NotifyIgnoredActionsOnUI, browser_context, request->id,
-                       std::move(ignored_actions)));
+    NotifyIgnoredActionsOnUI(browser_context, request->id,
+                             std::move(ignored_actions));
   }
 
   const bool redirected =
@@ -2463,8 +2302,7 @@
 }
 
 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
-    void* browser_context,
-    const InfoMap* extension_info_map,
+    content::BrowserContext* browser_context,
     const std::string& event_name,
     const WebRequestInfo* request,
     RequestStage request_stage,
@@ -2493,7 +2331,8 @@
         std::make_pair(rules_key_it->second.get(), false));
   }
 
-  void* cross_browser_context = GetCrossBrowserContext(browser_context);
+  content::BrowserContext* cross_browser_context =
+      GetCrossBrowserContext(browser_context);
   RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
                                                    rules_registry_id);
   if (cross_browser_context) {
@@ -2522,7 +2361,6 @@
     blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
     blocked_request.blocking_time = base::Time::Now();
     blocked_request.filtered_response_headers = filtered_response_headers;
-    blocked_request.extension_info_map = extension_info_map;
     return true;
   }
 
@@ -2537,7 +2375,7 @@
   for (const auto& it : relevant_registries) {
     WebRequestRulesRegistry* rules_registry = it.first;
     helpers::EventResponseDeltas result = rules_registry->CreateDeltas(
-        extension_info_map,
+        PermissionHelper::Get(browser_context),
         WebRequestData(request, request_stage, filtered_response_headers),
         it.second);
 
@@ -2554,7 +2392,7 @@
 }
 
 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const std::string& event_name,
     uint64_t request_id,
     RequestStage request_stage) {
@@ -2565,11 +2403,9 @@
     return;
 
   BlockedRequest& blocked_request = it->second;
-  ProcessDeclarativeRules(browser_context, blocked_request.extension_info_map,
-                          event_name, blocked_request.request, request_stage,
+  ProcessDeclarativeRules(browser_context, event_name, blocked_request.request,
+                          request_stage,
                           blocked_request.filtered_response_headers.get());
-  // Reset to null so that nobody relies on this being set.
-  blocked_request.extension_info_map = nullptr;
   DecrementBlockCount(browser_context, std::string(), event_name, request_id,
                       nullptr, 0 /* extra_info_spec */);
 }
@@ -2692,12 +2528,11 @@
   int web_view_instance_id = 0;
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
 
-  // TODO(dbertoni): We should just use source_process_id() here.
-  base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender = ipc_sender_weak();
-  int render_process_id = ipc_sender ? ipc_sender->render_process_id() : 0;
+  int render_process_id = source_process_id();
 
-  const Extension* extension =
-      extension_info_map()->extensions().GetByID(extension_id_safe());
+  const Extension* extension = ExtensionRegistry::Get(browser_context())
+                                   ->enabled_extensions()
+                                   .GetByID(extension_id_safe());
   std::string extension_name =
       extension ? extension->name() : extension_id_safe();
 
@@ -2736,10 +2571,10 @@
 
   bool success =
       ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
-          profile_id(), extension_id_safe(), extension_name,
+          browser_context(), extension_id_safe(), extension_name,
           GetEventHistogramValue(event_name), event_name, sub_event_name,
           filter, extra_info_spec, render_process_id, web_view_instance_id,
-          worker_thread_id(), service_worker_version_id(), ipc_sender_weak());
+          worker_thread_id(), service_worker_version_id());
   EXTENSION_FUNCTION_VALIDATE(success);
 
   helpers::ClearCacheOnNavigation();
@@ -2755,8 +2590,8 @@
     int web_view_instance_id,
     std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response) {
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
-      profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
-      render_process_id, web_view_instance_id, worker_thread_id(),
+      browser_context(), extension_id_safe(), event_name, sub_event_name,
+      request_id, render_process_id, web_view_instance_id, worker_thread_id(),
       service_worker_version_id(), response.release());
 }
 
@@ -2776,8 +2611,7 @@
   int web_view_instance_id = 0;
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(3, &web_view_instance_id));
 
-  base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender = ipc_sender_weak();
-  int render_process_id = ipc_sender ? ipc_sender->render_process_id() : 0;
+  int render_process_id = source_process_id();
 
   std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
   if (HasOptionalArgument(4)) {
@@ -2785,8 +2619,8 @@
     EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(4, &value));
 
     if (!value->empty()) {
-      base::Time install_time =
-          extension_info_map()->GetInstallTime(extension_id_safe());
+      base::Time install_time = ExtensionPrefs::Get(browser_context())
+                                    ->GetInstallTime(extension_id_safe());
       response.reset(new ExtensionWebRequestEventRouter::EventResponse(
           extension_id_safe(), install_time));
     }
@@ -2902,8 +2736,8 @@
   }
 
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
-      profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
-      render_process_id, web_view_instance_id, worker_thread_id(),
+      browser_context(), extension_id_safe(), event_name, sub_event_name,
+      request_id, render_process_id, web_view_instance_id, worker_thread_id(),
       service_worker_version_id(), response.release());
 
   return RespondNow(NoArguments());
@@ -2927,9 +2761,7 @@
   WarningSet warnings;
   warnings.insert(
       Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(&WarningService::NotifyWarningsOnUI,
-                                          profile_id(), warnings));
+  WarningService::NotifyWarningsOnUI(browser_context(), warnings);
 
   // Continue gracefully.
   RunWithValidation()->Execute();
@@ -2942,7 +2774,7 @@
 }
 
 ExtensionWebRequestEventRouter::EventListener::ID::ID(
-    void* browser_context,
+    content::BrowserContext* browser_context,
     const std::string& extension_id,
     const std::string& sub_event_name,
     int render_process_id,
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index b729c23..a3da883 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -65,7 +65,6 @@
 
 enum class WebRequestResourceType : uint8_t;
 
-class InfoMap;
 class WebRequestEventDetails;
 struct WebRequestInfo;
 class WebRequestRulesRegistry;
@@ -102,16 +101,11 @@
   };
 
   // A ProxySet is a set of proxies used by WebRequestAPI: It holds Proxy
-  // instances, and removes all proxies when the ResourceContext it is bound to
-  // is destroyed.
-  class ProxySet : public base::SupportsUserData::Data {
+  // instances, and removes all proxies when it is destroyed.
+  class ProxySet {
    public:
     ProxySet();
-    ~ProxySet() override;
-
-    // Gets or creates a ProxySet from the given ResourceContext.
-    static ProxySet* GetFromResourceContext(
-        content::ResourceContext* resource_context);
+    ~ProxySet();
 
     // Add a Proxy.
     void AddProxy(std::unique_ptr<Proxy> proxy);
@@ -158,7 +152,7 @@
    public:
     RequestIDGenerator() = default;
     int64_t Generate() {
-      DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+      DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
       return ++id_;
     }
 
@@ -254,9 +248,9 @@
   int web_request_extension_count_ = 0;
 
   content::BrowserContext* const browser_context_;
-  InfoMap* const info_map_;
 
   scoped_refptr<RequestIDGenerator> request_id_generator_;
+  std::unique_ptr<ProxySet> proxies_;
 
   // Stores the last result of |MayHaveProxies()|, so it can be used in
   // |UpdateMayHaveProxies()|.
@@ -339,7 +333,7 @@
   // Registers a rule registry. Pass null for |rules_registry| to unregister
   // the rule registry for |browser_context|.
   void RegisterRulesRegistry(
-      void* browser_context,
+      content::BrowserContext* browser_context,
       int rules_registry_id,
       scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry);
 
@@ -349,8 +343,7 @@
   // net::ERR_BLOCKED_BY_CLIENT is returned if the request should be blocked. In
   // this case, |should_collapse_initiator| might be set to true indicating
   // whether the DOM element which initiated the request should be blocked.
-  int OnBeforeRequest(void* browser_context,
-                      const extensions::InfoMap* extension_info_map,
+  int OnBeforeRequest(content::BrowserContext* browser_context,
                       WebRequestInfo* request,
                       net::CompletionOnceCallback callback,
                       GURL* new_url,
@@ -365,16 +358,14 @@
   // requests only, and allows modification of the outgoing request headers.
   // Returns net::ERR_IO_PENDING if an extension is intercepting the request, OK
   // otherwise.
-  int OnBeforeSendHeaders(void* browser_context,
-                          const extensions::InfoMap* extension_info_map,
+  int OnBeforeSendHeaders(content::BrowserContext* browser_context,
                           const WebRequestInfo* request,
                           BeforeSendHeadersCallback callback,
                           net::HttpRequestHeaders* headers);
 
   // Dispatches the onSendHeaders event. This is fired for HTTP(s) requests
   // only.
-  void OnSendHeaders(void* browser_context,
-                     const extensions::InfoMap* extension_info_map,
+  void OnSendHeaders(content::BrowserContext* browser_context,
                      const WebRequestInfo* request,
                      const net::HttpRequestHeaders& headers);
 
@@ -388,8 +379,7 @@
   // Do not modify |original_response_headers| directly but write new ones
   // into |override_response_headers|.
   int OnHeadersReceived(
-      void* browser_context,
-      const extensions::InfoMap* extension_info_map,
+      content::BrowserContext* browser_context,
       const WebRequestInfo* request,
       net::CompletionOnceCallback callback,
       const net::HttpResponseHeaders* original_response_headers,
@@ -402,8 +392,7 @@
   // AUTH_REQUIRED_RESPONSE_IO_PENDING is returned and |callback| will be
   // invoked later.
   net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(
-      void* browser_context,
-      const extensions::InfoMap* extension_info_map,
+      content::BrowserContext* browser_context,
       const WebRequestInfo* request,
       const net::AuthChallengeInfo& auth_info,
       net::NetworkDelegate::AuthCallback callback,
@@ -411,27 +400,23 @@
 
   // Dispatches the onBeforeRedirect event. This is fired for HTTP(s) requests
   // only.
-  void OnBeforeRedirect(void* browser_context,
-                        const extensions::InfoMap* extension_info_map,
+  void OnBeforeRedirect(content::BrowserContext* browser_context,
                         const WebRequestInfo* request,
                         const GURL& new_location);
 
   // Dispatches the onResponseStarted event indicating that the first bytes of
   // the response have arrived.
-  void OnResponseStarted(void* browser_context,
-                         const extensions::InfoMap* extension_info_map,
+  void OnResponseStarted(content::BrowserContext* browser_context,
                          const WebRequestInfo* request,
                          int net_error);
 
   // Dispatches the onComplete event.
-  void OnCompleted(void* browser_context,
-                   const extensions::InfoMap* extension_info_map,
+  void OnCompleted(content::BrowserContext* browser_context,
                    const WebRequestInfo* request,
                    int net_error);
 
   // Dispatches an onErrorOccurred event.
-  void OnErrorOccurred(void* browser_context,
-                       const extensions::InfoMap* extension_info_map,
+  void OnErrorOccurred(content::BrowserContext* browser_context,
                        const WebRequestInfo* request,
                        bool started,
                        int net_error);
@@ -440,11 +425,11 @@
   // whether it has gone to completion or merely been cancelled. This is
   // guaranteed to be called eventually for any request observed by this object,
   // and |*request| will be immintently destroyed after this returns.
-  void OnRequestWillBeDestroyed(void* browser_context,
+  void OnRequestWillBeDestroyed(content::BrowserContext* browser_context,
                                 const WebRequestInfo* request);
 
   // Called when an event listener handles a blocking event and responds.
-  void OnEventHandled(void* browser_context,
+  void OnEventHandled(content::BrowserContext* browser_context,
                       const std::string& extension_id,
                       const std::string& event_name,
                       const std::string& sub_event_name,
@@ -459,7 +444,7 @@
   // listened to. |sub_event_name| is an internal event uniquely generated in
   // the extension process to correspond to the given filter and
   // extra_info_spec. It returns true on success, false on failure.
-  bool AddEventListener(void* browser_context,
+  bool AddEventListener(content::BrowserContext* browser_context,
                         const std::string& extension_id,
                         const std::string& extension_name,
                         events::HistogramValue histogram_value,
@@ -470,19 +455,20 @@
                         int render_process_id,
                         int web_view_instance_id,
                         int worker_thread_id,
-                        int64_t service_worker_version_id,
-                        base::WeakPtr<IPC::Sender> ipc_sender);
+                        int64_t service_worker_version_id);
 
   // Removes the listeners for a given <webview>.
-  void RemoveWebViewEventListeners(void* browser_context,
+  void RemoveWebViewEventListeners(content::BrowserContext* browser_context,
                                    int render_process_id,
                                    int web_view_instance_id);
 
   // Called when an incognito browser_context is created or destroyed.
-  void OnOTRBrowserContextCreated(void* original_browser_context,
-                                  void* otr_browser_context);
-  void OnOTRBrowserContextDestroyed(void* original_browser_context,
-                                    void* otr_browser_context);
+  void OnOTRBrowserContextCreated(
+      content::BrowserContext* original_browser_context,
+      content::BrowserContext* otr_browser_context);
+  void OnOTRBrowserContextDestroyed(
+      content::BrowserContext* original_browser_context,
+      content::BrowserContext* otr_browser_context);
 
   // Registers a |callback| that is executed when the next page load happens.
   // The callback is then deleted.
@@ -491,19 +477,17 @@
   // Whether there is a listener matching the request that has
   // ExtraInfoSpec::EXTRA_HEADERS set.
   bool HasExtraHeadersListenerForRequest(
-      void* browser_context,
-      const extensions::InfoMap* extension_info_map,
+      content::BrowserContext* browser_context,
       const WebRequestInfo* request);
 
   // Whether there are any listeners for this context that have
   // ExtraInfoSpec::EXTRA_HEADERS set.
-  bool HasAnyExtraHeadersListener(void* browser_context);
+  bool HasAnyExtraHeadersListener(content::BrowserContext* browser_context);
 
-  // Like above, but for usage on the UI thread.
-  bool HasAnyExtraHeadersListenerOnUI(content::BrowserContext* browser_context);
-
-  void IncrementExtraHeadersListenerCount(void* browser_context);
-  void DecrementExtraHeadersListenerCount(void* browser_context);
+  void IncrementExtraHeadersListenerCount(
+      content::BrowserContext* browser_context);
+  void DecrementExtraHeadersListenerCount(
+      content::BrowserContext* browser_context);
 
  private:
   friend class WebRequestAPI;
@@ -534,7 +518,7 @@
     // This is why we need the LooselyMatches method, and the need for a
     // |strict| argument on RemoveEventListener.
     struct ID {
-      ID(void* browser_context,
+      ID(content::BrowserContext* browser_context,
          const std::string& extension_id,
          const std::string& sub_event_name,
          int render_process_id,
@@ -551,7 +535,7 @@
 
       bool operator==(const ID& that) const;
 
-      void* browser_context;
+      content::BrowserContext* browser_context;
       std::string extension_id;
       std::string sub_event_name;
       // In the case of a webview, this is the process ID of the embedder.
@@ -572,7 +556,6 @@
     events::HistogramValue histogram_value = events::UNKNOWN;
     RequestFilter filter;
     int extra_info_spec = 0;
-    base::WeakPtr<IPC::Sender> ipc_sender;
     std::unordered_set<uint64_t> blocked_requests;
 
    private:
@@ -583,15 +566,18 @@
   using ListenerIDs = std::vector<EventListener::ID>;
   using Listeners = std::vector<std::unique_ptr<EventListener>>;
   using ListenerMapForBrowserContext = std::map<std::string, Listeners>;
-  using ListenerMap = std::map<void*, ListenerMapForBrowserContext>;
-  using ExtraHeadersListenerCountMap = std::map<void*, int>;
+  using ListenerMap =
+      std::map<content::BrowserContext*, ListenerMapForBrowserContext>;
+  using ExtraHeadersListenerCountMap = std::map<content::BrowserContext*, int>;
   using BlockedRequestMap = std::map<uint64_t, BlockedRequest>;
   // Map of request_id -> bit vector of EventTypes already signaled
   using SignaledRequestMap = std::map<uint64_t, int>;
   // For each browser_context: a bool indicating whether it is an incognito
   // browser_context, and a pointer to the corresponding (non-)incognito
   // browser_context.
-  using CrossBrowserContextMap = std::map<void*, std::pair<bool, void*>>;
+  using CrossBrowserContextMap =
+      std::map<content::BrowserContext*,
+               std::pair<bool, content::BrowserContext*>>;
   using CallbacksForPageLoad = std::list<base::Closure>;
 
   ExtensionWebRequestEventRouter();
@@ -615,43 +601,30 @@
   // destroyed safely.
   void ClearPendingCallbacks(const WebRequestInfo& request);
 
-  bool DispatchEvent(void* browser_context,
-                     const InfoMap* extension_info_map,
+  bool DispatchEvent(content::BrowserContext* browser_context,
                      const WebRequestInfo* request,
                      const RawListeners& listener_ids,
                      std::unique_ptr<WebRequestEventDetails> event_details);
 
-  void OnFrameDataReceived(
-      void* browser_context,
-      const WebRequestInfo* request,
-      std::unique_ptr<WebRequestEventDetails> event_details,
-      const InfoMap* extension_info_map,
-      std::unique_ptr<ListenerIDs> listener_ids,
-      const ExtensionApiFrameIdMap::FrameData& frame_data);
-
   void DispatchEventToListeners(
-      void* browser_context,
-      const InfoMap* extension_info_map,
+      content::BrowserContext* browser_context,
       std::unique_ptr<ListenerIDs> listener_ids,
       std::unique_ptr<WebRequestEventDetails> event_details);
 
   // Returns a list of event listeners that care about the given event, based
   // on their filter parameters. |extra_info_spec| will contain the combined
   // set of extra_info_spec flags that every matching listener asked for.
-  RawListeners GetMatchingListeners(
-      void* browser_context,
-      const extensions::InfoMap* extension_info_map,
-      const std::string& event_name,
-      const WebRequestInfo* request,
-      int* extra_info_spec);
+  RawListeners GetMatchingListeners(content::BrowserContext* browser_context,
+                                    const std::string& event_name,
+                                    const WebRequestInfo* request,
+                                    int* extra_info_spec);
 
   // Helper for the above functions. This is called twice: once for the
   // browser_context of the event, the next time for the "cross" browser_context
   // (i.e. the incognito browser_context if the event is originally for the
   // normal browser_context, or vice versa).
-  void GetMatchingListenersImpl(void* browser_context,
+  void GetMatchingListenersImpl(content::BrowserContext* browser_context,
                                 const WebRequestInfo* request,
-                                const extensions::InfoMap* extension_info_map,
                                 bool crosses_incognito,
                                 const std::string& event_name,
                                 bool is_request_from_extension,
@@ -663,7 +636,7 @@
   // method requested by the extension with the highest precedence. Precedence
   // is decided by extension install time. If |response| is non-NULL, this
   // method assumes ownership.
-  void DecrementBlockCount(void* browser_context,
+  void DecrementBlockCount(content::BrowserContext* browser_context,
                            const std::string& extension_id,
                            const std::string& event_name,
                            uint64_t request_id,
@@ -676,7 +649,7 @@
   // The function returns the error code for the network request. This is
   // mostly relevant in case the caller passes |call_callback| = false
   // and wants to return the correct network error code himself.
-  int ExecuteDeltas(void* browser_context,
+  int ExecuteDeltas(content::BrowserContext* browser_context,
                     const WebRequestInfo* request,
                     bool call_callback);
 
@@ -686,8 +659,7 @@
   // set for the OnHeadersReceived stage and NULL otherwise. Returns whether any
   // deltas were generated.
   bool ProcessDeclarativeRules(
-      void* browser_context,
-      const extensions::InfoMap* extension_info_map,
+      content::BrowserContext* browser_context,
       const std::string& event_name,
       const WebRequestInfo* request,
       extensions::RequestStage request_stage,
@@ -696,12 +668,12 @@
   // If the BlockedRequest contains messages_to_extension entries in the event
   // deltas, we send them to subscribers of
   // chrome.declarativeWebRequest.onMessage.
-  void SendMessages(void* browser_context,
+  void SendMessages(content::BrowserContext* browser_context,
                     const BlockedRequest& blocked_request);
 
   // Called when the RulesRegistry is ready to unblock a request that was
   // waiting for said event.
-  void OnRulesRegistryReady(void* browser_context,
+  void OnRulesRegistryReady(content::BrowserContext* browser_context,
                             const std::string& event_name,
                             uint64_t request_id,
                             extensions::RequestStage request_stage);
@@ -721,25 +693,23 @@
 
   // Returns the matching cross browser_context (the regular browser_context if
   // |browser_context| is OTR and vice versa).
-  void* GetCrossBrowserContext(void* browser_context) const;
+  content::BrowserContext* GetCrossBrowserContext(
+      content::BrowserContext* browser_context) const;
 
   // Determines whether the specified browser_context is an incognito
   // browser_context (based on the contents of the cross-browser_context table
   // and without dereferencing the browser_context pointer).
-  bool IsIncognitoBrowserContext(void* browser_context) const;
+  bool IsIncognitoBrowserContext(
+      content::BrowserContext* browser_context) const;
 
   // Returns true if |request| was already signaled to some event handlers.
   bool WasSignaled(const WebRequestInfo& request) const;
 
   // Helper for |HasAnyExtraHeadersListener()|.
-  bool HasAnyExtraHeadersListenerImpl(void* browser_context);
-
-  // Called on the UI thread to update |browser_contexts_with_extra_headers_|.
-  void UpdateExtraHeadersListenerOnUI(void* browser_context,
-                                      bool has_extra_headers_listeners);
+  bool HasAnyExtraHeadersListenerImpl(content::BrowserContext* browser_context);
 
   // Get the number of listeners - for testing only.
-  size_t GetListenerCountForTesting(void* browser_context,
+  size_t GetListenerCountForTesting(content::BrowserContext* browser_context,
                                     const std::string& event_name);
 
   // TODO(karandeepb): The below code should be refactored to have a single map
@@ -753,10 +723,6 @@
   // modified through [Increment/Decrement]ExtraHeadersListenerCount.
   ExtraHeadersListenerCountMap extra_headers_listener_count_;
 
-  // Accessed on the UI thread to check if a given BrowserContext has any
-  // extra headers listeners.
-  std::set<content::BrowserContext*> browser_contexts_with_extra_headers_;
-
   // A map of network requests that are waiting for at least one event handler
   // to respond.
   BlockedRequestMap blocked_requests_;
@@ -773,13 +739,9 @@
   // webRequest API.
   std::unique_ptr<ExtensionWebRequestTimeTracker> request_time_tracker_;
 
-  // The set of requests for which we are querying the frame data over the UI
-  // thread.
-  std::set<const WebRequestInfo*> pending_requests_for_frame_data_;
-
   CallbacksForPageLoad callbacks_for_page_load_;
 
-  typedef std::pair<void*, int> RulesRegistryKey;
+  typedef std::pair<content::BrowserContext*, int> RulesRegistryKey;
   // Maps each browser_context (and OTRBrowserContext) and a webview key to its
   // respective rules registry.
   std::map<RulesRegistryKey,
@@ -788,7 +750,7 @@
   DISALLOW_COPY_AND_ASSIGN(ExtensionWebRequestEventRouter);
 };
 
-class WebRequestInternalFunction : public IOThreadExtensionFunction {
+class WebRequestInternalFunction : public UIThreadExtensionFunction {
  public:
   WebRequestInternalFunction() {}
 
diff --git a/extensions/browser/api/web_request/web_request_event_details.cc b/extensions/browser/api/web_request/web_request_event_details.cc
index d0c2272..b6415644 100644
--- a/extensions/browser/api/web_request/web_request_event_details.cc
+++ b/extensions/browser/api/web_request/web_request_event_details.cc
@@ -150,7 +150,7 @@
 
 std::unique_ptr<base::DictionaryValue> WebRequestEventDetails::GetFilteredDict(
     int extra_info_spec,
-    const extensions::InfoMap* extension_info_map,
+    PermissionHelper* permission_helper,
     const extensions::ExtensionId& extension_id,
     bool crosses_incognito) const {
   std::unique_ptr<base::DictionaryValue> result = dict_.CreateDeepCopy();
@@ -174,12 +174,12 @@
   }
 
   // Only listeners with a permission for the initiator should recieve it.
-  if (extension_info_map && initiator_) {
+  if (initiator_) {
     int tab_id = -1;
     dict_.GetInteger(keys::kTabIdKey, &tab_id);
     if (initiator_->opaque() ||
         WebRequestPermissions::CanExtensionAccessInitiator(
-            extension_info_map, extension_id, initiator_, tab_id,
+            permission_helper, extension_id, initiator_, tab_id,
             crosses_incognito)) {
       result->SetString(keys::kInitiatorKey, initiator_->Serialize());
     }
diff --git a/extensions/browser/api/web_request/web_request_event_details.h b/extensions/browser/api/web_request/web_request_event_details.h
index c9fa6ef..bac180e 100644
--- a/extensions/browser/api/web_request/web_request_event_details.h
+++ b/extensions/browser/api/web_request/web_request_event_details.h
@@ -25,7 +25,7 @@
 
 namespace extensions {
 
-class InfoMap;
+class PermissionHelper;
 struct WebRequestInfo;
 
 // This helper class is used to construct the details for a webRequest event
@@ -115,7 +115,7 @@
   // This can be called from any thread.
   std::unique_ptr<base::DictionaryValue> GetFilteredDict(
       int extra_info_spec,
-      const InfoMap* extension_info_map,
+      PermissionHelper* permission_helper,
       const ExtensionId& extension_id,
       bool crosses_incognito) const;
 
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc
index c6aae01..8eb9e17 100644
--- a/extensions/browser/api/web_request/web_request_info.cc
+++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/stl_util.h"
 #include "base/values.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/websocket_handshake_request_info.h"
 #include "extensions/browser/api/web_request/upload_data_presenter.h"
@@ -159,7 +160,6 @@
     int render_frame_id,
     std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
     int32_t routing_id,
-    content::ResourceContext* resource_context,
     const network::ResourceRequest& request,
     bool is_download,
     bool is_async)
@@ -174,8 +174,7 @@
       initiator(request.request_initiator),
       type(static_cast<content::ResourceType>(request.resource_type)),
       is_async(is_async),
-      extra_request_headers(request.headers),
-      resource_context(resource_context) {
+      extra_request_headers(request.headers) {
   if (url.SchemeIsWSOrWSS())
     web_request_type = WebRequestResourceType::WEB_SOCKET;
   else if (is_download)
@@ -213,18 +212,9 @@
       web_view_embedder_process_id = web_view_info.embedder_process_id;
     }
 
-    // For subresource loads we attempt to resolve the FrameData immediately
-    // anyway using cached information.
-    ExtensionApiFrameIdMap::FrameData data;
-    bool was_cached = ExtensionApiFrameIdMap::Get()->GetCachedFrameDataOnIO(
-        render_process_id, frame_id, &data);
-    // TODO(crbug.com/843762): Investigate when |was_cached| can be false. It
-    // seems we are not tracking all WebContents or that the corresponding
-    // render frame was destroyed. Track where this can occur, this should help
-    // in minimizing IO->UI->IO thread that the web request API performs to
-    // fetch the frame data.
-    if (was_cached)
-      frame_data = data;
+    // For subresource loads we attempt to resolve the FrameData immediately.
+    frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData(
+        content::RenderFrameHost::FromID(render_process_id, frame_id));
   }
 }
 
@@ -247,8 +237,7 @@
       is_web_view(params.is_web_view),
       web_view_instance_id(params.web_view_instance_id),
       web_view_rules_registry_id(params.web_view_rules_registry_id),
-      web_view_embedder_process_id(params.web_view_embedder_process_id),
-      resource_context(params.resource_context) {}
+      web_view_embedder_process_id(params.web_view_embedder_process_id) {}
 
 WebRequestInfo::~WebRequestInfo() = default;
 
diff --git a/extensions/browser/api/web_request/web_request_info.h b/extensions/browser/api/web_request/web_request_info.h
index 949e5717..7688e9b 100644
--- a/extensions/browser/api/web_request/web_request_info.h
+++ b/extensions/browser/api/web_request/web_request_info.h
@@ -25,10 +25,6 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-namespace content {
-class ResourceContext;
-}  // namespace content
-
 namespace network {
 struct ResourceResponseHead;
 }
@@ -51,7 +47,6 @@
       int render_frame_id,
       std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
       int32_t routing_id,
-      content::ResourceContext* resource_context,
       const network::ResourceRequest& request,
       bool is_download,
       bool is_async);
@@ -76,7 +71,6 @@
   int web_view_instance_id = -1;
   int web_view_rules_registry_id = -1;
   int web_view_embedder_process_id = -1;
-  content::ResourceContext* resource_context = nullptr;
   base::Optional<ExtensionApiFrameIdMap::FrameData> frame_data;
 
  private:
@@ -173,9 +167,6 @@
   const int web_view_rules_registry_id;
   const int web_view_embedder_process_id;
 
-  // The ResourceContext associated with this request. May be null.
-  content::ResourceContext* const resource_context;
-
   // The Declarative Net Request action associated with this request. Mutable
   // since this is lazily computed. Cached to avoid redundant computations.
   mutable base::Optional<declarative_net_request::RulesetManager::Action>
diff --git a/extensions/browser/api/web_request/web_request_info_unittest.cc b/extensions/browser/api/web_request/web_request_info_unittest.cc
index 53b1d8e..22c9305 100644
--- a/extensions/browser/api/web_request/web_request_info_unittest.cc
+++ b/extensions/browser/api/web_request/web_request_info_unittest.cc
@@ -28,8 +28,8 @@
   request.request_body->AppendFileRange(base::FilePath(kFilePath), 0,
                                         std::numeric_limits<uint64_t>::max(),
                                         base::Time());
-  WebRequestInfo info(WebRequestInfoInitParams(0, 0, 0, nullptr, 0, nullptr,
-                                               request, false, false));
+  WebRequestInfo info(
+      WebRequestInfoInitParams(0, 0, 0, nullptr, 0, request, false, false));
   ASSERT_TRUE(info.request_body_data);
   auto* value = info.request_body_data->FindKey(
       extension_web_request_api_constants::kRequestBodyRawKey);
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc
index f58f049..5611c800 100644
--- a/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -12,14 +12,17 @@
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
+#include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/permissions/permissions_data.h"
 #include "url/gurl.h"
 
@@ -64,7 +67,7 @@
 }
 
 PermissionsData::PageAccess CanExtensionAccessURLInternal(
-    const extensions::InfoMap* extension_info_map,
+    extensions::PermissionHelper* permission_helper,
     const std::string& extension_id,
     const GURL& url,
     int tab_id,
@@ -72,12 +75,9 @@
     WebRequestPermissions::HostPermissionsCheck host_permissions_check,
     const base::Optional<url::Origin>& initiator,
     const base::Optional<content::ResourceType>& resource_type) {
-  // extension_info_map can be NULL in testing.
-  if (!extension_info_map)
-    return PermissionsData::PageAccess::kAllowed;
-
   const extensions::Extension* extension =
-      extension_info_map->extensions().GetByID(extension_id);
+      permission_helper->extension_registry()->enabled_extensions().GetByID(
+          extension_id);
   if (!extension)
     return PermissionsData::PageAccess::kDenied;
 
@@ -103,7 +103,7 @@
 #endif
 
   // Check if this event crosses incognito boundaries when it shouldn't.
-  if (crosses_incognito && !extension_info_map->CanCrossIncognito(extension))
+  if (crosses_incognito && !permission_helper->CanCrossIncognito(extension))
     return PermissionsData::PageAccess::kDenied;
 
   switch (host_permissions_check) {
@@ -236,7 +236,7 @@
 
 // static
 bool WebRequestPermissions::HideRequest(
-    const extensions::InfoMap* extension_info_map,
+    extensions::PermissionHelper* permission_helper,
     const extensions::WebRequestInfo& request) {
   if (!HasWebRequestScheme(request.url))
     return true;
@@ -268,8 +268,8 @@
   }
 
   // Hide requests from the Chrome WebStore App.
-  if (!is_request_from_browser && extension_info_map &&
-      extension_info_map->process_map().Contains(extensions::kWebStoreAppId,
+  if (!is_request_from_browser &&
+      permission_helper->process_map()->Contains(extensions::kWebStoreAppId,
                                                  request.render_process_id)) {
     return true;
   }
@@ -305,10 +305,8 @@
   }
 
   // Allow the extension embedder to hide the request.
-  if (extensions::ExtensionsAPIClient::Get()->ShouldHideBrowserNetworkRequest(
-          request)) {
+  if (permission_helper->ShouldHideBrowserNetworkRequest(request))
     return true;
-  }
 
   // Safebrowsing and Chrome Webstore URLs are always protected, i.e. also
   // for requests from common renderers.
@@ -333,7 +331,7 @@
 
 // static
 PermissionsData::PageAccess WebRequestPermissions::CanExtensionAccessURL(
-    const extensions::InfoMap* extension_info_map,
+    extensions::PermissionHelper* permission_helper,
     const std::string& extension_id,
     const GURL& url,
     int tab_id,
@@ -342,13 +340,13 @@
     const base::Optional<url::Origin>& initiator,
     const base::Optional<content::ResourceType>& resource_type) {
   return CanExtensionAccessURLInternal(
-      extension_info_map, extension_id, url, tab_id, crosses_incognito,
+      permission_helper, extension_id, url, tab_id, crosses_incognito,
       host_permissions_check, initiator, resource_type);
 }
 
 // static
 bool WebRequestPermissions::CanExtensionAccessInitiator(
-    const extensions::InfoMap* extension_info_map,
+    extensions::PermissionHelper* permission_helper,
     const extensions::ExtensionId extension_id,
     const base::Optional<url::Origin>& initiator,
     int tab_id,
@@ -357,7 +355,7 @@
     return true;
 
   return CanExtensionAccessURLInternal(
-             extension_info_map, extension_id, initiator->GetURL(), tab_id,
+             permission_helper, extension_id, initiator->GetURL(), tab_id,
              crosses_incognito,
              WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL,
              base::nullopt /* initiator */,
diff --git a/extensions/browser/api/web_request/web_request_permissions.h b/extensions/browser/api/web_request/web_request_permissions.h
index 4ef75ac..e8dc992 100644
--- a/extensions/browser/api/web_request/web_request_permissions.h
+++ b/extensions/browser/api/web_request/web_request_permissions.h
@@ -17,7 +17,7 @@
 class GURL;
 
 namespace extensions {
-class InfoMap;
+class PermissionHelper;
 struct WebRequestInfo;
 }
 
@@ -39,7 +39,7 @@
   };
 
   // Returns true if the request shall not be reported to extensions.
-  static bool HideRequest(const extensions::InfoMap* extension_info_map,
+  static bool HideRequest(extensions::PermissionHelper* permission_helper,
                           const extensions::WebRequestInfo& request);
 
   // Helper function used only in tests, sets a variable which enables or
@@ -49,7 +49,7 @@
   // |host_permission_check| controls how permissions are checked with regard to
   // |url| and |initiator| if an initiator exists.
   static extensions::PermissionsData::PageAccess CanExtensionAccessURL(
-      const extensions::InfoMap* extension_info_map,
+      extensions::PermissionHelper* permission_helper,
       const std::string& extension_id,
       const GURL& url,
       int tab_id,
@@ -59,7 +59,7 @@
       const base::Optional<content::ResourceType>& resource_type);
 
   static bool CanExtensionAccessInitiator(
-      const extensions::InfoMap* extension_info_map,
+      extensions::PermissionHelper* permission_helper,
       const extensions::ExtensionId extension_id,
       const base::Optional<url::Origin>& initiator,
       int tab_id,
diff --git a/extensions/browser/api/web_request/web_request_permissions_unittest.cc b/extensions/browser/api/web_request/web_request_permissions_unittest.cc
index 8c757dd..04e2cd26 100644
--- a/extensions/browser/api/web_request/web_request_permissions_unittest.cc
+++ b/extensions/browser/api/web_request/web_request_permissions_unittest.cc
@@ -8,8 +8,10 @@
 #include "base/strings/stringprintf.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
-#include "extensions/browser/info_map.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extensions_test.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/permissions/permission_set.h"
@@ -22,7 +24,9 @@
 
 namespace extensions {
 
-TEST(ExtensionWebRequestPermissions, TestHideRequestForURL) {
+using ExtensionWebRequestPermissionsTest = ExtensionsTest;
+
+TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
   enum HideRequestMask {
     HIDE_NONE = 0,
     HIDE_RENDERER_REQUEST = 1,
@@ -33,12 +37,8 @@
                HIDE_MAIN_FRAME_NAVIGATION | HIDE_BROWSER_SUB_RESOURCE_REQUEST,
   };
 
-  // The InfoMap requires methods to be called on the IO thread. Fake it.
-  content::TestBrowserThreadBundle thread_bundle(
-      content::TestBrowserThreadBundle::IO_MAINLOOP);
-
   ExtensionsAPIClient api_client;
-  auto info_map = base::MakeRefCounted<extensions::InfoMap>();
+  auto* permission_helper = PermissionHelper::Get(browser_context());
 
   struct TestCase {
     const char* url;
@@ -132,7 +132,7 @@
       bool expect_hidden =
           test_case.expected_hide_request_mask & HIDE_RENDERER_REQUEST;
       EXPECT_EQ(expect_hidden,
-                WebRequestPermissions::HideRequest(info_map.get(), request));
+                WebRequestPermissions::HideRequest(permission_helper, request));
     }
 
     {
@@ -142,7 +142,7 @@
       bool expect_hidden = test_case.expected_hide_request_mask &
                            HIDE_BROWSER_SUB_RESOURCE_REQUEST;
       EXPECT_EQ(expect_hidden,
-                WebRequestPermissions::HideRequest(info_map.get(), request));
+                WebRequestPermissions::HideRequest(permission_helper, request));
     }
 
     {
@@ -152,7 +152,7 @@
       bool expect_hidden =
           test_case.expected_hide_request_mask & HIDE_MAIN_FRAME_NAVIGATION;
       EXPECT_EQ(expect_hidden,
-                WebRequestPermissions::HideRequest(info_map.get(), request));
+                WebRequestPermissions::HideRequest(permission_helper, request));
     }
 
     {
@@ -162,7 +162,7 @@
       bool expect_hidden =
           test_case.expected_hide_request_mask & HIDE_SUB_FRAME_NAVIGATION;
       EXPECT_EQ(expect_hidden,
-                WebRequestPermissions::HideRequest(info_map.get(), request));
+                WebRequestPermissions::HideRequest(permission_helper, request));
     }
   }
 
@@ -173,7 +173,7 @@
   {
     WebRequestInfo non_sensitive_request(create_request_params(
         non_sensitive_url, content::ResourceType::kScript, kRendererProcessId));
-    EXPECT_FALSE(WebRequestPermissions::HideRequest(info_map.get(),
+    EXPECT_FALSE(WebRequestPermissions::HideRequest(permission_helper,
                                                     non_sensitive_request));
   }
 
@@ -181,21 +181,18 @@
   {
     const int kWebstoreProcessId = 42;
     const int kSiteInstanceId = 23;
-    info_map->RegisterExtensionProcess(extensions::kWebStoreAppId,
-                                       kWebstoreProcessId, kSiteInstanceId);
+    ProcessMap::Get(browser_context())
+        ->Insert(extensions::kWebStoreAppId, kWebstoreProcessId,
+                 kSiteInstanceId);
     WebRequestInfo sensitive_request_info(create_request_params(
         non_sensitive_url, content::ResourceType::kScript, kWebstoreProcessId));
-    EXPECT_TRUE(WebRequestPermissions::HideRequest(info_map.get(),
+    EXPECT_TRUE(WebRequestPermissions::HideRequest(permission_helper,
                                                    sensitive_request_info));
   }
 }
 
-TEST(ExtensionWebRequestPermissions,
-     CanExtensionAccessURLWithWithheldPermissions) {
-  // The InfoMap requires methods to be called on the IO thread. Fake it.
-  content::TestBrowserThreadBundle thread_bundle(
-      content::TestBrowserThreadBundle::IO_MAINLOOP);
-
+TEST_F(ExtensionWebRequestPermissionsTest,
+       CanExtensionAccessURLWithWithheldPermissions) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("ext").AddPermission("<all_urls>").Build();
   URLPatternSet all_urls(
@@ -207,10 +204,9 @@
           APIPermissionSet(), ManifestPermissionSet(), all_urls.Clone(),
           URLPatternSet()) /* withheld permissions */);
 
-  scoped_refptr<InfoMap> info_map = base::MakeRefCounted<InfoMap>();
-  info_map->AddExtension(extension.get(), base::Time(), false, false);
+  ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
 
-  auto get_access = [extension, info_map](
+  auto get_access = [extension, this](
                         const GURL& url,
                         const base::Optional<url::Origin>& initiator,
                         const base::Optional<content::ResourceType>&
@@ -219,7 +215,7 @@
     constexpr WebRequestPermissions::HostPermissionsCheck kPermissionsCheck =
         WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL;
     return WebRequestPermissions::CanExtensionAccessURL(
-        info_map.get(), extension->id(), url, kTabId,
+        PermissionHelper::Get(browser_context()), extension->id(), url, kTabId,
         false /* crosses incognito */, kPermissionsCheck, initiator,
         resource_type);
   };
@@ -293,11 +289,10 @@
   }
 }
 
-TEST(ExtensionWebRequestPermissions,
-     RequireAccessToURLAndInitiatorWithWithheldPermissions) {
-  // The InfoMap requires methods to be called on the IO thread. Fake it.
-  content::TestBrowserThreadBundle thread_bundle(
-      content::TestBrowserThreadBundle::IO_MAINLOOP);
+TEST_F(ExtensionWebRequestPermissionsTest,
+       RequireAccessToURLAndInitiatorWithWithheldPermissions) {
+  ExtensionsAPIClient api_client;
+
   const char* kGoogleCom = "https://google.com/";
   const char* kExampleCom = "https://example.com/";
   const char* kYahooCom = "https://yahoo.com";
@@ -322,10 +317,9 @@
           kWithheldPatternSet.Clone(),
           kWithheldPatternSet.Clone()) /* withheld permissions */);
 
-  scoped_refptr<InfoMap> info_map = base::MakeRefCounted<InfoMap>();
-  info_map->AddExtension(extension.get(), base::Time(), false, false);
+  ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
 
-  auto get_access = [extension, info_map](
+  auto get_access = [extension, this](
                         const GURL& url,
                         const base::Optional<url::Origin>& initiator,
                         const base::Optional<content::ResourceType>&
@@ -334,7 +328,7 @@
     constexpr WebRequestPermissions::HostPermissionsCheck kPermissionsCheck =
         WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR;
     return WebRequestPermissions::CanExtensionAccessURL(
-        info_map.get(), extension->id(), url, kTabId,
+        PermissionHelper::Get(browser_context()), extension->id(), url, kTabId,
         false /* crosses incognito */, kPermissionsCheck, initiator,
         resource_type);
   };
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index 9291a28..95d47c3 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -12,11 +12,14 @@
 #include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
+#include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/common/url_utils.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
 #include "net/base/completion_repeating_callback.h"
 #include "net/http/http_util.h"
@@ -25,6 +28,33 @@
 #include "url/origin.h"
 
 namespace extensions {
+namespace {
+
+// This shutdown notifier makes sure the proxy is destroyed if an incognito
+// browser context is destroyed. This is needed because WebRequestAPI only
+// clears the proxies when the original browser context is destroyed.
+class ShutdownNotifierFactory
+    : public BrowserContextKeyedServiceShutdownNotifierFactory {
+ public:
+  static ShutdownNotifierFactory* GetInstance() {
+    static base::NoDestructor<ShutdownNotifierFactory> factory;
+    return factory.get();
+  }
+
+ private:
+  friend class base::NoDestructor<ShutdownNotifierFactory>;
+
+  ShutdownNotifierFactory()
+      : BrowserContextKeyedServiceShutdownNotifierFactory(
+            "WebRequestProxyingURLLoaderFactory") {
+    DependsOn(PermissionHelper::GetFactoryInstance());
+  }
+  ~ShutdownNotifierFactory() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory);
+};
+
+}  // namespace
 
 WebRequestProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
     FollowRedirectParams() = default;
@@ -101,15 +131,15 @@
       request_id_, factory_->render_process_id_, request_.render_frame_id,
       factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy()
                                     : nullptr,
-      routing_id_, factory_->resource_context_, request_for_info, is_download_,
+      routing_id_, request_for_info, is_download_,
       !(options_ & network::mojom::kURLLoadOptionSynchronous)));
 
   current_request_uses_header_client_ =
       factory_->url_loader_header_client_binding_ &&
       request_.url.SchemeIsHTTPOrHTTPS() && network_service_request_id_ != 0 &&
       ExtensionWebRequestEventRouter::GetInstance()
-          ->HasExtraHeadersListenerForRequest(
-              factory_->browser_context_, factory_->info_map_, &info_.value());
+          ->HasExtraHeadersListenerForRequest(factory_->browser_context_,
+                                              &info_.value());
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
@@ -132,8 +162,8 @@
   redirect_url_ = GURL();
   bool should_collapse_initiator = false;
   int result = ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
-      factory_->browser_context_, factory_->info_map_, &info_.value(),
-      continuation, &redirect_url_, &should_collapse_initiator);
+      factory_->browser_context_, &info_.value(), continuation, &redirect_url_,
+      &should_collapse_initiator);
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
     // The request was cancelled synchronously. Dispatch an error notification
     // and terminate the request.
@@ -305,8 +335,7 @@
 
   target_client_->OnComplete(status);
   ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
-      factory_->browser_context_, factory_->info_map_, &info_.value(),
-      status.error_code);
+      factory_->browser_context_, &info_.value(), status.error_code);
 
   // Deletes |this|.
   factory_->RemoveRequest(network_service_request_id_, request_id_);
@@ -461,8 +490,8 @@
         &InProgressRequest::ContinueToSendHeaders, weak_factory_.GetWeakPtr());
     int result =
         ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
-            factory_->browser_context_, factory_->info_map_, &info_.value(),
-            continuation, &request_.headers);
+            factory_->browser_context_, &info_.value(), continuation,
+            &request_.headers);
 
     if (result == net::ERR_BLOCKED_BY_CLIENT) {
       // The request was cancelled synchronously. Dispatch an error notification
@@ -573,8 +602,7 @@
     // intuitive), |onSendHeaders| is only dispatched for HTTP and HTTPS
     // requests.
     ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
-        factory_->browser_context_, factory_->info_map_, &info_.value(),
-        request_.headers);
+        factory_->browser_context_, &info_.value(), request_.headers);
   }
 
   if (!current_request_uses_header_client_)
@@ -586,9 +614,9 @@
     WebRequestAPI::AuthRequestCallback callback,
     int error_code) {
   if (error_code != net::OK) {
-    base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                             base::BindOnce(std::move(callback), base::nullopt,
-                                            true /* should_cancel */));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), base::nullopt,
+                                  true /* should_cancel */));
     return;
   }
 
@@ -600,8 +628,8 @@
   auth_credentials_.emplace();
   net::NetworkDelegate::AuthRequiredResponse response =
       ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired(
-          factory_->browser_context_, factory_->info_map_, &info_.value(),
-          auth_info, continuation, &auth_credentials_.value());
+          factory_->browser_context_, &info_.value(), auth_info, continuation,
+          &auth_credentials_.value());
 
   // At least one extension has a blocking handler for this request, so we'll
   // just wait for them to finish. |OnAuthRequestHandled()| will be invoked
@@ -644,8 +672,8 @@
   }
 
   auth_credentials_ = base::nullopt;
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                           std::move(completion));
+  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                   std::move(completion));
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::
@@ -717,7 +745,7 @@
   proxied_client_binding_.ResumeIncomingMethodCallProcessing();
 
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
-      factory_->browser_context_, factory_->info_map_, &info_.value(), net::OK);
+      factory_->browser_context_, &info_.value(), net::OK);
   target_client_->OnReceiveResponse(current_response_);
 }
 
@@ -735,8 +763,7 @@
     proxied_client_binding_.ResumeIncomingMethodCallProcessing();
 
   ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
-      factory_->browser_context_, factory_->info_map_, &info_.value(),
-      redirect_info.new_url);
+      factory_->browser_context_, &info_.value(), redirect_info.new_url);
   target_client_->OnReceiveRedirect(redirect_info, current_response_);
   request_.url = redirect_info.new_url;
   request_.method = redirect_info.new_method;
@@ -763,9 +790,9 @@
     DCHECK(info_.has_value());
     int result =
         ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
-            factory_->browser_context_, factory_->info_map_, &info_.value(),
-            copyable_callback, current_response_.headers.get(),
-            &override_headers_, &redirect_url_);
+            factory_->browser_context_, &info_.value(), copyable_callback,
+            current_response_.headers.get(), &override_headers_,
+            &redirect_url_);
     if (result == net::ERR_BLOCKED_BY_CLIENT) {
       OnRequestError(network::URLLoaderCompletionStatus(result));
       return;
@@ -791,8 +818,8 @@
   if (!request_completed_) {
     target_client_->OnComplete(status);
     ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
-        factory_->browser_context_, factory_->info_map_, &info_.value(),
-        true /* started */, status.error_code);
+        factory_->browser_context_, &info_.value(), true /* started */,
+        status.error_code);
   }
 
   // Deletes |this|.
@@ -805,7 +832,9 @@
     const GURL& to_url) {
   if (to_url.SchemeIs(extensions::kExtensionScheme)) {
     const Extension* extension =
-        factory_->info_map_->extensions().GetByID(to_url.host());
+        ExtensionRegistry::Get(factory_->browser_context_)
+            ->enabled_extensions()
+            .GetByID(to_url.host());
     if (!extension)
       return false;
     return WebAccessibleResourcesInfo::IsResourceWebAccessible(extension,
@@ -815,27 +844,31 @@
 }
 
 WebRequestProxyingURLLoaderFactory::WebRequestProxyingURLLoaderFactory(
-    void* browser_context,
-    content::ResourceContext* resource_context,
+    content::BrowserContext* browser_context,
     int render_process_id,
     bool is_download,
     scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
     std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
-    InfoMap* info_map,
     network::mojom::URLLoaderFactoryRequest loader_request,
     network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
     network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request,
     WebRequestAPI::ProxySet* proxies)
     : browser_context_(browser_context),
-      resource_context_(resource_context),
       render_process_id_(render_process_id),
       is_download_(is_download),
       request_id_generator_(std::move(request_id_generator)),
       navigation_ui_data_(std::move(navigation_ui_data)),
-      info_map_(info_map),
       url_loader_header_client_binding_(this),
       proxies_(proxies) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // base::Unretained is safe here because the callback will be canceled when
+  // |shutdown_notifier_| is destroyed, and |proxies_| owns this.
+  shutdown_notifier_ =
+      ShutdownNotifierFactory::GetInstance()
+          ->Get(browser_context)
+          ->Subscribe(base::BindRepeating(&WebRequestAPI::ProxySet::RemoveProxy,
+                                          base::Unretained(proxies_), this));
+
   target_factory_.Bind(std::move(target_factory_info));
   target_factory_.set_connection_error_handler(
       base::BindOnce(&WebRequestProxyingURLLoaderFactory::OnTargetFactoryError,
@@ -850,23 +883,20 @@
 }
 
 void WebRequestProxyingURLLoaderFactory::StartProxying(
-    void* browser_context,
-    content::ResourceContext* resource_context,
+    content::BrowserContext* browser_context,
     int render_process_id,
     bool is_download,
     scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
     std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
-    InfoMap* info_map,
     network::mojom::URLLoaderFactoryRequest loader_request,
     network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
-    network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  auto* proxies =
-      WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
+    network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request,
+    WebRequestAPI::ProxySet* proxies) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   auto proxy = std::make_unique<WebRequestProxyingURLLoaderFactory>(
-      browser_context, resource_context, render_process_id, is_download,
-      std::move(request_id_generator), std::move(navigation_ui_data), info_map,
+      browser_context, render_process_id, is_download,
+      std::move(request_id_generator), std::move(navigation_ui_data),
       std::move(loader_request), std::move(target_factory_info),
       std::move(header_client_request), proxies);
 
@@ -881,7 +911,7 @@
     const network::ResourceRequest& request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Make sure we are not proxying a browser initiated non-navigation request.
   DCHECK(render_process_id_ != -1 || navigation_ui_data_);
@@ -912,7 +942,7 @@
 
 void WebRequestProxyingURLLoaderFactory::Clone(
     network::mojom::URLLoaderFactoryRequest loader_request) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   proxy_bindings_.AddBinding(this, std::move(loader_request));
 }
 
@@ -935,9 +965,9 @@
     WebRequestAPI::AuthRequestCallback callback) {
   auto it = network_request_id_to_web_request_id_.find(request_id);
   if (it == network_request_id_to_web_request_id_.end()) {
-    base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                             base::BindOnce(std::move(callback), base::nullopt,
-                                            true /* should_cancel */));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), base::nullopt,
+                                  true /* should_cancel */));
     return;
   }
 
@@ -951,7 +981,7 @@
     default;
 
 void WebRequestProxyingURLLoaderFactory::OnTargetFactoryError() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   target_factory_.reset();
   proxy_bindings_.CloseAllBindings();
 
@@ -959,7 +989,7 @@
 }
 
 void WebRequestProxyingURLLoaderFactory::OnProxyBindingError() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (proxy_bindings_.empty())
     target_factory_.reset();
 
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 1c08d98..83352e0b 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -26,21 +27,12 @@
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
-namespace content {
-class ResourceContext;
-}  // namespace content
-
 namespace extensions {
 
 class ExtensionNavigationUIData;
-class InfoMap;
 
 // Owns URLLoaderFactory bindings for WebRequest proxies with the Network
-// Service enabled. This is loosely controlled by the WebRequestAPI on the UI
-// thread, but does all its real work on the IO thread. This is only because
-// it is tightly coupled to ExtensionsWebRequestEventRouter, and that object
-// must stay on the IO thread.
-// TODO(http://crbug.com/824840): Move this to the UI thread.
+// Service enabled.
 class WebRequestProxyingURLLoaderFactory
     : public WebRequestAPI::Proxy,
       public network::mojom::URLLoaderFactory,
@@ -192,13 +184,11 @@
   };
 
   WebRequestProxyingURLLoaderFactory(
-      void* browser_context,
-      content::ResourceContext* resource_context,
+      content::BrowserContext* browser_context,
       int render_process_id,
       bool is_download,
       scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
       std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
-      InfoMap* info_map,
       network::mojom::URLLoaderFactoryRequest loader_request,
       network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
       network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request,
@@ -207,17 +197,15 @@
   ~WebRequestProxyingURLLoaderFactory() override;
 
   static void StartProxying(
-      void* browser_context,
-      content::ResourceContext* resource_context,
+      content::BrowserContext* browser_context,
       int render_process_id,
       bool is_download,
       scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
       std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
-      InfoMap* info_map,
       network::mojom::URLLoaderFactoryRequest loader_request,
       network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
-      network::mojom::TrustedURLLoaderHeaderClientRequest
-          header_client_request);
+      network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request,
+      WebRequestAPI::ProxySet* proxies);
 
   // network::mojom::URLLoaderFactory:
   void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader_request,
@@ -248,13 +236,11 @@
   void RemoveRequest(int32_t network_service_request_id, uint64_t request_id);
   void MaybeRemoveProxy();
 
-  void* const browser_context_;
-  content::ResourceContext* const resource_context_;
+  content::BrowserContext* const browser_context_;
   const int render_process_id_;
   const bool is_download_;
   scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator_;
   std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data_;
-  InfoMap* const info_map_;
   mojo::BindingSet<network::mojom::URLLoaderFactory> proxy_bindings_;
   network::mojom::URLLoaderFactoryPtr target_factory_;
   mojo::Binding<network::mojom::TrustedURLLoaderHeaderClient>
@@ -270,6 +256,10 @@
   // internally generated request ID for the same request.
   std::map<int32_t, uint64_t> network_request_id_to_web_request_id_;
 
+  // Notifies the proxy that the browser context has been shutdown.
+  std::unique_ptr<KeyedServiceShutdownNotifier::Subscription>
+      shutdown_notifier_;
+
   base::WeakPtrFactory<WebRequestProxyingURLLoaderFactory> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebRequestProxyingURLLoaderFactory);
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.cc b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
index 5fb8ccb..0a4e292 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
@@ -7,13 +7,42 @@
 #include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/ip_endpoint.h"
 #include "net/http/http_util.h"
 
 namespace extensions {
+namespace {
+
+// This shutdown notifier makes sure the proxy is destroyed if an incognito
+// browser context is destroyed. This is needed because WebRequestAPI only
+// clears the proxies when the original browser context is destroyed.
+class ShutdownNotifierFactory
+    : public BrowserContextKeyedServiceShutdownNotifierFactory {
+ public:
+  static ShutdownNotifierFactory* GetInstance() {
+    static base::NoDestructor<ShutdownNotifierFactory> factory;
+    return factory.get();
+  }
+
+ private:
+  friend class base::NoDestructor<ShutdownNotifierFactory>;
+
+  ShutdownNotifierFactory()
+      : BrowserContextKeyedServiceShutdownNotifierFactory(
+            "WebRequestProxyingWebSocket") {
+    DependsOn(PermissionHelper::GetFactoryInstance());
+  }
+  ~ShutdownNotifierFactory() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory);
+};
+
+}  // namespace
 
 WebRequestProxyingWebSocket::WebRequestProxyingWebSocket(
     WebSocketFactory factory,
@@ -23,13 +52,10 @@
     int process_id,
     int render_frame_id,
     content::BrowserContext* browser_context,
-    content::ResourceContext* resource_context,
-    InfoMap* info_map,
     scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
     WebRequestAPI::ProxySet* proxies)
     : factory_(std::move(factory)),
       browser_context_(browser_context),
-      info_map_(info_map),
       forwarding_handshake_client_(std::move(handshake_client)),
       binding_as_handshake_client_(this),
       binding_as_auth_handler_(this),
@@ -40,11 +66,18 @@
                                      render_frame_id,
                                      nullptr,
                                      MSG_ROUTING_NONE,
-                                     resource_context,
                                      request,
                                      false /* is_download */,
                                      true /* is_async */)),
-      proxies_(proxies) {}
+      proxies_(proxies) {
+  // base::Unretained is safe here because the callback will be canceled when
+  // |shutdown_notifier_| is destroyed, and |proxies_| owns this.
+  shutdown_notifier_ =
+      ShutdownNotifierFactory::GetInstance()
+          ->Get(browser_context)
+          ->Subscribe(base::BindRepeating(&WebRequestAPI::ProxySet::RemoveProxy,
+                                          base::Unretained(proxies_), this));
+}
 
 WebRequestProxyingWebSocket::~WebRequestProxyingWebSocket() {
   // This is important to ensure that no outstanding blocking requests continue
@@ -80,7 +113,7 @@
   // WebRequestProxyingURLLoaderFactory).
   bool should_collapse_initiator = false;
   int result = ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
-      browser_context_, info_map_, &info_, continuation, &redirect_url_,
+      browser_context_, &info_, continuation, &redirect_url_,
       &should_collapse_initiator);
 
   // It doesn't make sense to collapse WebSocket requests since they won't be
@@ -142,8 +175,8 @@
       &WebRequestProxyingWebSocket::OnHeadersReceivedComplete,
       weak_factory_.GetWeakPtr());
   int result = ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
-      browser_context_, info_map_, &info_, continuation,
-      response_.headers.get(), &override_headers_, &redirect_url_);
+      browser_context_, &info_, continuation, response_.headers.get(),
+      &override_headers_, &redirect_url_);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
     OnError(result);
@@ -167,7 +200,7 @@
   DCHECK(!is_done_);
   is_done_ = true;
   ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
-      browser_context_, info_map_, &info_, net::ERR_WS_UPGRADE);
+      browser_context_, &info_, net::ERR_WS_UPGRADE);
 
   forwarding_handshake_client_->OnConnectionEstablished(
       std::move(websocket), selected_protocol, extensions,
@@ -195,8 +228,8 @@
       &WebRequestProxyingWebSocket::OnHeadersReceivedCompleteForAuth,
       weak_factory_.GetWeakPtr(), auth_info);
   int result = ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
-      browser_context_, info_map_, &info_, continuation,
-      response_.headers.get(), &override_headers_, &redirect_url_);
+      browser_context_, &info_, continuation, response_.headers.get(),
+      &override_headers_, &redirect_url_);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
     OnError(result);
@@ -251,11 +284,8 @@
     scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
     const url::Origin& origin,
     content::BrowserContext* browser_context,
-    content::ResourceContext* resource_context,
-    InfoMap* info_map) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  auto* proxies =
-      WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
+    WebRequestAPI::ProxySet* proxies) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   network::ResourceRequest request;
   request.url = url;
   request.site_for_cookies = site_for_cookies;
@@ -268,7 +298,7 @@
       std::move(factory), request,
       network::mojom::WebSocketHandshakeClientPtr(std::move(handshake_client)),
       has_extra_headers, process_id, render_frame_id, browser_context,
-      resource_context, info_map, std::move(request_id_generator), proxies);
+      std::move(request_id_generator), proxies);
 
   auto* raw_proxy = proxy.get();
   proxies->AddProxy(std::move(proxy));
@@ -289,7 +319,7 @@
 
   int result =
       ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
-          browser_context_, info_map_, &info_, continuation, &request_headers_);
+          browser_context_, &info_, continuation, &request_headers_);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
     OnError(result);
@@ -321,7 +351,7 @@
   }
 
   ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
-      browser_context_, info_map_, &info_, request_headers_);
+      browser_context_, &info_, request_headers_);
 
   if (!binding_as_header_client_)
     ContinueToStartRequest(net::OK);
@@ -384,7 +414,7 @@
   ResumeIncomingMethodCallProcessing();
   info_.AddResponseInfoFromResourceResponse(response_);
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
-      browser_context_, info_map_, &info_, net::OK);
+      browser_context_, &info_, net::OK);
 }
 
 void WebRequestProxyingWebSocket::OnAuthRequiredComplete(
@@ -420,7 +450,7 @@
       base::BindRepeating(&WebRequestProxyingWebSocket::OnAuthRequiredComplete,
                           weak_factory_.GetWeakPtr());
   auto auth_rv = ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired(
-      browser_context_, info_map_, &info_, auth_info, std::move(continuation),
+      browser_context_, &info_, auth_info, std::move(continuation),
       &auth_credentials_);
   PauseIncomingMethodCallProcessing();
   if (auth_rv == net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING)
@@ -447,7 +477,7 @@
   if (!is_done_) {
     is_done_ = true;
     ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
-        browser_context_, info_map_, &info_, true /* started */, error_code);
+        browser_context_, &info_, true /* started */, error_code);
   }
 
   // Deletes |this|.
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.h b/extensions/browser/api/web_request/web_request_proxying_websocket.h
index 0601834..ff2a39cc 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.h
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -49,8 +50,6 @@
       int process_id,
       int render_frame_id,
       content::BrowserContext* browser_context,
-      content::ResourceContext* resource_context,
-      InfoMap* info_map,
       scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
       WebRequestAPI::ProxySet* proxies);
   ~WebRequestProxyingWebSocket() override;
@@ -91,8 +90,7 @@
       scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
       const url::Origin& origin,
       content::BrowserContext* browser_context,
-      content::ResourceContext* resource_context,
-      InfoMap* info_map);
+      WebRequestAPI::ProxySet* proxies);
 
  private:
   void OnBeforeRequestComplete(int error_code);
@@ -112,7 +110,6 @@
 
   WebSocketFactory factory_;
   content::BrowserContext* const browser_context_;
-  InfoMap* const info_map_;
   network::mojom::WebSocketHandshakeClientPtr forwarding_handshake_client_;
   mojo::Binding<network::mojom::WebSocketHandshakeClient>
       binding_as_handshake_client_;
@@ -138,6 +135,10 @@
   // Owns |this|.
   WebRequestAPI::ProxySet* const proxies_;
 
+  // Notifies the proxy that the browser context has been shutdown.
+  std::unique_ptr<KeyedServiceShutdownNotifier::Subscription>
+      shutdown_notifier_;
+
   base::WeakPtrFactory<WebRequestProxyingWebSocket> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(WebRequestProxyingWebSocket);
 };
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index 9333c25..a7e96cd8 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -138,22 +138,12 @@
                                         int64_t service_worker_version_id,
                                         std::unique_ptr<ListValue> event_args,
                                         const EventFilteringInfo& info) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   int event_id = g_extension_event_id.GetNext();
 
-  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    DoDispatchEventToSenderBookkeepingOnUI(
-        browser_context_id, extension_id, event_id, render_process_id,
-        service_worker_version_id, histogram_value, event_name);
-  } else {
-    // This is called from WebRequest API.
-    // TODO(lazyboy): Skip this entirely: http://crbug.com/488747.
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&EventRouter::DoDispatchEventToSenderBookkeepingOnUI,
-                       browser_context_id, extension_id, event_id,
-                       render_process_id, service_worker_version_id,
-                       histogram_value, event_name));
-  }
+  DoDispatchEventToSenderBookkeepingOnUI(
+      browser_context_id, extension_id, event_id, render_process_id,
+      service_worker_version_id, histogram_value, event_name);
 
   DispatchExtensionMessage(ipc_sender, worker_thread_id, browser_context_id,
                            extension_id, event_id, event_name, event_args.get(),
diff --git a/extensions/browser/extension_api_frame_id_map.cc b/extensions/browser/extension_api_frame_id_map.cc
index 555cd8c2..071abda 100644
--- a/extensions/browser/extension_api_frame_id_map.cc
+++ b/extensions/browser/extension_api_frame_id_map.cc
@@ -30,13 +30,6 @@
 base::LazyInstance<ExtensionApiFrameIdMap>::Leaky g_map_instance =
     LAZY_INSTANCE_INITIALIZER;
 
-bool IsFrameRoutingIdValid(int frame_routing_id) {
-  // frame_routing_id == -2 = MSG_ROUTING_NONE -> not a RenderFrameHost.
-  // frame_routing_id == -1 -> should be MSG_ROUTING_NONE, but there are
-  // callers that use "-1" for unknown frames.
-  return frame_routing_id > -1;
-}
-
 }  // namespace
 
 const int ExtensionApiFrameIdMap::kInvalidFrameId = -1;
@@ -195,8 +188,7 @@
 }
 
 ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::LookupFrameDataOnUI(
-    const RenderFrameIdKey& key,
-    bool is_from_io) {
+    const RenderFrameIdKey& key) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   bool lookup_successful = false;
@@ -211,125 +203,12 @@
     if (data.frame_id != kInvalidFrameId) {
       lookup_successful = true;
       auto kvpair = FrameDataMap::value_type(key, data);
-      base::AutoLock lock(frame_data_map_lock_);
       frame_data_map_.insert(kvpair);
     }
   }
-
-  // TODO(devlin): Depending on how the data looks, this may be removable after
-  // a few cycles. Check back in M52 to see if it's still needed.
-  if (is_from_io) {
-    UMA_HISTOGRAM_BOOLEAN("Extensions.ExtensionFrameMapLookupSuccessful",
-                          lookup_successful);
-  }
-
   return data;
 }
 
-void ExtensionApiFrameIdMap::ReceivedFrameDataOnIO(
-    const RenderFrameIdKey& key,
-    const FrameData& cached_frame_data) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  auto map_iter = callbacks_map_.find(key);
-  if (map_iter == callbacks_map_.end()) {
-    // Can happen if ReceivedFrameDataOnIO was called after the frame ID was
-    // resolved (e.g. via GetFrameDataOnIO), but before PostTaskAndReply
-    // replied.
-    return;
-  }
-
-  FrameDataCallbacks& callbacks = map_iter->second;
-
-  if (callbacks.is_iterating)
-    return;
-  callbacks.is_iterating = true;
-
-  // Note: Extra items can be appended to |callbacks| during this loop if a
-  // callback calls GetFrameDataOnIO().
-  for (auto it = callbacks.callbacks.begin(); it != callbacks.callbacks.end();
-       ++it) {
-    it->Run(cached_frame_data);
-  }
-  callbacks_map_.erase(key);
-}
-
-void ExtensionApiFrameIdMap::GetFrameDataOnIO(
-    int render_process_id,
-    int frame_routing_id,
-    const FrameDataCallback& callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  // TODO(robwu): Enable assertion when all callers have been fixed.
-  // DCHECK_EQ(MSG_ROUTING_NONE, -1);
-  if (!IsFrameRoutingIdValid(frame_routing_id)) {
-    callback.Run(FrameData());
-    return;
-  }
-
-  FrameData cached_frame_data;
-  bool did_find_cached_frame_data = GetCachedFrameDataOnIO(
-      render_process_id, frame_routing_id, &cached_frame_data);
-
-  const RenderFrameIdKey key(render_process_id, frame_routing_id);
-  auto map_iter = callbacks_map_.find(key);
-
-  if (did_find_cached_frame_data) {
-    // Value already cached, thread hopping is not needed.
-    if (map_iter == callbacks_map_.end()) {
-      // If the frame ID was cached, then it is likely that there are no pending
-      // callbacks. So do not unnecessarily copy the callback, but run it.
-      callback.Run(cached_frame_data);
-    } else {
-      map_iter->second.callbacks.push_back(callback);
-      ReceivedFrameDataOnIO(key, cached_frame_data);
-    }
-    return;
-  }
-
-  // The key was seen for the first time (or the frame has been removed).
-  // Hop to the UI thread to look up the extension API frame ID.
-  callbacks_map_[key].callbacks.push_back(callback);
-  base::PostTaskWithTraitsAndReplyWithResult(
-      FROM_HERE, {content::BrowserThread::UI},
-      base::Bind(&ExtensionApiFrameIdMap::LookupFrameDataOnUI,
-                 base::Unretained(this), key, true /* is_from_io */),
-      base::Bind(&ExtensionApiFrameIdMap::ReceivedFrameDataOnIO,
-                 base::Unretained(this), key));
-}
-
-bool ExtensionApiFrameIdMap::GetCachedFrameDataOnIO(int render_process_id,
-                                                    int frame_routing_id,
-                                                    FrameData* frame_data_out) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  // TODO(robwu): Enable assertion when all callers have been fixed.
-  // DCHECK_EQ(MSG_ROUTING_NONE, -1);
-  if (!IsFrameRoutingIdValid(frame_routing_id))
-    return false;
-
-  // A valid routing ID is only meaningful with a valid process ID.
-  DCHECK_GE(render_process_id, 0);
-
-  bool found = false;
-  {
-    base::AutoLock lock(frame_data_map_lock_);
-    FrameDataMap::const_iterator frame_id_iter = frame_data_map_.find(
-        RenderFrameIdKey(render_process_id, frame_routing_id));
-    if (frame_id_iter != frame_data_map_.end()) {
-      // This is very likely to happen because CacheFrameData() is called as
-      // soon as the frame is created.
-      *frame_data_out = frame_id_iter->second;
-      found = true;
-    }
-  }
-
-  // TODO(devlin): Depending on how the data looks, this may be removable after
-  // a few cycles. Check back in M52 to see if it's still needed.
-  UMA_HISTOGRAM_BOOLEAN("Extensions.ExtensionFrameMapCacheHit", found);
-  return found;
-}
-
 ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::GetFrameData(
     content::RenderFrameHost* rfh) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -338,7 +217,7 @@
     return FrameData();
 
   const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
-  return LookupFrameDataOnUI(key, false /* is_from_io */);
+  return LookupFrameDataOnUI(key);
 }
 
 void ExtensionApiFrameIdMap::InitializeRenderFrameData(
@@ -353,7 +232,7 @@
 }
 
 void ExtensionApiFrameIdMap::CacheFrameData(const RenderFrameIdKey& key) {
-  LookupFrameDataOnUI(key, false /* is_from_io */);
+  LookupFrameDataOnUI(key);
 }
 
 void ExtensionApiFrameIdMap::OnRenderFrameDeleted(
@@ -378,7 +257,6 @@
     return;
   }
 
-  base::AutoLock lock(frame_data_map_lock_);
   auto iter = frame_data_map_.find(key);
   // The FrameData for |rfh| should have already been initialized.
   DCHECK(iter != frame_data_map_.end());
@@ -406,7 +284,6 @@
 
   const RenderFrameIdKey key(main_frame->GetProcess()->GetID(),
                              main_frame->GetRoutingID());
-  base::AutoLock lock(frame_data_map_lock_);
   auto iter = frame_data_map_.find(key);
 
   // We must have already cached the FrameData for this in
@@ -448,7 +325,6 @@
 
   const RenderFrameIdKey key(main_frame->GetProcess()->GetID(),
                              main_frame->GetRoutingID());
-  base::AutoLock lock(frame_data_map_lock_);
   auto iter = frame_data_map_.find(key);
 
   // We must have already cached the FrameData for this in
@@ -477,7 +353,6 @@
 void ExtensionApiFrameIdMap::RemoveFrameData(const RenderFrameIdKey& key) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  base::AutoLock lock(frame_data_map_lock_);
   frame_data_map_.erase(key);
 }
 
diff --git a/extensions/browser/extension_api_frame_id_map.h b/extensions/browser/extension_api_frame_id_map.h
index d90b4fc..c259da1 100644
--- a/extensions/browser/extension_api_frame_id_map.h
+++ b/extensions/browser/extension_api_frame_id_map.h
@@ -25,6 +25,8 @@
 
 namespace extensions {
 
+// TODO(http://crbug.com/980774): Investigate if this class and
+// ExtensionApiFrameIdMap are still needed.
 class ExtensionApiFrameIdMapHelper {
  public:
   virtual void PopulateTabData(content::RenderFrameHost* rfh,
@@ -50,12 +52,9 @@
 //
 // Unless stated otherwise, the methods can only be called on the UI thread.
 //
-// The non-static methods of this class use an internal cache. This cache is
-// used to minimize IO->UI->IO round-trips of GetFrameIdOnIO. If the cost of
-// attaching FrameTreeNode IDs to requests is negligible (crbug.com/524228),
-// then we can remove all key caching and remove the cache from this class.
-// TODO(robwu): Keep an eye on crbug.com/524228 and act upon the outcome.
-// TODO(devlin): Also keep an eye on FrameIOData to see if that could help.
+// The non-static methods of this class use an internal cache.
+// TODO(http://crbug.com/980774): This cache may not be necessary now that this
+// is not accessed on IO.
 class ExtensionApiFrameIdMap {
  public:
   // The data for a RenderFrame. Every RenderFrameIdKey maps to a FrameData.
@@ -124,21 +123,6 @@
       content::WebContents* web_contents,
       int frame_id);
 
-  // Runs |callback| with a result that is equivalent to calling GetFrameData()
-  // on the UI thread. Thread hopping is minimized if possible. Callbacks for
-  // the same |render_process_id| and |frame_routing_id| are guaranteed to be
-  // run in order. The order of other callbacks is undefined.
-  void GetFrameDataOnIO(int render_process_id,
-                        int frame_routing_id,
-                        const FrameDataCallback& callback);
-
-  // Attempts to populate |frame_data_out| with the FrameData for the specified
-  // frame, but only does so if the data is already cached. Returns true if
-  // cached frame data was found.
-  bool GetCachedFrameDataOnIO(int render_process_id,
-                              int frame_routing_id,
-                              FrameData* frame_data_out);
-
   // Retrieves the FrameData for a given |rfh|. The map may be updated with the
   // result if the map did not contain the FrameData before the lookup.
   // If |rfh| is nullptr, then the map is not modified.
@@ -215,13 +199,7 @@
   virtual FrameData KeyToValue(const RenderFrameIdKey& key) const;
 
   // Looks up the data for the given |key| and adds it to the |frame_data_map_|.
-  // |is_from_io| indicates whether the lookup originated from the IO thread.
-  FrameData LookupFrameDataOnUI(const RenderFrameIdKey& key, bool is_from_io);
-
-  // Called as soon as the frame data is found for the given |key|, and runs all
-  // queued callbacks with |cached_frame_data|.
-  void ReceivedFrameDataOnIO(const RenderFrameIdKey& key,
-                             const FrameData& cached_frame_data);
+  FrameData LookupFrameDataOnUI(const RenderFrameIdKey& key);
 
   // Implementation of CacheFrameData(RenderFrameHost), separated for testing.
   void CacheFrameData(const RenderFrameIdKey& key);
@@ -231,18 +209,10 @@
 
   std::unique_ptr<ExtensionApiFrameIdMapHelper> helper_;
 
-  // Queued callbacks for use on the IO thread.
-  FrameDataCallbacksMap callbacks_map_;
-
-  // This map is only modified on the UI thread and is used to minimize the
-  // number of thread hops on the IO thread.
+  // This map holds a mapping of render frame key to FrameData.
+  // TODO(http://crbug.com/980774): Investigate if this is still needed.
   FrameDataMap frame_data_map_;
 
-  // This lock protects |frame_data_map_| from being concurrently written on the
-  // UI thread and read on the IO thread. Acquire during a read on the IO thread
-  // and during a write on the UI thread.
-  base::Lock frame_data_map_lock_;
-
   // The set of pending main frame navigations for which ReadyToCommitNavigation
   // has been fired. Only used on the UI thread. This is needed to clear state
   // set up in OnMainFrameReadyToCommitNavigation for navigations which
diff --git a/extensions/browser/extension_api_frame_id_map_unittest.cc b/extensions/browser/extension_api_frame_id_map_unittest.cc
deleted file mode 100644
index 1a77fbd..0000000
--- a/extensions/browser/extension_api_frame_id_map_unittest.cc
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/extension_api_frame_id_map.h"
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "extensions/common/constants.h"
-#include "ipc/ipc_message.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace extensions {
-
-namespace {
-
-using FrameDataCallback = extensions::ExtensionApiFrameIdMap::FrameDataCallback;
-
-int ToTestFrameId(int render_process_id, int frame_routing_id) {
-  if (render_process_id < 0 && frame_routing_id < 0)
-    return ExtensionApiFrameIdMap::kInvalidFrameId;
-  // Return a deterministic value (yet different from the input) for testing.
-  // To make debugging easier: Ending with 0 = frame ID.
-  return render_process_id * 1000 + frame_routing_id * 10;
-}
-
-int ToTestParentFrameId(int render_process_id, int frame_routing_id) {
-  if (render_process_id < 0 && frame_routing_id < 0)
-    return ExtensionApiFrameIdMap::kInvalidFrameId;
-  // Return a deterministic value (yet different from the input) for testing.
-  // To make debugging easier: Ending with 7 = parent frame ID.
-  return render_process_id * 1000 + frame_routing_id * 10 + 7;
-}
-
-int ToTestTabId(int render_process_id, int frame_routing_id) {
-  if (render_process_id < 0 && frame_routing_id < 0)
-    return extension_misc::kUnknownTabId;
-  // Return a deterministic value (yet different from the input) for testing.
-  // To make debugging easier: Ending with 5 = tab ID.
-  return render_process_id * 1000 + frame_routing_id * 10 + 5;
-}
-
-int ToTestWindowId(int render_process_id, int frame_routing_id) {
-  if (render_process_id < 0 && frame_routing_id < 0)
-    return extension_misc::kUnknownWindowId;
-  // Return a deterministic value (yet different from the input) for testing.
-  // To make debugging easier: Ending with 4 = window ID.
-  return render_process_id * 1000 + frame_routing_id * 10 + 4;
-}
-
-GURL ToTestLastCommittedMainFrameURL(int render_process_id,
-                                     int frame_routing_id) {
-  if (render_process_id < 0 && frame_routing_id < 0)
-    return GURL();
-
-  // Return a deterministic value (yet different from the input) for testing.
-  return GURL(base::StringPrintf("http://%d.com/%d", render_process_id,
-                                 frame_routing_id));
-}
-
-class TestExtensionApiFrameIdMap : public ExtensionApiFrameIdMap {
- public:
-  TestExtensionApiFrameIdMap() {}
-  ~TestExtensionApiFrameIdMap() override {}
-
-  int GetInternalSize() { return frame_data_map_.size(); }
-  int GetInternalCallbackCount() {
-    int count = 0;
-    for (auto& it : callbacks_map_)
-      count += it.second.callbacks.size();
-    return count;
-  }
-
-  // These indirections are used because we cannot mock RenderFrameHost with
-  // fixed IDs in unit tests.
-  // TODO(robwu): Use content/public/test/test_renderer_host.h to mock
-  // RenderFrameHosts and update the tests to test against these mocks.
-  // After doing that, there is no need for CacheFrameData/RemoveFrameData
-  // methods that take a RenderFrameIdKey, so the methods can be merged.
-  void SetInternalFrameData(int render_process_id, int frame_routing_id) {
-    CacheFrameData(RenderFrameIdKey(render_process_id, frame_routing_id));
-  }
-  void RemoveInternalFrameData(int render_process_id, int frame_routing_id) {
-    RemoveFrameData(RenderFrameIdKey(render_process_id, frame_routing_id));
-  }
-
- private:
-  // ExtensionApiFrameIdMap:
-  FrameData KeyToValue(const RenderFrameIdKey& key) const override {
-    return FrameData(
-        ToTestFrameId(key.render_process_id, key.frame_routing_id),
-        ToTestParentFrameId(key.render_process_id, key.frame_routing_id),
-        ToTestTabId(key.render_process_id, key.frame_routing_id),
-        ToTestWindowId(key.render_process_id, key.frame_routing_id),
-        ToTestLastCommittedMainFrameURL(key.render_process_id,
-                                        key.frame_routing_id));
-  }
-};
-
-class ExtensionApiFrameIdMapTest : public testing::Test {
- public:
-  ExtensionApiFrameIdMapTest()
-      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
-
-  FrameDataCallback CreateCallback(
-      int render_process_id,
-      int frame_routing_id,
-      const std::string& callback_name_for_testing) {
-    return base::Bind(&ExtensionApiFrameIdMapTest::OnCalledCallback,
-                      base::Unretained(this), render_process_id,
-                      frame_routing_id, callback_name_for_testing);
-  }
-
-  void OnCalledCallback(int render_process_id,
-                        int frame_routing_id,
-                        const std::string& callback_name_for_testing,
-                        const ExtensionApiFrameIdMap::FrameData& frame_data) {
-    results_.push_back(callback_name_for_testing);
-
-    // If this fails, then the mapping is completely wrong.
-    EXPECT_EQ(ToTestFrameId(render_process_id, frame_routing_id),
-              frame_data.frame_id);
-    EXPECT_EQ(ToTestParentFrameId(render_process_id, frame_routing_id),
-              frame_data.parent_frame_id);
-    EXPECT_EQ(ToTestTabId(render_process_id, frame_routing_id),
-              frame_data.tab_id);
-    EXPECT_EQ(ToTestWindowId(render_process_id, frame_routing_id),
-              frame_data.window_id);
-    EXPECT_EQ(
-        ToTestLastCommittedMainFrameURL(render_process_id, frame_routing_id),
-        frame_data.last_committed_main_frame_url);
-  }
-
-  const std::vector<std::string>& results() { return results_; }
-  void ClearResults() { results_.clear(); }
-
- private:
-  content::TestBrowserThreadBundle thread_bundle_;
-  // Used to verify the order of callbacks.
-  std::vector<std::string> results_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionApiFrameIdMapTest);
-};
-
-}  // namespace
-
-TEST_F(ExtensionApiFrameIdMapTest, GetFrameDataOnIO) {
-  TestExtensionApiFrameIdMap map;
-  EXPECT_EQ(0, map.GetInternalSize());
-
-  // Two identical calls, should be processed at the next message loop.
-  map.GetFrameDataOnIO(1, 2, CreateCallback(1, 2, "first"));
-  EXPECT_EQ(1, map.GetInternalCallbackCount());
-  EXPECT_EQ(0, map.GetInternalSize());
-
-  map.GetFrameDataOnIO(1, 2, CreateCallback(1, 2, "first again"));
-  EXPECT_EQ(2, map.GetInternalCallbackCount());
-  EXPECT_EQ(0, map.GetInternalSize());
-
-  // First get the frame ID on IO (queued on message loop), then set it on UI.
-  // No callbacks should be invoked because the IO thread cannot know that the
-  // frame ID was set on the UI thread.
-  map.GetFrameDataOnIO(2, 1, CreateCallback(2, 1, "something else"));
-  EXPECT_EQ(3, map.GetInternalCallbackCount());
-  EXPECT_EQ(0, map.GetInternalSize());
-
-  map.SetInternalFrameData(2, 1);
-  EXPECT_EQ(1, map.GetInternalSize());
-  EXPECT_EQ(0U, results().size());
-
-  // Run some self-contained test. They should not affect the above callbacks.
-  {
-    // Callbacks for invalid IDs should immediately be run because it doesn't
-    // require a thread hop to determine their invalidity.
-    map.GetFrameDataOnIO(-1, MSG_ROUTING_NONE,
-                         CreateCallback(-1, MSG_ROUTING_NONE, "invalid IDs"));
-    EXPECT_EQ(3, map.GetInternalCallbackCount());  // No change.
-    EXPECT_EQ(1, map.GetInternalSize());           // No change.
-    ASSERT_EQ(1U, results().size());               // +1
-    EXPECT_EQ("invalid IDs", results()[0]);
-    ClearResults();
-  }
-
-  {
-    // First set the frame ID on UI, then get it on IO. Callback should
-    // immediately be invoked.
-    map.SetInternalFrameData(3, 1);
-    EXPECT_EQ(2, map.GetInternalSize());
-
-    map.GetFrameDataOnIO(3, 1, CreateCallback(3, 1, "the only result"));
-    EXPECT_EQ(3, map.GetInternalCallbackCount());  // No change.
-    EXPECT_EQ(2, map.GetInternalSize());           // +1
-    ASSERT_EQ(1U, results().size());               // +1
-    EXPECT_EQ("the only result", results()[0]);
-    ClearResults();
-  }
-
-  {
-    // Request the frame ID on IO, set the frame ID (in reality, set on the UI),
-    // and request another frame ID. The last query should cause both callbacks
-    // to run because the frame ID is known at the time of the call.
-    map.GetFrameDataOnIO(7, 2, CreateCallback(7, 2, "queued"));
-    EXPECT_EQ(4, map.GetInternalCallbackCount());  // +1
-
-    map.SetInternalFrameData(7, 2);
-    EXPECT_EQ(3, map.GetInternalSize());           // +1
-
-    map.GetFrameDataOnIO(7, 2, CreateCallback(7, 2, "not queued"));
-    EXPECT_EQ(3, map.GetInternalCallbackCount());  // -1 (first callback ran).
-    EXPECT_EQ(3, map.GetInternalSize());           // No change.
-    ASSERT_EQ(2U, results().size());               // +2 (both callbacks ran).
-    EXPECT_EQ("queued", results()[0]);
-    EXPECT_EQ("not queued", results()[1]);
-    ClearResults();
-  }
-
-  // A call identical to the very first call.
-  map.GetFrameDataOnIO(1, 2, CreateCallback(1, 2, "same as first"));
-  EXPECT_EQ(4, map.GetInternalCallbackCount());
-  EXPECT_EQ(3, map.GetInternalSize());
-
-  // Trigger the queued callbacks.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(0, map.GetInternalCallbackCount());   // -4 (no queued callbacks).
-
-  EXPECT_EQ(4, map.GetInternalSize());            // +1 (1 new cached frame ID).
-  ASSERT_EQ(4U, results().size());                // +4 (callbacks ran).
-
-  // PostTasks are processed in order, so the very first callbacks should be
-  // processed. As soon as the first callback is available, all of its callbacks
-  // should be run (no deferrals!).
-  EXPECT_EQ("first", results()[0]);
-  EXPECT_EQ("first again", results()[1]);
-  EXPECT_EQ("same as first", results()[2]);
-  // This was queued after "first again", but has a different frame ID, so it
-  // is received after "same as first".
-  EXPECT_EQ("something else", results()[3]);
-  ClearResults();
-
-  // Request the frame ID for input that was already looked up. Should complete
-  // synchronously.
-  map.GetFrameDataOnIO(1, 2, CreateCallback(1, 2, "first and cached"));
-  EXPECT_EQ(0, map.GetInternalCallbackCount());  // No change.
-  EXPECT_EQ(4, map.GetInternalSize());           // No change.
-  ASSERT_EQ(1U, results().size());               // +1 (synchronous callback).
-  EXPECT_EQ("first and cached", results()[0]);
-  ClearResults();
-
-  // Trigger frame removal and look up frame ID. The frame ID should no longer
-  // be available. and GetFrameDataOnIO() should require a thread hop.
-  map.RemoveInternalFrameData(1, 2);
-  EXPECT_EQ(3, map.GetInternalSize());           // -1
-  map.GetFrameDataOnIO(1, 2, CreateCallback(1, 2, "first was removed"));
-  EXPECT_EQ(1, map.GetInternalCallbackCount());  // +1
-  ASSERT_EQ(0U, results().size());               // No change (queued callback).
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(0, map.GetInternalCallbackCount());  // -1 (callback not in queue).
-  EXPECT_EQ(4, map.GetInternalSize());           // +1 (cached frame ID).
-  ASSERT_EQ(1U, results().size());               // +1 (callback ran).
-  EXPECT_EQ("first was removed", results()[0]);
-}
-
-TEST_F(ExtensionApiFrameIdMapTest, GetCachedFrameDataOnIO) {
-  TestExtensionApiFrameIdMap map;
-  EXPECT_EQ(0, map.GetInternalSize());
-
-  const int kRenderProcessId = 1;
-  const int kFrameRoutingId = 2;
-
-  // Getting cached data on the IO thread should fail if there is no cached
-  // data for the entry...
-  ExtensionApiFrameIdMap::FrameData data;
-  EXPECT_FALSE(
-      map.GetCachedFrameDataOnIO(kRenderProcessId, kFrameRoutingId, &data));
-  // ... should not queue any callbacks...
-  EXPECT_EQ(0, map.GetInternalCallbackCount());
-  base::RunLoop().RunUntilIdle();
-  // ... and should not add any entries to the map.
-  EXPECT_EQ(0, map.GetInternalSize());
-
-  // Getting cached data should succeed if there is a cached entry.
-  map.SetInternalFrameData(kRenderProcessId, kFrameRoutingId);
-  EXPECT_EQ(1, map.GetInternalSize());
-  EXPECT_TRUE(
-      map.GetCachedFrameDataOnIO(kRenderProcessId, kFrameRoutingId, &data));
-  EXPECT_EQ(0, map.GetInternalCallbackCount());
-  EXPECT_EQ(ToTestFrameId(kRenderProcessId, kFrameRoutingId), data.frame_id);
-  EXPECT_EQ(ToTestParentFrameId(kRenderProcessId, kFrameRoutingId),
-            data.parent_frame_id);
-  EXPECT_EQ(ToTestTabId(kRenderProcessId, kFrameRoutingId), data.tab_id);
-  EXPECT_EQ(ToTestWindowId(kRenderProcessId, kFrameRoutingId), data.window_id);
-  EXPECT_EQ(ToTestLastCommittedMainFrameURL(kRenderProcessId, kFrameRoutingId),
-            data.last_committed_main_frame_url);
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 1c0b86b..437e9b0a 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -553,6 +553,11 @@
     return dispatcher_.get();
   }
 
+  void set_worker_thread_id(int worker_thread_id) {
+    worker_thread_id_ = worker_thread_id;
+  }
+  int worker_thread_id() const { return worker_thread_id_; }
+
   // Returns the web contents associated with the sending |render_frame_host_|.
   // This can be null.
   content::WebContents* GetSenderWebContents();
@@ -593,6 +598,8 @@
   // The blobs transferred to the renderer process.
   std::vector<std::string> transferred_blob_uuids_;
 
+  int worker_thread_id_ = -1;
+
   DISALLOW_COPY_AND_ASSIGN(UIThreadExtensionFunction);
 };
 
@@ -603,6 +610,8 @@
 // requests). Generally, UIThreadExtensionFunction is more appropriate and will
 // be easier to use and interface with the rest of the browser.
 // To use this, specify `"forIOThread": true` in the function's schema.
+// TODO(http://crbug.com/980774): Remove this as it is no longer used. Also
+// remove "forIOThread" support in JSON.
 class IOThreadExtensionFunction : public ExtensionFunction {
  public:
   IOThreadExtensionFunction();
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc
index 08f523f..f63b7d3 100644
--- a/extensions/browser/extension_function_dispatcher.cc
+++ b/extensions/browser/extension_function_dispatcher.cc
@@ -475,6 +475,7 @@
     NOTREACHED();
     return;
   }
+  function_ui->set_worker_thread_id(params.worker_thread_id);
   if (IsRequestFromServiceWorker(params)) {
     function_ui->set_service_worker_version_id(
         params.service_worker_version_id);
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc
index 3cd9723c..854ea5ae 100644
--- a/extensions/browser/extension_util.cc
+++ b/extensions/browser/extension_util.cc
@@ -50,6 +50,16 @@
   return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
 }
 
+bool CanCrossIncognito(const Extension* extension,
+                       content::BrowserContext* context) {
+  // We allow the extension to see events and data from another profile iff it
+  // uses "spanning" behavior and it has incognito access. "split" mode
+  // extensions only see events for a matching profile.
+  CHECK(extension);
+  return IsIncognitoEnabled(extension->id(), context) &&
+         !IncognitoInfo::IsSplitMode(extension);
+}
+
 GURL GetSiteForExtensionId(const std::string& extension_id,
                            content::BrowserContext* context) {
   return content::SiteInstance::GetSiteForURL(
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h
index c831f71..d2a6531e 100644
--- a/extensions/browser/extension_util.h
+++ b/extensions/browser/extension_util.h
@@ -35,6 +35,11 @@
 bool IsIncognitoEnabled(const std::string& extension_id,
                         content::BrowserContext* context);
 
+// Returns true if |extension| can see events and data from another sub-profile
+// (incognito to original profile, or vice versa).
+bool CanCrossIncognito(const extensions::Extension* extension,
+                       content::BrowserContext* context);
+
 // Returns the site of the |extension_id|, given the associated |context|.
 // Suitable for use with BrowserContext::GetStoragePartitionForSite().
 GURL GetSiteForExtensionId(const std::string& extension_id,
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 964750a..db1017e 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -196,17 +196,6 @@
   }
 }
 
-void RemoveWebViewEventListenersOnIOThread(
-    void* profile,
-    int embedder_process_id,
-    int view_instance_id) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
-      profile,
-      embedder_process_id,
-      view_instance_id);
-}
-
 double ConvertZoomLevelToZoomFactor(double zoom_level) {
   double zoom_factor = content::ZoomLevelToZoomFactor(zoom_level);
   // Because the conversion from zoom level to zoom factor isn't perfect, the
@@ -242,10 +231,8 @@
   }
 
   // Clean up web request event listeners for the WebView.
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&RemoveWebViewEventListenersOnIOThread, browser_context,
-                     embedder_process_id, view_instance_id));
+  ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
+      browser_context, embedder_process_id, view_instance_id);
 
   // Clean up content scripts for the WebView.
   auto* csm = WebViewContentScriptManager::Get(browser_context);
diff --git a/extensions/browser/info_map.cc b/extensions/browser/info_map.cc
index 83b139b6..39c077a 100644
--- a/extensions/browser/info_map.cc
+++ b/extensions/browser/info_map.cc
@@ -46,7 +46,7 @@
 
 InfoMap::ExtraData::~ExtraData() {}
 
-InfoMap::InfoMap() : ruleset_manager_(this) {}
+InfoMap::InfoMap() {}
 
 const ExtensionSet& InfoMap::extensions() const {
   CheckOnValidThread();
@@ -203,17 +203,6 @@
   return quota_service_.get();
 }
 
-declarative_net_request::RulesetManager* InfoMap::GetRulesetManager() {
-  CheckOnValidThread();
-  return &ruleset_manager_;
-}
-
-const declarative_net_request::RulesetManager* InfoMap::GetRulesetManager()
-    const {
-  CheckOnValidThread();
-  return &ruleset_manager_;
-}
-
 void InfoMap::SetNotificationsDisabled(
     const std::string& extension_id,
     bool notifications_disabled) {
diff --git a/extensions/browser/info_map.h b/extensions/browser/info_map.h
index c2f0fac..414ceba 100644
--- a/extensions/browser/info_map.h
+++ b/extensions/browser/info_map.h
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
 #include "extensions/browser/process_map.h"
 #include "extensions/browser/quota_service.h"
 #include "extensions/common/extension_set.h"
@@ -28,6 +27,7 @@
 // Contains extension data that needs to be accessed on the IO thread. It can
 // be created on any thread, but all other methods and destructor must be called
 // on the IO thread.
+// TODO(http://crbug.com/980774): Audit this to see what is still necessary.
 class InfoMap : public base::RefCountedThreadSafe<
                     InfoMap,
                     content::BrowserThread::DeleteOnIOThread> {
@@ -82,10 +82,6 @@
   // Returns the IO thread QuotaService. Creates the instance on first call.
   QuotaService* GetQuotaService();
 
-  // Returns the RulesetManager for the Declarative Net Request API.
-  declarative_net_request::RulesetManager* GetRulesetManager();
-  const declarative_net_request::RulesetManager* GetRulesetManager() const;
-
   // Notifications can be enabled/disabled in real time by the user.
   void SetNotificationsDisabled(const std::string& extension_id,
                                 bool notifications_disabled);
@@ -123,9 +119,6 @@
   // Assignment of extensions to renderer processes.
   ProcessMap process_map_;
 
-  // Manages rulesets for the Declarative Net Request API.
-  declarative_net_request::RulesetManager ruleset_manager_;
-
   scoped_refptr<ContentVerifier> content_verifier_;
 };