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

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

Issue 1074273002: Move the event attach/detach logic on unload from event.js to (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: other comment Created 5 years, 8 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/event_bindings.h" 5 #include "extensions/renderer/event_bindings.h"
6 6
7 #include <map> 7 #include <map>
8 #include <set> 8 #include <set>
Devlin 2015/04/13 16:07:07 remove #include <set>, <string>
not at google - send to devlin 2015/04/13 17:08:30 Done.
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/basictypes.h" 12 #include "base/basictypes.h"
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
15 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "components/crx_file/id_util.h" 16 #include "components/crx_file/id_util.h"
17 #include "content/public/child/v8_value_converter.h" 17 #include "content/public/child/v8_value_converter.h"
18 #include "content/public/renderer/render_thread.h" 18 #include "content/public/renderer/render_thread.h"
19 #include "content/public/renderer/render_view.h" 19 #include "content/public/renderer/render_view.h"
20 #include "extensions/common/event_filter.h" 20 #include "extensions/common/event_filter.h"
21 #include "extensions/common/extension.h" 21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_messages.h" 22 #include "extensions/common/extension_messages.h"
23 #include "extensions/common/manifest_handlers/background_info.h" 23 #include "extensions/common/manifest_handlers/background_info.h"
24 #include "extensions/common/value_counter.h" 24 #include "extensions/common/value_counter.h"
25 #include "extensions/renderer/dispatcher.h" 25 #include "extensions/renderer/dispatcher.h"
26 #include "extensions/renderer/extension_helper.h" 26 #include "extensions/renderer/extension_helper.h"
27 #include "extensions/renderer/object_backed_native_handler.h" 27 #include "extensions/renderer/object_backed_native_handler.h"
Devlin 2015/04/13 16:07:07 remove
not at google - send to devlin 2015/04/13 17:08:30 ... christ, how do you find these things. I didn't
28 #include "url/gurl.h" 28 #include "url/gurl.h"
29 #include "v8/include/v8.h" 29 #include "v8/include/v8.h"
Devlin 2015/04/13 16:07:07 remove
30 30
31 namespace extensions { 31 namespace extensions {
32 32
33 namespace { 33 namespace {
34 34
35 // A map of event names to the number of contexts listening to that event. 35 // A map of event names to the number of contexts listening to that event.
36 // We notify the browser about event listeners when we transition between 0 36 // We notify the browser about event listeners when we transition between 0
37 // and 1. 37 // and 1.
38 typedef std::map<std::string, int> EventListenerCounts; 38 typedef std::map<std::string, int> EventListenerCounts;
39 39
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 FilteredEventListenerCounts::iterator it = counts.find(event_name); 136 FilteredEventListenerCounts::iterator it = counts.find(event_name);
137 if (it == counts.end()) 137 if (it == counts.end())
138 return false; 138 return false;
139 return 0 == it->second->Remove(*filter); 139 return 0 == it->second->Remove(*filter);
140 } 140 }
141 141
142 } // namespace 142 } // namespace
143 143
144 EventBindings::EventBindings(Dispatcher* dispatcher, ScriptContext* context) 144 EventBindings::EventBindings(Dispatcher* dispatcher, ScriptContext* context)
145 : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { 145 : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) {
146 RouteFunction( 146 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler,
147 "AttachEvent", 147 base::Unretained(this)));
Devlin 2015/04/13 16:07:07 If you can, a really brief note about why unretain
not at google - send to devlin 2015/04/13 17:08:30 There are many many calls of RouteFunction. I'll a
148 base::Bind(&EventBindings::AttachEvent, base::Unretained(this))); 148 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler,
149 RouteFunction( 149 base::Unretained(this)));
150 "DetachEvent",
151 base::Bind(&EventBindings::DetachEvent, base::Unretained(this)));
152 RouteFunction( 150 RouteFunction(
153 "AttachFilteredEvent", 151 "AttachFilteredEvent",
154 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); 152 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this)));
155 RouteFunction( 153 RouteFunction(
156 "DetachFilteredEvent", 154 "DetachFilteredEvent",
157 base::Bind(&EventBindings::DetachFilteredEvent, base::Unretained(this))); 155 base::Bind(&EventBindings::DetachFilteredEvent, base::Unretained(this)));
158 RouteFunction("MatchAgainstEventFilter", 156 RouteFunction("MatchAgainstEventFilter",
159 base::Bind(&EventBindings::MatchAgainstEventFilter, 157 base::Bind(&EventBindings::MatchAgainstEventFilter,
160 base::Unretained(this))); 158 base::Unretained(this)));
159
160 // It's safe to use base::Unretained here because |context| will always
161 // outlive us.
162 context->AddInvalidationObserver(
163 base::Bind(&EventBindings::OnInvalidated, base::Unretained(this)));
161 } 164 }
162 165
163 EventBindings::~EventBindings() {} 166 EventBindings::~EventBindings() {}
164 167
165 // Attach an event name to an object. 168 void EventBindings::AttachEventHandler(
166 void EventBindings::AttachEvent(
167 const v8::FunctionCallbackInfo<v8::Value>& args) { 169 const v8::FunctionCallbackInfo<v8::Value>& args) {
168 CHECK_EQ(1, args.Length()); 170 CHECK_EQ(1, args.Length());
169 CHECK(args[0]->IsString()); 171 CHECK(args[0]->IsString());
172 AttachEvent(*v8::String::Utf8Value(args[0]));
173 }
170 174
171 std::string event_name = *v8::String::Utf8Value(args[0]); 175 void EventBindings::AttachEvent(const std::string& event_name) {
172 176 // This method throws an exception if it returns false.
173 if (!dispatcher_->CheckContextAccessToExtensionAPI(event_name, context())) 177 if (!dispatcher_->CheckContextAccessToExtensionAPI(event_name, context()))
174 return; 178 return;
175 179
180 // Record the attachment for this context so that events can be detached when
181 // the context is destroyed.
182 //
183 // Ideally we'd CHECK that it's not already attached, however that's not
184 // possible because extensions can create and attach events themselves. Very
185 // silly, but that's the way it is. For an example of this, see
186 // chrome/test/data/extensions/api_test/events/background.js.
187 attached_event_names_.insert(event_name);
188
176 const std::string& extension_id = context()->GetExtensionID(); 189 const std::string& extension_id = context()->GetExtensionID();
177 if (IncrementEventListenerCount(context(), event_name) == 1) { 190 if (IncrementEventListenerCount(context(), event_name) == 1) {
178 content::RenderThread::Get()->Send(new ExtensionHostMsg_AddListener( 191 content::RenderThread::Get()->Send(new ExtensionHostMsg_AddListener(
179 extension_id, context()->GetURL(), event_name)); 192 extension_id, context()->GetURL(), event_name));
180 } 193 }
181 194
182 // This is called the first time the page has added a listener. Since 195 // This is called the first time the page has added a listener. Since
183 // the background page is the only lazy page, we know this is the first 196 // the background page is the only lazy page, we know this is the first
184 // time this listener has been registered. 197 // time this listener has been registered.
185 if (IsLazyBackgroundPage(context()->GetRenderView(), 198 if (IsLazyBackgroundPage(context()->GetRenderView(),
186 context()->extension())) { 199 context()->extension())) {
187 content::RenderThread::Get()->Send( 200 content::RenderThread::Get()->Send(
188 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); 201 new ExtensionHostMsg_AddLazyListener(extension_id, event_name));
189 } 202 }
190 } 203 }
191 204
192 void EventBindings::DetachEvent( 205 void EventBindings::DetachEventHandler(
193 const v8::FunctionCallbackInfo<v8::Value>& args) { 206 const v8::FunctionCallbackInfo<v8::Value>& args) {
194 CHECK_EQ(2, args.Length()); 207 CHECK_EQ(2, args.Length());
195 CHECK(args[0]->IsString()); 208 CHECK(args[0]->IsString());
196 CHECK(args[1]->IsBoolean()); 209 CHECK(args[1]->IsBoolean());
210 DetachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue());
211 }
197 212
198 std::string event_name = *v8::String::Utf8Value(args[0]); 213 void EventBindings::DetachEvent(const std::string& event_name, bool is_manual) {
199 bool is_manual = args[1]->BooleanValue(); 214 // See comment in AttachEvent().
215 attached_event_names_.erase(event_name);
200 216
201 const std::string& extension_id = context()->GetExtensionID(); 217 const std::string& extension_id = context()->GetExtensionID();
218
202 if (DecrementEventListenerCount(context(), event_name) == 0) { 219 if (DecrementEventListenerCount(context(), event_name) == 0) {
203 content::RenderThread::Get()->Send(new ExtensionHostMsg_RemoveListener( 220 content::RenderThread::Get()->Send(new ExtensionHostMsg_RemoveListener(
204 extension_id, context()->GetURL(), event_name)); 221 extension_id, context()->GetURL(), event_name));
205 } 222 }
206 223
207 // DetachEvent is called when the last listener for the context is 224 // DetachEvent is called when the last listener for the context is
208 // removed. If the context is the background page, and it removes the 225 // removed. If the context is the background page, and it removes the
209 // last listener manually, then we assume that it is no longer interested 226 // last listener manually, then we assume that it is no longer interested
210 // in being awakened for this event. 227 // in being awakened for this event.
211 if (is_manual && IsLazyBackgroundPage(context()->GetRenderView(), 228 if (is_manual && IsLazyBackgroundPage(context()->GetRenderView(),
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 args.GetReturnValue().Set(array); 334 args.GetReturnValue().Set(array);
318 } 335 }
319 336
320 scoped_ptr<EventMatcher> EventBindings::ParseEventMatcher( 337 scoped_ptr<EventMatcher> EventBindings::ParseEventMatcher(
321 base::DictionaryValue* filter_dict) { 338 base::DictionaryValue* filter_dict) {
322 return scoped_ptr<EventMatcher>(new EventMatcher( 339 return scoped_ptr<EventMatcher>(new EventMatcher(
323 scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()), 340 scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()),
324 context()->GetRenderView()->GetRoutingID())); 341 context()->GetRenderView()->GetRoutingID()));
325 } 342 }
326 343
344 void EventBindings::OnInvalidated() {
345 // Detach all attached events that weren't attached. Iterate over a copy
346 // because it will be mutated.
347 std::set<std::string> attached_event_names_safe = attached_event_names_;
348 for (const std::string& event_name : attached_event_names_safe) {
349 DetachEvent(event_name, false /* is_manual */);
350 }
351 DCHECK(attached_event_names_.empty())
352 << "Events cannot be attached during invalidation";
353 }
354
327 } // namespace extensions 355 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698