api_event_listeners.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. #ifndef EXTENSIONS_RENDERER_BINDINGS_API_EVENT_LISTENERS_H_
  5. #define EXTENSIONS_RENDERER_BINDINGS_API_EVENT_LISTENERS_H_
  6. #include <string>
  7. #include <vector>
  8. #include "base/callback.h"
  9. #include "extensions/common/mojom/event_dispatcher.mojom-forward.h"
  10. #include "extensions/renderer/bindings/api_binding_types.h"
  11. #include "v8/include/v8.h"
  12. namespace base {
  13. class DictionaryValue;
  14. }
  15. namespace extensions {
  16. class ListenerTracker;
  17. // A base class to hold listeners for a given event. This allows for adding,
  18. // removing, and querying listeners in the list, and calling a callback when
  19. // transitioning from 0 -> 1 or 1 -> 0 listeners.
  20. class APIEventListeners {
  21. public:
  22. // The callback called when listeners change. |update_lazy_listeners|
  23. // indicates that the lazy listener count for the event should potentially be
  24. // updated. This is true if a) the event supports lazy listeners and b) the
  25. // change was "manual" (i.e., triggered by a direct call from the extension
  26. // rather than something like the context being destroyed).
  27. using ListenersUpdated =
  28. base::RepeatingCallback<void(const std::string& event_name,
  29. binding::EventListenersChanged,
  30. const base::DictionaryValue* filter,
  31. bool update_lazy_listeners,
  32. v8::Local<v8::Context> context)>;
  33. // A callback to retrieve the identity of the context's owner. This allows us
  34. // to associate multiple listeners from different v8::Contexts with the same
  35. // owner (e.g., extension). This is used lazily, when listeners are first
  36. // added.
  37. // TODO(https://crbug.com/877658): Ideally, we'd just pass in the context
  38. // owner to the event directly. However, this led to https://crbug.com/877401,
  39. // presumably because of https://crbug.com/877658. If we can fix that, we can
  40. // simplify this again.
  41. using ContextOwnerIdGetter =
  42. base::RepeatingCallback<std::string(v8::Local<v8::Context>)>;
  43. APIEventListeners(const APIEventListeners&) = delete;
  44. APIEventListeners& operator=(const APIEventListeners&) = delete;
  45. virtual ~APIEventListeners() = default;
  46. // Adds the given |listener| to the list, possibly associating it with the
  47. // given |filter|. Returns true if the listener is added. Populates |error|
  48. // with any errors encountered. Note that |error| is *not* always populated
  49. // if false is returned, since we don't consider trying to re-add a listener
  50. // to be an error.
  51. virtual bool AddListener(v8::Local<v8::Function> listener,
  52. v8::Local<v8::Object> filter,
  53. v8::Local<v8::Context> context,
  54. std::string* error) = 0;
  55. // Removes the given |listener|, if it's present in the list.
  56. virtual void RemoveListener(v8::Local<v8::Function> listener,
  57. v8::Local<v8::Context> context) = 0;
  58. // Returns true if the given |listener| is in the list.
  59. virtual bool HasListener(v8::Local<v8::Function> listener) = 0;
  60. // Returns the number of listeners in the list.
  61. virtual size_t GetNumListeners() = 0;
  62. // Returns the listeners that should be notified for the given |filter|.
  63. virtual std::vector<v8::Local<v8::Function>> GetListeners(
  64. mojom::EventFilteringInfoPtr filter,
  65. v8::Local<v8::Context> context) = 0;
  66. // Invalidates the list.
  67. virtual void Invalidate(v8::Local<v8::Context> context) = 0;
  68. protected:
  69. APIEventListeners() {}
  70. };
  71. // A listener list implementation that doesn't support filtering. Each event
  72. // dispatched is dispatched to all the associated listeners.
  73. class UnfilteredEventListeners final : public APIEventListeners {
  74. public:
  75. UnfilteredEventListeners(ListenersUpdated listeners_updated,
  76. const std::string& event_name,
  77. ContextOwnerIdGetter context_owner_id_getter,
  78. int max_listeners,
  79. bool supports_lazy_listeners,
  80. ListenerTracker* listener_tracker);
  81. UnfilteredEventListeners(const UnfilteredEventListeners&) = delete;
  82. UnfilteredEventListeners& operator=(const UnfilteredEventListeners&) = delete;
  83. ~UnfilteredEventListeners() override;
  84. bool AddListener(v8::Local<v8::Function> listener,
  85. v8::Local<v8::Object> filter,
  86. v8::Local<v8::Context> context,
  87. std::string* error) override;
  88. void RemoveListener(v8::Local<v8::Function> listener,
  89. v8::Local<v8::Context> context) override;
  90. bool HasListener(v8::Local<v8::Function> listener) override;
  91. size_t GetNumListeners() override;
  92. std::vector<v8::Local<v8::Function>> GetListeners(
  93. mojom::EventFilteringInfoPtr filter,
  94. v8::Local<v8::Context> context) override;
  95. void Invalidate(v8::Local<v8::Context> context) override;
  96. private:
  97. // Lazily sets |context_id_owner_| from |context_id_owner_getter_|.
  98. void LazilySetContextOwner(v8::Local<v8::Context> context);
  99. // Notifies that all the listeners for this context are now removed.
  100. void NotifyListenersEmpty(v8::Local<v8::Context> context,
  101. bool update_lazy_listeners);
  102. // The event listeners associated with this event.
  103. // TODO(devlin): Having these listeners held as v8::Globals means that we
  104. // need to worry about cycles when a listener holds a reference to the event,
  105. // e.g. EventEmitter -> Listener -> EventEmitter. Right now, we handle that by
  106. // requiring Invalidate() to be called, but that means that events that aren't
  107. // Invalidate()'d earlier can leak until context destruction. We could
  108. // circumvent this by storing the listeners strongly in a private propery
  109. // (thus traceable by v8), and optionally keep a weak cache on this object.
  110. std::vector<v8::Global<v8::Function>> listeners_;
  111. ListenersUpdated listeners_updated_;
  112. // This event's name.
  113. std::string event_name_;
  114. // The getter for the owner of the context; called lazily when the first
  115. // listener is added. Only used when the event is managed (i.e.,
  116. // |listener_tracker_ is non-null|).
  117. ContextOwnerIdGetter context_owner_id_getter_;
  118. // The owner of the context these listeners belong to. Only used when the
  119. // event is managed (i.e., |listener_tracker_ is non-null|).
  120. std::string context_owner_id_;
  121. // The maximum number of supported listeners.
  122. int max_listeners_;
  123. // Whether the event supports lazy listeners.
  124. bool supports_lazy_listeners_;
  125. // The listener tracker to notify of added or removed listeners. This may be
  126. // null if this is a set of listeners for an unmanaged event. If
  127. // non-null, required to outlive this object.
  128. ListenerTracker* listener_tracker_ = nullptr;
  129. };
  130. // A listener list implementation that supports filtering. Events should only
  131. // be dispatched to those listeners whose filters match. Additionally, the
  132. // updated callback is triggered any time a listener with a new filter is
  133. // added, or the last listener with a given filter is removed.
  134. class FilteredEventListeners final : public APIEventListeners {
  135. public:
  136. FilteredEventListeners(ListenersUpdated listeners_updated,
  137. const std::string& event_name,
  138. ContextOwnerIdGetter context_owner_id_getter,
  139. int max_listeners,
  140. bool supports_lazy_listeners,
  141. ListenerTracker* listener_tracker);
  142. FilteredEventListeners(const FilteredEventListeners&) = delete;
  143. FilteredEventListeners& operator=(const FilteredEventListeners&) = delete;
  144. ~FilteredEventListeners() override;
  145. bool AddListener(v8::Local<v8::Function> listener,
  146. v8::Local<v8::Object> filter,
  147. v8::Local<v8::Context> context,
  148. std::string* error) override;
  149. void RemoveListener(v8::Local<v8::Function> listener,
  150. v8::Local<v8::Context> context) override;
  151. bool HasListener(v8::Local<v8::Function> listener) override;
  152. size_t GetNumListeners() override;
  153. std::vector<v8::Local<v8::Function>> GetListeners(
  154. mojom::EventFilteringInfoPtr filter,
  155. v8::Local<v8::Context> context) override;
  156. void Invalidate(v8::Local<v8::Context> context) override;
  157. private:
  158. struct ListenerData;
  159. // Lazily sets |context_owner_id_| from |context_owner_id_getter_|.
  160. void LazilySetContextOwner(v8::Local<v8::Context> context);
  161. void InvalidateListener(const ListenerData& listener,
  162. bool was_manual,
  163. v8::Local<v8::Context> context);
  164. // Note: See TODO on UnfilteredEventListeners::listeners_.
  165. std::vector<ListenerData> listeners_;
  166. ListenersUpdated listeners_updated_;
  167. // This event's name.
  168. std::string event_name_;
  169. // The getter for the owner of the context; called lazily when the first
  170. // listener is added. This is always non-null.
  171. ContextOwnerIdGetter context_owner_id_getter_;
  172. // The owner of the context these listeners belong to. This should always be
  173. // non-empty after initialization.
  174. std::string context_owner_id_;
  175. // The maximum number of supported listeners.
  176. int max_listeners_;
  177. // Whether the event supports lazy listeners.
  178. bool supports_lazy_listeners_;
  179. // The listener tracker to notify of added or removed listeners. Required to
  180. // outlive this object. Must be non-null.
  181. ListenerTracker* listener_tracker_ = nullptr;
  182. };
  183. } // namespace extensions
  184. #endif // EXTENSIONS_RENDERER_BINDINGS_API_EVENT_LISTENERS_H_