OLD | NEW |
---|---|
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 Loading... | |
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(event_data.empty()) |
32 // We explicitly clear the event data map here to remove all references to | 32 << "|event_data| should have been cleared by InvalidateContext()"; |
33 // v8 objects. This helps us avoid cycles in v8 where an event listener | |
34 // could hold a reference to the event, which in turn holds the reference | |
35 // to the listener. | |
36 for (const auto& pair : event_data) { | |
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 } | 33 } |
44 | 34 |
45 // The associated v8::Isolate. Since this object is cleaned up at context | 35 // The associated v8::Isolate. Since this object is cleaned up at context |
46 // destruction, this should always be valid. | 36 // destruction, this should always be valid. |
47 v8::Isolate* isolate; | 37 v8::Isolate* isolate; |
48 | 38 |
49 // A map from event name -> event emitter. | 39 // A map from event name -> event emitter. |
50 std::map<std::string, v8::Global<v8::Object>> event_data; | 40 std::map<std::string, v8::Global<v8::Object>> event_data; |
51 }; | 41 }; |
52 | 42 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
120 v8_args.push_back(converter->ToV8Value(arg.get(), context)); | 110 v8_args.push_back(converter->ToV8Value(arg.get(), context)); |
121 | 111 |
122 EventEmitter* emitter = nullptr; | 112 EventEmitter* emitter = nullptr; |
123 gin::Converter<EventEmitter*>::FromV8( | 113 gin::Converter<EventEmitter*>::FromV8( |
124 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); | 114 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); |
125 CHECK(emitter); | 115 CHECK(emitter); |
126 | 116 |
127 emitter->Fire(context, &v8_args); | 117 emitter->Fire(context, &v8_args); |
128 } | 118 } |
129 | 119 |
120 void APIEventHandler::InvalidateContext(v8::Local<v8::Context> context) { | |
121 gin::PerContextData* per_context_data = gin::PerContextData::From(context); | |
122 DCHECK(per_context_data); | |
123 APIEventPerContextData* data = static_cast<APIEventPerContextData*>( | |
124 per_context_data->GetUserData(kExtensionAPIEventPerContextKey)); | |
125 if (!data) | |
126 return; | |
127 | |
128 v8::Isolate* isolate = context->GetIsolate(); | |
129 v8::HandleScope scope(isolate); | |
130 for (const auto& pair : data->event_data) { | |
131 EventEmitter* emitter = nullptr; | |
132 gin::Converter<EventEmitter*>::FromV8(isolate, pair.second.Get(isolate), | |
133 &emitter); | |
134 CHECK(emitter); | |
135 emitter->Invalidate(); | |
136 // When the context is shut down, all listeners are removed. | |
137 listeners_changed_.Run( | |
138 pair.first, binding::EventListenersChanged::NO_LISTENERS, context); | |
139 } | |
140 | |
141 data->event_data.clear(); | |
lazyboy
2017/03/03 22:14:19
FYI: If there's a chance that |data->event_data| c
Devlin
2017/03/06 19:11:06
It shouldn't be possible, but I've added a comment
| |
142 | |
143 // InvalidateContext() is called shortly (and, theoretically, synchronously) | |
144 // before the PerContextData is deleted. We have a check that guarantees that | |
145 // no new EventEmitters are created after the PerContextData is deleted, so | |
146 // no new emitters should be created after this point. | |
147 } | |
148 | |
130 size_t APIEventHandler::GetNumEventListenersForTesting( | 149 size_t APIEventHandler::GetNumEventListenersForTesting( |
131 const std::string& event_name, | 150 const std::string& event_name, |
132 v8::Local<v8::Context> context) { | 151 v8::Local<v8::Context> context) { |
133 gin::PerContextData* per_context_data = gin::PerContextData::From(context); | 152 gin::PerContextData* per_context_data = gin::PerContextData::From(context); |
134 DCHECK(per_context_data); | 153 DCHECK(per_context_data); |
135 APIEventPerContextData* data = static_cast<APIEventPerContextData*>( | 154 APIEventPerContextData* data = static_cast<APIEventPerContextData*>( |
136 per_context_data->GetUserData(kExtensionAPIEventPerContextKey)); | 155 per_context_data->GetUserData(kExtensionAPIEventPerContextKey)); |
137 DCHECK(data); | 156 DCHECK(data); |
138 | 157 |
139 auto iter = data->event_data.find(event_name); | 158 auto iter = data->event_data.find(event_name); |
140 DCHECK(iter != data->event_data.end()); | 159 DCHECK(iter != data->event_data.end()); |
141 EventEmitter* emitter = nullptr; | 160 EventEmitter* emitter = nullptr; |
142 gin::Converter<EventEmitter*>::FromV8( | 161 gin::Converter<EventEmitter*>::FromV8( |
143 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); | 162 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); |
144 CHECK(emitter); | 163 CHECK(emitter); |
145 return emitter->listeners()->size(); | 164 return emitter->listeners()->size(); |
146 } | 165 } |
147 | 166 |
148 } // namespace extensions | 167 } // namespace extensions |
OLD | NEW |