| OLD | NEW |
| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <map> | 9 #include <map> |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 context->v8_context()), | 222 context->v8_context()), |
| 223 listener_ids, | 223 listener_ids, |
| 224 }; | 224 }; |
| 225 | 225 |
| 226 context->module_system()->CallModuleMethodSafe( | 226 context->module_system()->CallModuleMethodSafe( |
| 227 kEventBindings, "dispatchEvent", arraysize(v8_args), v8_args); | 227 kEventBindings, "dispatchEvent", arraysize(v8_args), v8_args); |
| 228 } | 228 } |
| 229 | 229 |
| 230 void EventBindings::AttachEventHandler( | 230 void EventBindings::AttachEventHandler( |
| 231 const v8::FunctionCallbackInfo<v8::Value>& args) { | 231 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 232 CHECK_EQ(1, args.Length()); | 232 CHECK_EQ(2, args.Length()); |
| 233 CHECK(args[0]->IsString()); | 233 CHECK(args[0]->IsString()); |
| 234 AttachEvent(*v8::String::Utf8Value(args[0])); | 234 CHECK(args[1]->IsBoolean()); |
| 235 AttachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue()); |
| 235 } | 236 } |
| 236 | 237 |
| 237 void EventBindings::AttachEvent(const std::string& event_name) { | 238 void EventBindings::AttachEvent(const std::string& event_name, |
| 239 bool supports_lazy_events) { |
| 238 if (!context()->HasAccessOrThrowError(event_name)) | 240 if (!context()->HasAccessOrThrowError(event_name)) |
| 239 return; | 241 return; |
| 240 | 242 |
| 241 // Record the attachment for this context so that events can be detached when | 243 // Record the attachment for this context so that events can be detached when |
| 242 // the context is destroyed. | 244 // the context is destroyed. |
| 243 // | 245 // |
| 244 // Ideally we'd CHECK that it's not already attached, however that's not | 246 // Ideally we'd CHECK that it's not already attached, however that's not |
| 245 // possible because extensions can create and attach events themselves. Very | 247 // possible because extensions can create and attach events themselves. Very |
| 246 // silly, but that's the way it is. For an example of this, see | 248 // silly, but that's the way it is. For an example of this, see |
| 247 // chrome/test/data/extensions/api_test/events/background.js. | 249 // chrome/test/data/extensions/api_test/events/background.js. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 259 : context()->url(), | 261 : context()->url(), |
| 260 event_name, worker_thread_id)); | 262 event_name, worker_thread_id)); |
| 261 } | 263 } |
| 262 | 264 |
| 263 // This is called the first time the page has added a listener. Since | 265 // This is called the first time the page has added a listener. Since |
| 264 // the background page is the only lazy page, we know this is the first | 266 // the background page is the only lazy page, we know this is the first |
| 265 // time this listener has been registered. | 267 // time this listener has been registered. |
| 266 bool is_lazy_context = | 268 bool is_lazy_context = |
| 267 ExtensionFrameHelper::IsContextForEventPage(context()) || | 269 ExtensionFrameHelper::IsContextForEventPage(context()) || |
| 268 context()->context_type() == Feature::SERVICE_WORKER_CONTEXT; | 270 context()->context_type() == Feature::SERVICE_WORKER_CONTEXT; |
| 269 if (is_lazy_context) { | 271 if (is_lazy_context && supports_lazy_events) { |
| 270 if (is_service_worker_context) { | 272 if (is_service_worker_context) { |
| 271 sender->Send(new ExtensionHostMsg_AddLazyServiceWorkerListener( | 273 sender->Send(new ExtensionHostMsg_AddLazyServiceWorkerListener( |
| 272 extension_id, event_name, context()->service_worker_scope())); | 274 extension_id, event_name, context()->service_worker_scope())); |
| 273 } else { | 275 } else { |
| 274 sender->Send( | 276 sender->Send( |
| 275 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); | 277 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); |
| 276 } | 278 } |
| 277 } | 279 } |
| 278 } | 280 } |
| 279 | 281 |
| 280 void EventBindings::DetachEventHandler( | 282 void EventBindings::DetachEventHandler( |
| 281 const v8::FunctionCallbackInfo<v8::Value>& args) { | 283 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 282 CHECK_EQ(2, args.Length()); | 284 CHECK_EQ(3, args.Length()); |
| 283 CHECK(args[0]->IsString()); | 285 CHECK(args[0]->IsString()); |
| 284 CHECK(args[1]->IsBoolean()); | 286 CHECK(args[1]->IsBoolean()); |
| 285 DetachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue()); | 287 CHECK(args[2]->IsBoolean()); |
| 288 bool was_manual = args[1]->BooleanValue(); |
| 289 bool supports_lazy_listeners = args[2]->BooleanValue(); |
| 290 DetachEvent(*v8::String::Utf8Value(args[0]), |
| 291 was_manual && supports_lazy_listeners); |
| 286 } | 292 } |
| 287 | 293 |
| 288 void EventBindings::DetachEvent(const std::string& event_name, bool is_manual) { | 294 void EventBindings::DetachEvent(const std::string& event_name, |
| 295 bool remove_lazy_listener) { |
| 289 // See comment in AttachEvent(). | 296 // See comment in AttachEvent(). |
| 290 attached_event_names_.erase(event_name); | 297 attached_event_names_.erase(event_name); |
| 291 | 298 |
| 292 int worker_thread_id = content::WorkerThread::GetCurrentId(); | 299 int worker_thread_id = content::WorkerThread::GetCurrentId(); |
| 293 const bool is_service_worker_context = worker_thread_id != kNonWorkerThreadId; | 300 const bool is_service_worker_context = worker_thread_id != kNonWorkerThreadId; |
| 294 IPC::Sender* sender = GetIPCSender(); | 301 IPC::Sender* sender = GetIPCSender(); |
| 295 const std::string& extension_id = context()->GetExtensionID(); | 302 const std::string& extension_id = context()->GetExtensionID(); |
| 296 | 303 |
| 297 if (DecrementEventListenerCount(context(), event_name) == 0) { | 304 if (DecrementEventListenerCount(context(), event_name) == 0) { |
| 298 sender->Send(new ExtensionHostMsg_RemoveListener( | 305 sender->Send(new ExtensionHostMsg_RemoveListener( |
| 299 extension_id, | 306 extension_id, |
| 300 is_service_worker_context ? context()->service_worker_scope() | 307 is_service_worker_context ? context()->service_worker_scope() |
| 301 : context()->url(), | 308 : context()->url(), |
| 302 event_name, worker_thread_id)); | 309 event_name, worker_thread_id)); |
| 303 } | 310 } |
| 304 | 311 |
| 305 // DetachEvent is called when the last listener for the context is | 312 // DetachEvent is called when the last listener for the context is |
| 306 // removed. If the context is the background page or service worker, and it | 313 // removed. If the context is the background page or service worker, and it |
| 307 // removes the last listener manually, then we assume that it is no longer | 314 // removes the last listener manually, then we assume that it is no longer |
| 308 // interested in being awakened for this event. | 315 // interested in being awakened for this event. |
| 309 if (is_manual) { | 316 if (remove_lazy_listener) { |
| 310 bool is_lazy_context = | 317 bool is_lazy_context = |
| 311 ExtensionFrameHelper::IsContextForEventPage(context()) || | 318 ExtensionFrameHelper::IsContextForEventPage(context()) || |
| 312 context()->context_type() == Feature::SERVICE_WORKER_CONTEXT; | 319 context()->context_type() == Feature::SERVICE_WORKER_CONTEXT; |
| 313 if (is_lazy_context) { | 320 if (is_lazy_context) { |
| 314 if (is_service_worker_context) { | 321 if (is_service_worker_context) { |
| 315 sender->Send(new ExtensionHostMsg_RemoveLazyServiceWorkerListener( | 322 sender->Send(new ExtensionHostMsg_RemoveLazyServiceWorkerListener( |
| 316 extension_id, event_name, context()->service_worker_scope())); | 323 extension_id, event_name, context()->service_worker_scope())); |
| 317 } else { | 324 } else { |
| 318 sender->Send( | 325 sender->Send( |
| 319 new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name)); | 326 new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name)); |
| 320 } | 327 } |
| 321 } | 328 } |
| 322 } | 329 } |
| 323 } | 330 } |
| 324 | 331 |
| 325 // MatcherID AttachFilteredEvent(string event_name, object filter) | 332 // MatcherID AttachFilteredEvent(string event_name, object filter) |
| 326 // event_name - Name of the event to attach. | 333 // event_name - Name of the event to attach. |
| 327 // filter - Which instances of the named event are we interested in. | 334 // filter - Which instances of the named event are we interested in. |
| 328 // returns the id assigned to the listener, which will be provided to calls to | 335 // returns the id assigned to the listener, which will be provided to calls to |
| 329 // dispatchEvent(). | 336 // dispatchEvent(). |
| 330 void EventBindings::AttachFilteredEvent( | 337 void EventBindings::AttachFilteredEvent( |
| 331 const v8::FunctionCallbackInfo<v8::Value>& args) { | 338 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 332 CHECK_EQ(2, args.Length()); | 339 CHECK_EQ(3, args.Length()); |
| 333 CHECK(args[0]->IsString()); | 340 CHECK(args[0]->IsString()); |
| 334 CHECK(args[1]->IsObject()); | 341 CHECK(args[1]->IsObject()); |
| 342 CHECK(args[2]->IsBoolean()); |
| 335 | 343 |
| 336 std::string event_name = *v8::String::Utf8Value(args[0]); | 344 std::string event_name = *v8::String::Utf8Value(args[0]); |
| 337 if (!context()->HasAccessOrThrowError(event_name)) | 345 if (!context()->HasAccessOrThrowError(event_name)) |
| 338 return; | 346 return; |
| 339 | 347 |
| 340 std::unique_ptr<base::DictionaryValue> filter; | 348 std::unique_ptr<base::DictionaryValue> filter; |
| 341 { | 349 { |
| 342 std::unique_ptr<base::Value> filter_value = | 350 std::unique_ptr<base::Value> filter_value = |
| 343 content::V8ValueConverter::Create()->FromV8Value( | 351 content::V8ValueConverter::Create()->FromV8Value( |
| 344 v8::Local<v8::Object>::Cast(args[1]), context()->v8_context()); | 352 v8::Local<v8::Object>::Cast(args[1]), context()->v8_context()); |
| 345 if (!filter_value || !filter_value->IsType(base::Value::Type::DICTIONARY)) { | 353 if (!filter_value || !filter_value->IsType(base::Value::Type::DICTIONARY)) { |
| 346 args.GetReturnValue().Set(static_cast<int32_t>(-1)); | 354 args.GetReturnValue().Set(static_cast<int32_t>(-1)); |
| 347 return; | 355 return; |
| 348 } | 356 } |
| 349 filter = base::DictionaryValue::From(std::move(filter_value)); | 357 filter = base::DictionaryValue::From(std::move(filter_value)); |
| 350 } | 358 } |
| 351 | 359 |
| 360 bool supports_lazy_events = args[2]->BooleanValue(); |
| 361 |
| 352 int id = g_event_filter.Get().AddEventMatcher( | 362 int id = g_event_filter.Get().AddEventMatcher( |
| 353 event_name, | 363 event_name, |
| 354 base::MakeUnique<EventMatcher>( | 364 base::MakeUnique<EventMatcher>( |
| 355 std::move(filter), context()->GetRenderFrame()->GetRoutingID())); | 365 std::move(filter), context()->GetRenderFrame()->GetRoutingID())); |
| 356 if (id == -1) { | 366 if (id == -1) { |
| 357 args.GetReturnValue().Set(static_cast<int32_t>(-1)); | 367 args.GetReturnValue().Set(static_cast<int32_t>(-1)); |
| 358 return; | 368 return; |
| 359 } | 369 } |
| 360 attached_matcher_ids_.insert(id); | 370 attached_matcher_ids_.insert(id); |
| 361 | 371 |
| 362 // Only send IPCs the first time a filter gets added. | 372 // Only send IPCs the first time a filter gets added. |
| 363 const EventMatcher* matcher = g_event_filter.Get().GetEventMatcher(id); | 373 const EventMatcher* matcher = g_event_filter.Get().GetEventMatcher(id); |
| 364 DCHECK(matcher); | 374 DCHECK(matcher); |
| 365 base::DictionaryValue* filter_weak = matcher->value(); | 375 base::DictionaryValue* filter_weak = matcher->value(); |
| 366 std::string extension_id = context()->GetExtensionID(); | 376 std::string extension_id = context()->GetExtensionID(); |
| 367 if (AddFilter(event_name, extension_id, *filter_weak)) { | 377 if (AddFilter(event_name, extension_id, *filter_weak)) { |
| 368 bool lazy = ExtensionFrameHelper::IsContextForEventPage(context()); | 378 bool lazy = supports_lazy_events && |
| 379 ExtensionFrameHelper::IsContextForEventPage(context()); |
| 369 content::RenderThread::Get()->Send(new ExtensionHostMsg_AddFilteredListener( | 380 content::RenderThread::Get()->Send(new ExtensionHostMsg_AddFilteredListener( |
| 370 extension_id, event_name, *filter_weak, lazy)); | 381 extension_id, event_name, *filter_weak, lazy)); |
| 371 } | 382 } |
| 372 | 383 |
| 373 args.GetReturnValue().Set(static_cast<int32_t>(id)); | 384 args.GetReturnValue().Set(static_cast<int32_t>(id)); |
| 374 } | 385 } |
| 375 | 386 |
| 376 void EventBindings::DetachFilteredEventHandler( | 387 void EventBindings::DetachFilteredEventHandler( |
| 377 const v8::FunctionCallbackInfo<v8::Value>& args) { | 388 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 378 CHECK_EQ(2, args.Length()); | 389 CHECK_EQ(3, args.Length()); |
| 379 CHECK(args[0]->IsInt32()); | 390 CHECK(args[0]->IsInt32()); |
| 380 CHECK(args[1]->IsBoolean()); | 391 CHECK(args[1]->IsBoolean()); |
| 381 DetachFilteredEvent(args[0]->Int32Value(), args[1]->BooleanValue()); | 392 CHECK(args[2]->IsBoolean()); |
| 393 bool was_manual = args[1]->BooleanValue(); |
| 394 bool supports_lazy_events = args[2]->BooleanValue(); |
| 395 DetachFilteredEvent(args[0]->Int32Value(), |
| 396 was_manual && supports_lazy_events); |
| 382 } | 397 } |
| 383 | 398 |
| 384 void EventBindings::DetachFilteredEvent(int matcher_id, bool is_manual) { | 399 void EventBindings::DetachFilteredEvent(int matcher_id, |
| 400 bool remove_lazy_event) { |
| 385 EventFilter& event_filter = g_event_filter.Get(); | 401 EventFilter& event_filter = g_event_filter.Get(); |
| 386 EventMatcher* event_matcher = event_filter.GetEventMatcher(matcher_id); | 402 EventMatcher* event_matcher = event_filter.GetEventMatcher(matcher_id); |
| 387 | 403 |
| 388 const std::string& event_name = event_filter.GetEventName(matcher_id); | 404 const std::string& event_name = event_filter.GetEventName(matcher_id); |
| 389 | 405 |
| 390 // Only send IPCs the last time a filter gets removed. | 406 // Only send IPCs the last time a filter gets removed. |
| 391 std::string extension_id = context()->GetExtensionID(); | 407 std::string extension_id = context()->GetExtensionID(); |
| 392 if (RemoveFilter(event_name, extension_id, event_matcher->value())) { | 408 if (RemoveFilter(event_name, extension_id, event_matcher->value())) { |
| 393 bool remove_lazy = | 409 bool remove_lazy = remove_lazy_event && |
| 394 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); | 410 ExtensionFrameHelper::IsContextForEventPage(context()); |
| 395 content::RenderThread::Get()->Send( | 411 content::RenderThread::Get()->Send( |
| 396 new ExtensionHostMsg_RemoveFilteredListener( | 412 new ExtensionHostMsg_RemoveFilteredListener( |
| 397 extension_id, event_name, *event_matcher->value(), remove_lazy)); | 413 extension_id, event_name, *event_matcher->value(), remove_lazy)); |
| 398 } | 414 } |
| 399 | 415 |
| 400 event_filter.RemoveEventMatcher(matcher_id); | 416 event_filter.RemoveEventMatcher(matcher_id); |
| 401 attached_matcher_ids_.erase(matcher_id); | 417 attached_matcher_ids_.erase(matcher_id); |
| 402 } | 418 } |
| 403 | 419 |
| 404 void EventBindings::AttachUnmanagedEvent( | 420 void EventBindings::AttachUnmanagedEvent( |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 for (int matcher_id : attached_matcher_ids_safe) { | 462 for (int matcher_id : attached_matcher_ids_safe) { |
| 447 DetachFilteredEvent(matcher_id, false /* is_manual */); | 463 DetachFilteredEvent(matcher_id, false /* is_manual */); |
| 448 } | 464 } |
| 449 DCHECK(attached_matcher_ids_.empty()) | 465 DCHECK(attached_matcher_ids_.empty()) |
| 450 << "Filtered events cannot be attached during invalidation"; | 466 << "Filtered events cannot be attached during invalidation"; |
| 451 | 467 |
| 452 g_unmanaged_listeners.Get().erase(context()); | 468 g_unmanaged_listeners.Get().erase(context()); |
| 453 } | 469 } |
| 454 | 470 |
| 455 } // namespace extensions | 471 } // namespace extensions |
| OLD | NEW |