lazy_event_dispatcher.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/browser/events/lazy_event_dispatcher.h"
  5. #include "base/bind.h"
  6. #include "base/containers/contains.h"
  7. #include "extensions/browser/event_router.h"
  8. #include "extensions/browser/extension_registry.h"
  9. #include "extensions/browser/extensions_browser_client.h"
  10. #include "extensions/browser/lazy_context_id.h"
  11. #include "extensions/common/features/feature.h"
  12. #include "extensions/common/manifest_handlers/incognito_info.h"
  13. using content::BrowserContext;
  14. namespace extensions {
  15. LazyEventDispatcher::LazyEventDispatcher(BrowserContext* browser_context,
  16. DispatchFunction dispatch_function)
  17. : browser_context_(browser_context),
  18. dispatch_function_(std::move(dispatch_function)) {}
  19. LazyEventDispatcher::~LazyEventDispatcher() {}
  20. void LazyEventDispatcher::Dispatch(
  21. const Event& event,
  22. const LazyContextId& dispatch_context,
  23. const base::DictionaryValue* listener_filter) {
  24. const Extension* extension = ExtensionRegistry::Get(browser_context_)
  25. ->enabled_extensions()
  26. .GetByID(dispatch_context.extension_id());
  27. if (!extension)
  28. return;
  29. // Check both the original and the incognito browser context to see if we
  30. // should load a non-peristent context (a lazy background page or an
  31. // extension service worker) to handle the event. We need to use the incognito
  32. // context in the case of split-mode extensions.
  33. if (QueueEventDispatch(event, dispatch_context, extension, listener_filter))
  34. RecordAlreadyDispatched(dispatch_context);
  35. BrowserContext* additional_context = GetIncognitoContext(extension);
  36. if (!additional_context)
  37. return;
  38. LazyContextId additional_context_id(dispatch_context);
  39. additional_context_id.set_browser_context(additional_context);
  40. if (QueueEventDispatch(event, additional_context_id, extension,
  41. listener_filter)) {
  42. RecordAlreadyDispatched(additional_context_id);
  43. }
  44. }
  45. bool LazyEventDispatcher::HasAlreadyDispatched(
  46. const LazyContextId& dispatch_context) const {
  47. return base::Contains(dispatched_ids_, dispatch_context);
  48. }
  49. bool LazyEventDispatcher::QueueEventDispatch(
  50. const Event& event,
  51. const LazyContextId& dispatch_context,
  52. const Extension* extension,
  53. const base::DictionaryValue* listener_filter) {
  54. if (!EventRouter::CanDispatchEventToBrowserContext(
  55. dispatch_context.browser_context(), extension, event)) {
  56. return false;
  57. }
  58. if (HasAlreadyDispatched(dispatch_context))
  59. return false;
  60. LazyContextTaskQueue* queue = dispatch_context.GetTaskQueue();
  61. if (!queue->ShouldEnqueueTask(dispatch_context.browser_context(),
  62. extension)) {
  63. return false;
  64. }
  65. // TODO(devlin): This results in a copy each time we dispatch events to
  66. // ServiceWorkers and inactive event pages. It'd be nice to avoid that.
  67. std::unique_ptr<Event> dispatched_event = event.DeepCopy();
  68. // If there's a dispatch callback, call it now (rather than dispatch time)
  69. // to avoid lifetime issues. Use a separate copy of the event args, so they
  70. // last until the event is dispatched.
  71. if (!dispatched_event->will_dispatch_callback.is_null()) {
  72. std::unique_ptr<base::Value::List> modified_event_args;
  73. mojom::EventFilteringInfoPtr modified_event_filter_info;
  74. if (!dispatched_event->will_dispatch_callback.Run(
  75. dispatch_context.browser_context(),
  76. // The only lazy listeners belong to an extension's background
  77. // context (either an event page or a service worker), which are
  78. // always BLESSED_EXTENSION_CONTEXTs
  79. extensions::Feature::BLESSED_EXTENSION_CONTEXT, extension,
  80. listener_filter, &modified_event_args,
  81. &modified_event_filter_info)) {
  82. // The event has been canceled.
  83. return true;
  84. }
  85. if (modified_event_args) {
  86. dispatched_event->event_args = std::move(*modified_event_args);
  87. }
  88. if (modified_event_filter_info)
  89. dispatched_event->filter_info = std::move(modified_event_filter_info);
  90. // Ensure we don't call it again at dispatch time.
  91. dispatched_event->will_dispatch_callback.Reset();
  92. }
  93. queue->AddPendingTask(
  94. dispatch_context,
  95. base::BindOnce(dispatch_function_, std::move(dispatched_event)));
  96. return true;
  97. }
  98. void LazyEventDispatcher::RecordAlreadyDispatched(
  99. const LazyContextId& dispatch_context) {
  100. dispatched_ids_.insert(dispatch_context);
  101. }
  102. BrowserContext* LazyEventDispatcher::GetIncognitoContext(
  103. const Extension* extension) {
  104. if (!IncognitoInfo::IsSplitMode(extension))
  105. return nullptr;
  106. ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
  107. if (!browser_client->HasOffTheRecordContext(browser_context_))
  108. return nullptr;
  109. return browser_client->GetOffTheRecordContext(browser_context_);
  110. }
  111. } // namespace extensions