Chromium Code Reviews| 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 |