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

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

Issue 878513005: Extensions: suspend extension's scripts when V8 is paused (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed ActivityLogPrerenderTest.TestScriptInjected Created 5 years, 10 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/script_injection_manager.h" 5 #include "extensions/renderer/script_injection_manager.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/memory/weak_ptr.h" 9 #include "base/memory/weak_ptr.h"
10 #include "base/values.h" 10 #include "base/values.h"
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 void ScriptInjectionManager::RVOHelper::InvalidateFrame( 235 void ScriptInjectionManager::RVOHelper::InvalidateFrame(
236 blink::WebFrame* frame) { 236 blink::WebFrame* frame) {
237 pending_idle_frames_.erase(frame); 237 pending_idle_frames_.erase(frame);
238 manager_->InvalidateForFrame(frame); 238 manager_->InvalidateForFrame(frame);
239 } 239 }
240 240
241 ScriptInjectionManager::ScriptInjectionManager( 241 ScriptInjectionManager::ScriptInjectionManager(
242 const ExtensionSet* extensions, 242 const ExtensionSet* extensions,
243 UserScriptSetManager* user_script_set_manager) 243 UserScriptSetManager* user_script_set_manager)
244 : extensions_(extensions), 244 : extensions_(extensions),
245 injecting_scripts_(false),
246 user_script_set_manager_(user_script_set_manager), 245 user_script_set_manager_(user_script_set_manager),
247 user_script_set_manager_observer_(this) { 246 user_script_set_manager_observer_(this) {
248 user_script_set_manager_observer_.Add(user_script_set_manager_); 247 user_script_set_manager_observer_.Add(user_script_set_manager_);
249 } 248 }
250 249
251 ScriptInjectionManager::~ScriptInjectionManager() { 250 ScriptInjectionManager::~ScriptInjectionManager() {
252 } 251 }
253 252
254 void ScriptInjectionManager::OnRenderViewCreated( 253 void ScriptInjectionManager::OnRenderViewCreated(
255 content::RenderView* render_view) { 254 content::RenderView* render_view) {
256 rvo_helpers_.push_back(new RVOHelper(render_view, this)); 255 rvo_helpers_.push_back(new RVOHelper(render_view, this));
257 } 256 }
258 257
258 void ScriptInjectionManager::OnInjectionFinished(
259 ScriptInjection* injection,
260 scoped_refptr<ScriptsRunInfo> scripts_run_info) {
261 blink::WebFrame* frame = injection->web_frame();
262 UserScript::RunLocation run_location = injection->run_location();
263
264 ScopedVector<ScriptInjection>::iterator it;
265 for (it = running_injections_.begin(); it != running_injections_.end(); ++it){
266 running_injections_.erase(it);
267 break;
268 }
269
270 if (scripts_run_info && scripts_run_info->HasOneRef() && IsFrameValid(frame))
Devlin 2015/02/25 18:02:15 ref counted lifetimes are already somewhat Evil.
kozy 2015/02/27 17:32:28 I've removed ref counted Scripts Run Info and retu
Devlin 2015/02/27 18:25:32 Fair enough. More than anything else, I'd want to
kozy 2015/02/28 15:23:21 I've added _BlockedScriptCount metrics to ScriptsR
271 scripts_run_info->LogRun(frame, run_location);
272 }
273
259 void ScriptInjectionManager::OnUserScriptsUpdated( 274 void ScriptInjectionManager::OnUserScriptsUpdated(
260 const std::set<std::string>& changed_extensions, 275 const std::set<std::string>& changed_extensions,
261 const std::vector<UserScript*>& scripts) { 276 const std::vector<UserScript*>& scripts) {
262 for (ScopedVector<ScriptInjection>::iterator iter = 277 for (ScopedVector<ScriptInjection>::iterator iter =
263 pending_injections_.begin(); 278 pending_injections_.begin();
264 iter != pending_injections_.end();) { 279 iter != pending_injections_.end();) {
265 if (changed_extensions.count((*iter)->host_id().id()) > 0) 280 if (changed_extensions.count((*iter)->host_id().id()) > 0)
266 iter = pending_injections_.erase(iter); 281 iter = pending_injections_.erase(iter);
267 else 282 else
268 ++iter; 283 ++iter;
269 } 284 }
270
271 // If we are currently injecting scripts, we need to make a note that these
272 // extensions were updated.
273 if (injecting_scripts_) {
274 invalidated_while_injecting_.insert(changed_extensions.begin(),
275 changed_extensions.end());
276 }
277 } 285 }
278 286
279 void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) { 287 void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) {
280 for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin(); 288 for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin();
281 iter != rvo_helpers_.end(); 289 iter != rvo_helpers_.end();
282 ++iter) { 290 ++iter) {
283 if (*iter == helper) { 291 if (*iter == helper) {
284 rvo_helpers_.erase(iter); 292 rvo_helpers_.erase(iter);
285 break; 293 break;
286 } 294 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 // Certain run location signals (like DidCreateDocumentElement) can happen 338 // Certain run location signals (like DidCreateDocumentElement) can happen
331 // multiple times. Ignore the subsequent signals. 339 // multiple times. Ignore the subsequent signals.
332 return; 340 return;
333 } 341 }
334 342
335 // Otherwise, all is right in the world, and we can get on with the 343 // Otherwise, all is right in the world, and we can get on with the
336 // injections! 344 // injections!
337 345
338 frame_statuses_[frame] = run_location; 346 frame_statuses_[frame] = run_location;
339 347
340 // If a content script injects blocking code (such as a javascript alert()), 348 InjectScripts(frame, run_location);
341 // then there is a chance that we are running in a nested message loop, and 349 // As above, we might have been blocked, but that means that, in the mean
Devlin 2015/02/25 18:02:15 Isn't the point of this patch that executing scrip
kozy 2015/02/27 17:32:28 Done.
342 // shouldn't inject scripts right now (to avoid conflicts). 350 // time, it's possible the frame advanced. Inject any scripts for run
343 if (!injecting_scripts_) { 351 // locations that were registered, but never ran.
352 while ((iter = frame_statuses_.find(frame)) != frame_statuses_.end() &&
353 iter->second > run_location) {
354 run_location = NextRunLocation(run_location);
355 DCHECK_LE(run_location, UserScript::DOCUMENT_IDLE);
344 InjectScripts(frame, run_location); 356 InjectScripts(frame, run_location);
345 // As above, we might have been blocked, but that means that, in the mean
346 // time, it's possible the frame advanced. Inject any scripts for run
347 // locations that were registered, but never ran.
348 while ((iter = frame_statuses_.find(frame)) != frame_statuses_.end() &&
349 iter->second > run_location) {
350 run_location = NextRunLocation(run_location);
351 DCHECK_LE(run_location, UserScript::DOCUMENT_IDLE);
352 InjectScripts(frame, run_location);
353 }
354 } 357 }
355 } 358 }
356 359
357 void ScriptInjectionManager::InjectScripts( 360 void ScriptInjectionManager::InjectScripts(
358 blink::WebFrame* frame, 361 blink::WebFrame* frame,
359 UserScript::RunLocation run_location) { 362 UserScript::RunLocation run_location) {
360 DCHECK(!injecting_scripts_);
361 DCHECK(invalidated_while_injecting_.empty());
362 base::AutoReset<bool>(&injecting_scripts_, true);
363
364 // Find any injections that want to run on the given frame. 363 // Find any injections that want to run on the given frame.
365 // We create a separate vector for these because there is a chance that 364 // We create a separate vector for these because there is a chance that
366 // injected scripts can block, which can create a nested message loop. When 365 // injected scripts can block, which can create a nested message loop. When
367 // this happens, other signals (like IPCs) can cause |pending_injections_| to 366 // this happens, other signals (like IPCs) can cause |pending_injections_| to
368 // be changed, so we don't want to risk that. 367 // be changed, so we don't want to risk that.
369 ScopedVector<ScriptInjection> frame_injections; 368 ScopedVector<ScriptInjection> frame_injections;
370 for (ScopedVector<ScriptInjection>::iterator iter = 369 for (ScopedVector<ScriptInjection>::iterator iter =
371 pending_injections_.begin(); 370 pending_injections_.begin();
372 iter != pending_injections_.end();) { 371 iter != pending_injections_.end();) {
373 if ((*iter)->web_frame() == frame) { 372 if ((*iter)->web_frame() == frame) {
374 frame_injections.push_back(*iter); 373 frame_injections.push_back(*iter);
375 iter = pending_injections_.weak_erase(iter); 374 iter = pending_injections_.weak_erase(iter);
376 } else { 375 } else {
377 ++iter; 376 ++iter;
378 } 377 }
379 } 378 }
380 379
381 // Add any injections for user scripts. 380 // Add any injections for user scripts.
382 int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView( 381 int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView(
383 frame->top()->view()))->tab_id(); 382 frame->top()->view()))->tab_id();
384 user_script_set_manager_->GetAllInjections( 383 user_script_set_manager_->GetAllInjections(
385 &frame_injections, frame, tab_id, run_location); 384 &frame_injections, frame, tab_id, run_location);
386 385
387 ScriptsRunInfo scripts_run_info; 386 scoped_refptr<ScriptsRunInfo> scripts_run_info(new ScriptsRunInfo());
388 for (ScopedVector<ScriptInjection>::iterator iter = frame_injections.begin(); 387 for (ScopedVector<ScriptInjection>::iterator iter = frame_injections.begin();
389 iter != frame_injections.end();) { 388 iter != frame_injections.end();) {
390 // If a blocking script was injected, there is potentially a possibility 389 // If a blocking script was injected, there is potentially a possibility
391 // that the frame has been invalidated in the time since. Check. 390 // that the frame has been invalidated in the time since. Check.
392 if (!IsFrameValid(frame)) 391 if (!IsFrameValid(frame))
393 break; 392 break;
394 393
395 const std::string& extension_id = (*iter)->host_id().id(); 394 const std::string& extension_id = (*iter)->host_id().id();
396 scoped_ptr<ExtensionInjectionHost> extension_injection_host = 395 scoped_ptr<ExtensionInjectionHost> extension_injection_host =
397 GetExtensionInjectionHost(extension_id, extensions_); 396 GetExtensionInjectionHost(extension_id, extensions_);
398 // Try to inject the script if the extension is not "dirty" (invalidated by 397 // Try to inject the script. If the injection does not finish
399 // an update). If the injection does not finish (i.e., it is waiting for 398 // (i.e., it is waiting for permission), add it to the list of pending
400 // permission), add it to the list of pending injections. 399 // injections. If the injection does not finished, add it to the list of
401 if (invalidated_while_injecting_.count(extension_id) == 0 && 400 // running injections.
402 !(*iter)->TryToInject(run_location, 401 ScriptInjection* injection = *iter;
403 extension_injection_host.get(), 402 injection->SetScriptInjectionManager(this);
404 &scripts_run_info)) { 403 if (!injection->TryToInject(run_location,
405 pending_injections_.insert(pending_injections_.begin(), *iter); 404 extension_injection_host.get(),
405 scripts_run_info)) {
406 pending_injections_.insert(pending_injections_.begin(), injection);
407 iter = frame_injections.weak_erase(iter);
408 } else if (!injection->is_complete()) {
409 running_injections_.insert(running_injections_.begin(), injection);
406 iter = frame_injections.weak_erase(iter); 410 iter = frame_injections.weak_erase(iter);
407 } else { 411 } else {
408 ++iter; 412 ++iter;
409 } 413 }
410 } 414 }
411 415
412 if (IsFrameValid(frame)) 416 frame_injections.clear();
413 scripts_run_info.LogRun(frame, run_location); 417 // If injection executes synchronously in OnInjectionFinished handler we
414 418 // will have two refs to scripts run info and we need call here LogRun
415 invalidated_while_injecting_.clear(); 419 if (scripts_run_info && scripts_run_info->HasOneRef() && IsFrameValid(frame))
420 scripts_run_info->LogRun(frame, run_location);
416 } 421 }
417 422
418 void ScriptInjectionManager::HandleExecuteCode( 423 void ScriptInjectionManager::HandleExecuteCode(
419 const ExtensionMsg_ExecuteCode_Params& params, 424 const ExtensionMsg_ExecuteCode_Params& params,
420 content::RenderView* render_view) { 425 content::RenderView* render_view) {
421 // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it 426 // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it
422 // would indicate a logic error--the browser must direct this request to the 427 // would indicate a logic error--the browser must direct this request to the
423 // right renderer process to begin with. 428 // right renderer process to begin with.
424 blink::WebLocalFrame* main_frame = 429 blink::WebLocalFrame* main_frame =
425 render_view->GetWebView()->mainFrame()->toWebLocalFrame(); 430 render_view->GetWebView()->mainFrame()->toWebLocalFrame();
426 if (!main_frame) { 431 if (!main_frame) {
427 render_view->Send( 432 render_view->Send(
428 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), 433 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(),
429 params.request_id, 434 params.request_id,
430 "No main frame", 435 "No main frame",
431 GURL(std::string()), 436 GURL(std::string()),
432 base::ListValue())); 437 base::ListValue()));
433 return; 438 return;
434 } 439 }
435 440
436 scoped_ptr<ScriptInjection> injection(new ScriptInjection( 441 scoped_ptr<ScriptInjection> injection(new ScriptInjection(
437 scoped_ptr<ScriptInjector>( 442 scoped_ptr<ScriptInjector>(
438 new ProgrammaticScriptInjector(params, main_frame)), 443 new ProgrammaticScriptInjector(params, main_frame)),
439 main_frame, 444 main_frame,
440 HostID(HostID::EXTENSIONS, params.extension_id), 445 HostID(HostID::EXTENSIONS, params.extension_id),
441 static_cast<UserScript::RunLocation>(params.run_at), 446 static_cast<UserScript::RunLocation>(params.run_at),
442 ExtensionHelper::Get(render_view)->tab_id())); 447 ExtensionHelper::Get(render_view)->tab_id()));
443 448
444 ScriptsRunInfo scripts_run_info; 449 scoped_refptr<ScriptsRunInfo> scripts_run_info(new ScriptsRunInfo());
445 FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame); 450 FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame);
446 451
452 blink::WebFrame* frame = injection->web_frame();
453 UserScript::RunLocation run_location = injection->run_location();
454
447 scoped_ptr<ExtensionInjectionHost> extension_injection_host = 455 scoped_ptr<ExtensionInjectionHost> extension_injection_host =
448 GetExtensionInjectionHost(injection->host_id().id(), extensions_); 456 GetExtensionInjectionHost(injection->host_id().id(), extensions_);
449 457 injection->SetScriptInjectionManager(this);
450 if (!injection->TryToInject( 458 if (!injection->TryToInject(
451 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second, 459 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second,
452 extension_injection_host.get(), 460 extension_injection_host.get(),
453 &scripts_run_info)) { 461 scripts_run_info)) {
454 pending_injections_.push_back(injection.release()); 462 pending_injections_.push_back(injection.release());
463 } else if (!injection->is_complete()) {
464 running_injections_.push_back(injection.release());
465 } else {
466 injection = NULL;
455 } 467 }
468
469 if (scripts_run_info && scripts_run_info->HasOneRef() && IsFrameValid(frame))
470 scripts_run_info->LogRun(frame, run_location);
456 } 471 }
457 472
458 void ScriptInjectionManager::HandleExecuteDeclarativeScript( 473 void ScriptInjectionManager::HandleExecuteDeclarativeScript(
459 blink::WebFrame* web_frame, 474 blink::WebFrame* web_frame,
460 int tab_id, 475 int tab_id,
461 const ExtensionId& extension_id, 476 const ExtensionId& extension_id,
462 int script_id, 477 int script_id,
463 const GURL& url) { 478 const GURL& url) {
464 scoped_ptr<ExtensionInjectionHost> extension_injection_host = 479 scoped_ptr<ExtensionInjectionHost> extension_injection_host =
465 GetExtensionInjectionHost(extension_id, extensions_); 480 GetExtensionInjectionHost(extension_id, extensions_);
466 const Extension* extension = extensions_->GetByID(extension_id); 481 const Extension* extension = extensions_->GetByID(extension_id);
467 // TODO(dcheng): This function signature should really be a WebLocalFrame, 482 // TODO(dcheng): This function signature should really be a WebLocalFrame,
468 // rather than trying to coerce it here. 483 // rather than trying to coerce it here.
469 scoped_ptr<ScriptInjection> injection = 484 scoped_ptr<ScriptInjection> injection =
470 user_script_set_manager_->GetInjectionForDeclarativeScript( 485 user_script_set_manager_->GetInjectionForDeclarativeScript(
471 script_id, 486 script_id,
472 web_frame->toWebLocalFrame(), 487 web_frame->toWebLocalFrame(),
473 tab_id, 488 tab_id,
474 url, 489 url,
475 extension); 490 extension);
476 if (injection.get()) { 491 if (injection.get()) {
477 ScriptsRunInfo scripts_run_info; 492 scoped_refptr<ScriptsRunInfo> scripts_run_info(new ScriptsRunInfo());
493 injection->SetScriptInjectionManager(this);
494
495 blink::WebFrame* frame = injection->web_frame();
496 UserScript::RunLocation run_location = injection->run_location();
497
478 // TODO(markdittmer): Use return value of TryToInject for error handling. 498 // TODO(markdittmer): Use return value of TryToInject for error handling.
479 injection->TryToInject(UserScript::BROWSER_DRIVEN, 499 if (injection->TryToInject(UserScript::BROWSER_DRIVEN,
480 extension_injection_host.get(), 500 extension_injection_host.get(),
481 &scripts_run_info); 501 scripts_run_info)) {
482 scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN); 502 if (!injection->is_complete())
503 running_injections_.push_back(injection.release());
504 }
505 injection = NULL;
506 if (scripts_run_info && scripts_run_info->HasOneRef()
507 && IsFrameValid(frame))
508 scripts_run_info->LogRun(frame, run_location);
483 } 509 }
484 } 510 }
485 511
486 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { 512 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) {
487 ScopedVector<ScriptInjection>::iterator iter = 513 ScopedVector<ScriptInjection>::iterator iter =
488 pending_injections_.begin(); 514 pending_injections_.begin();
489 for (; iter != pending_injections_.end(); ++iter) { 515 for (; iter != pending_injections_.end(); ++iter) {
490 if ((*iter)->request_id() == request_id) 516 if ((*iter)->request_id() == request_id)
491 break; 517 break;
492 } 518 }
493 if (iter == pending_injections_.end()) 519 if (iter == pending_injections_.end())
494 return; 520 return;
495 521
496 // At this point, because the request is present in pending_injections_, we 522 // At this point, because the request is present in pending_injections_, we
497 // know that this is the same page that issued the request (otherwise, 523 // know that this is the same page that issued the request (otherwise,
498 // RVOHelper's DidStartProvisionalLoad callback would have caused it to be 524 // RVOHelper's DidStartProvisionalLoad callback would have caused it to be
499 // cleared out). 525 // cleared out).
500 526
501 scoped_ptr<ScriptInjection> injection(*iter); 527 scoped_ptr<ScriptInjection> injection(*iter);
502 pending_injections_.weak_erase(iter); 528 pending_injections_.weak_erase(iter);
503 529
504 ScriptsRunInfo scripts_run_info; 530 injection->SetScriptInjectionManager(this);
531
505 scoped_ptr<ExtensionInjectionHost> extension_injection_host = 532 scoped_ptr<ExtensionInjectionHost> extension_injection_host =
506 GetExtensionInjectionHost(injection->host_id().id(), extensions_); 533 GetExtensionInjectionHost(injection->host_id().id(), extensions_);
507 if (injection->OnPermissionGranted(extension_injection_host.get(), 534 if (injection->OnPermissionGranted(extension_injection_host.get())) {
508 &scripts_run_info)) { 535 if (!injection->is_complete())
509 scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED); 536 running_injections_.push_back(injection.Pass());
510 } 537 }
511 } 538 }
512 539
513 } // namespace extensions 540 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698