Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: extensions/renderer/api_event_handler.cc

Issue 2722463006: [Extensions Bindings] Notify of event unregistration on invalidation (Closed)
Patch Set: Rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/api_event_handler.h" 5 #include "extensions/renderer/api_event_handler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 #include <memory> 9 #include <memory>
10 #include <vector> 10 #include <vector>
(...skipping 10 matching lines...) Expand all
21 21
22 namespace extensions { 22 namespace extensions {
23 23
24 namespace { 24 namespace {
25 25
26 const char kExtensionAPIEventPerContextKey[] = "extension_api_events"; 26 const char kExtensionAPIEventPerContextKey[] = "extension_api_events";
27 27
28 struct APIEventPerContextData : public base::SupportsUserData::Data { 28 struct APIEventPerContextData : public base::SupportsUserData::Data {
29 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {} 29 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {}
30 ~APIEventPerContextData() override { 30 ~APIEventPerContextData() override {
31 v8::HandleScope scope(isolate); 31 DCHECK(emitters.empty())
32 // We explicitly clear the event data map here to remove all references to 32 << "|emitters| should have been cleared by InvalidateContext()";
33 // v8 objects. This helps us avoid cycles in v8 where an event listener 33 DCHECK(massagers.empty())
34 // could hold a reference to the event, which in turn holds the reference 34 << "|massagers| should have been cleared by InvalidateContext()";
35 // to the listener.
36 for (const auto& pair : emitters) {
37 EventEmitter* emitter = nullptr;
38 gin::Converter<EventEmitter*>::FromV8(
39 isolate, pair.second.Get(isolate), &emitter);
40 CHECK(emitter);
41 emitter->listeners()->clear();
42 }
43 } 35 }
44 36
45 // The associated v8::Isolate. Since this object is cleaned up at context 37 // The associated v8::Isolate. Since this object is cleaned up at context
46 // destruction, this should always be valid. 38 // destruction, this should always be valid.
47 v8::Isolate* isolate; 39 v8::Isolate* isolate;
48 40
49 // A map from event name -> event emitter. 41 // A map from event name -> event emitter.
50 std::map<std::string, v8::Global<v8::Object>> emitters; 42 std::map<std::string, v8::Global<v8::Object>> emitters;
51 43
52 // A map from event name -> argument massager. 44 // A map from event name -> argument massager.
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 183
192 void APIEventHandler::RegisterArgumentMassager( 184 void APIEventHandler::RegisterArgumentMassager(
193 v8::Local<v8::Context> context, 185 v8::Local<v8::Context> context,
194 const std::string& event_name, 186 const std::string& event_name,
195 v8::Local<v8::Function> massager) { 187 v8::Local<v8::Function> massager) {
196 APIEventPerContextData* data = GetContextData(context, true); 188 APIEventPerContextData* data = GetContextData(context, true);
197 DCHECK(data->massagers.find(event_name) == data->massagers.end()); 189 DCHECK(data->massagers.find(event_name) == data->massagers.end());
198 data->massagers[event_name].Reset(context->GetIsolate(), massager); 190 data->massagers[event_name].Reset(context->GetIsolate(), massager);
199 } 191 }
200 192
193 void APIEventHandler::InvalidateContext(v8::Local<v8::Context> context) {
194 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
195 DCHECK(per_context_data);
196 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
197 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
198 if (!data)
199 return;
200
201 v8::Isolate* isolate = context->GetIsolate();
202 v8::HandleScope scope(isolate);
203 // This loop *shouldn't* allow any self-modification (i.e., no listeners
204 // should be added or removed as a result of the iteration). If that changes,
205 // we'll need to cache the listeners elsewhere before iterating.
206 for (const auto& pair : data->emitters) {
207 EventEmitter* emitter = nullptr;
208 gin::Converter<EventEmitter*>::FromV8(isolate, pair.second.Get(isolate),
209 &emitter);
210 CHECK(emitter);
211 emitter->Invalidate();
212 // When the context is shut down, all listeners are removed.
213 listeners_changed_.Run(
214 pair.first, binding::EventListenersChanged::NO_LISTENERS, context);
215 }
216
217 data->emitters.clear();
218 data->massagers.clear();
219
220 // InvalidateContext() is called shortly (and, theoretically, synchronously)
221 // before the PerContextData is deleted. We have a check that guarantees that
222 // no new EventEmitters are created after the PerContextData is deleted, so
223 // no new emitters should be created after this point.
224 }
225
201 size_t APIEventHandler::GetNumEventListenersForTesting( 226 size_t APIEventHandler::GetNumEventListenersForTesting(
202 const std::string& event_name, 227 const std::string& event_name,
203 v8::Local<v8::Context> context) { 228 v8::Local<v8::Context> context) {
204 APIEventPerContextData* data = GetContextData(context, false); 229 APIEventPerContextData* data = GetContextData(context, false);
205 DCHECK(data); 230 DCHECK(data);
206 231
207 auto iter = data->emitters.find(event_name); 232 auto iter = data->emitters.find(event_name);
208 DCHECK(iter != data->emitters.end()); 233 DCHECK(iter != data->emitters.end());
209 EventEmitter* emitter = nullptr; 234 EventEmitter* emitter = nullptr;
210 gin::Converter<EventEmitter*>::FromV8( 235 gin::Converter<EventEmitter*>::FromV8(
211 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); 236 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
212 CHECK(emitter); 237 CHECK(emitter);
213 return emitter->listeners()->size(); 238 return emitter->listeners()->size();
214 } 239 }
215 240
216 } // namespace extensions 241 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_event_handler.h ('k') | extensions/renderer/api_event_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698