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

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: check added 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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 void ScriptInjectionManager::RVOHelper::InvalidateFrame( 220 void ScriptInjectionManager::RVOHelper::InvalidateFrame(
221 blink::WebFrame* frame) { 221 blink::WebFrame* frame) {
222 pending_idle_frames_.erase(frame); 222 pending_idle_frames_.erase(frame);
223 manager_->InvalidateForFrame(frame); 223 manager_->InvalidateForFrame(frame);
224 } 224 }
225 225
226 ScriptInjectionManager::ScriptInjectionManager( 226 ScriptInjectionManager::ScriptInjectionManager(
227 const ExtensionSet* extensions, 227 const ExtensionSet* extensions,
228 UserScriptSetManager* user_script_set_manager) 228 UserScriptSetManager* user_script_set_manager)
229 : extensions_(extensions), 229 : extensions_(extensions),
230 injecting_scripts_(false),
231 user_script_set_manager_(user_script_set_manager), 230 user_script_set_manager_(user_script_set_manager),
232 user_script_set_manager_observer_(this) { 231 user_script_set_manager_observer_(this) {
233 user_script_set_manager_observer_.Add(user_script_set_manager_); 232 user_script_set_manager_observer_.Add(user_script_set_manager_);
234 } 233 }
235 234
236 ScriptInjectionManager::~ScriptInjectionManager() { 235 ScriptInjectionManager::~ScriptInjectionManager() {
237 } 236 }
238 237
239 void ScriptInjectionManager::OnRenderViewCreated( 238 void ScriptInjectionManager::OnRenderViewCreated(
240 content::RenderView* render_view) { 239 content::RenderView* render_view) {
241 rvo_helpers_.push_back(new RVOHelper(render_view, this)); 240 rvo_helpers_.push_back(new RVOHelper(render_view, this));
242 } 241 }
243 242
243 void ScriptInjectionManager::OnInjectionFinished(
244 ScriptInjection* injection,
245 ScriptsRunInfo* scripts_run_info) {
246 if (IsFrameValid(injection->web_frame()))
247 scripts_run_info->LogRun(injection->web_frame(), injection->run_location());
248
249 ScopedVector<ScriptInjection>::iterator it;
250 for (it = running_injections_.begin(); it != running_injections_.end(); ++it){
251 running_injections_.erase(it);
252 break;
253 }
254 }
255
244 void ScriptInjectionManager::OnUserScriptsUpdated( 256 void ScriptInjectionManager::OnUserScriptsUpdated(
245 const std::set<std::string>& changed_extensions, 257 const std::set<std::string>& changed_extensions,
246 const std::vector<UserScript*>& scripts) { 258 const std::vector<UserScript*>& scripts) {
247 for (ScopedVector<ScriptInjection>::iterator iter = 259 for (ScopedVector<ScriptInjection>::iterator iter =
248 pending_injections_.begin(); 260 pending_injections_.begin();
249 iter != pending_injections_.end();) { 261 iter != pending_injections_.end();) {
250 if (changed_extensions.count((*iter)->extension_id()) > 0) 262 if (changed_extensions.count((*iter)->extension_id()) > 0)
251 iter = pending_injections_.erase(iter); 263 iter = pending_injections_.erase(iter);
252 else 264 else
253 ++iter; 265 ++iter;
254 } 266 }
255
256 // If we are currently injecting scripts, we need to make a note that these
257 // extensions were updated.
258 if (injecting_scripts_) {
259 invalidated_while_injecting_.insert(changed_extensions.begin(),
260 changed_extensions.end());
261 }
262 } 267 }
263 268
264 void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) { 269 void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) {
265 for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin(); 270 for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin();
266 iter != rvo_helpers_.end(); 271 iter != rvo_helpers_.end();
267 ++iter) { 272 ++iter) {
268 if (*iter == helper) { 273 if (*iter == helper) {
269 rvo_helpers_.erase(iter); 274 rvo_helpers_.erase(iter);
270 break; 275 break;
271 } 276 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 // Certain run location signals (like DidCreateDocumentElement) can happen 320 // Certain run location signals (like DidCreateDocumentElement) can happen
316 // multiple times. Ignore the subsequent signals. 321 // multiple times. Ignore the subsequent signals.
317 return; 322 return;
318 } 323 }
319 324
320 // Otherwise, all is right in the world, and we can get on with the 325 // Otherwise, all is right in the world, and we can get on with the
321 // injections! 326 // injections!
322 327
323 frame_statuses_[frame] = run_location; 328 frame_statuses_[frame] = run_location;
324 329
325 // If a content script injects blocking code (such as a javascript alert()), 330 InjectScripts(frame, run_location);
326 // then there is a chance that we are running in a nested message loop, and 331 // As above, we might have been blocked, but that means that, in the mean
327 // shouldn't inject scripts right now (to avoid conflicts). 332 // time, it's possible the frame advanced. Inject any scripts for run
328 if (!injecting_scripts_) { 333 // locations that were registered, but never ran.
334 while ((iter = frame_statuses_.find(frame)) != frame_statuses_.end() &&
335 iter->second > run_location) {
336 run_location = NextRunLocation(run_location);
337 DCHECK_LE(run_location, UserScript::DOCUMENT_IDLE);
329 InjectScripts(frame, run_location); 338 InjectScripts(frame, run_location);
330 // As above, we might have been blocked, but that means that, in the mean
331 // time, it's possible the frame advanced. Inject any scripts for run
332 // locations that were registered, but never ran.
333 while ((iter = frame_statuses_.find(frame)) != frame_statuses_.end() &&
334 iter->second > run_location) {
335 run_location = NextRunLocation(run_location);
336 DCHECK_LE(run_location, UserScript::DOCUMENT_IDLE);
337 InjectScripts(frame, run_location);
338 }
339 } 339 }
340 } 340 }
341 341
342 void ScriptInjectionManager::InjectScripts( 342 void ScriptInjectionManager::InjectScripts(
343 blink::WebFrame* frame, 343 blink::WebFrame* frame,
344 UserScript::RunLocation run_location) { 344 UserScript::RunLocation run_location) {
345 DCHECK(!injecting_scripts_);
346 DCHECK(invalidated_while_injecting_.empty());
347 base::AutoReset<bool>(&injecting_scripts_, true);
348
349 // Find any injections that want to run on the given frame. 345 // Find any injections that want to run on the given frame.
350 // We create a separate vector for these because there is a chance that 346 // We create a separate vector for these because there is a chance that
351 // injected scripts can block, which can create a nested message loop. When 347 // injected scripts can block, which can create a nested message loop. When
352 // this happens, other signals (like IPCs) can cause |pending_injections_| to 348 // this happens, other signals (like IPCs) can cause |pending_injections_| to
353 // be changed, so we don't want to risk that. 349 // be changed, so we don't want to risk that.
354 ScopedVector<ScriptInjection> frame_injections; 350 ScopedVector<ScriptInjection> frame_injections;
355 for (ScopedVector<ScriptInjection>::iterator iter = 351 for (ScopedVector<ScriptInjection>::iterator iter =
356 pending_injections_.begin(); 352 pending_injections_.begin();
357 iter != pending_injections_.end();) { 353 iter != pending_injections_.end();) {
358 if ((*iter)->web_frame() == frame) { 354 if ((*iter)->web_frame() == frame) {
359 frame_injections.push_back(*iter); 355 frame_injections.push_back(*iter);
360 iter = pending_injections_.weak_erase(iter); 356 iter = pending_injections_.weak_erase(iter);
361 } else { 357 } else {
362 ++iter; 358 ++iter;
363 } 359 }
364 } 360 }
365 361
366 // Add any injections for user scripts. 362 // Add any injections for user scripts.
367 int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView( 363 int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView(
368 frame->top()->view()))->tab_id(); 364 frame->top()->view()))->tab_id();
369 user_script_set_manager_->GetAllInjections( 365 user_script_set_manager_->GetAllInjections(
370 &frame_injections, frame, tab_id, run_location); 366 &frame_injections, frame, tab_id, run_location);
371 367
372 ScriptsRunInfo scripts_run_info;
Devlin 2015/02/11 17:49:58 Having each injection own a ScriptsRunInfo makes t
Devlin 2015/02/19 17:13:00 Still waiting on this?
373 for (ScopedVector<ScriptInjection>::iterator iter = frame_injections.begin(); 368 for (ScopedVector<ScriptInjection>::iterator iter = frame_injections.begin();
374 iter != frame_injections.end();) { 369 iter != frame_injections.end();) {
375 // If a blocking script was injected, there is potentially a possibility 370 // If a blocking script was injected, there is potentially a possibility
376 // that the frame has been invalidated in the time since. Check. 371 // that the frame has been invalidated in the time since. Check.
377 if (!IsFrameValid(frame)) 372 if (!IsFrameValid(frame))
378 break; 373 break;
379 374
380 // Try to inject the script if the extension is not "dirty" (invalidated by 375 // Try to inject the script. If the injection does not started
381 // an update). If the injection does not finish (i.e., it is waiting for 376 // (i.e., it is waiting for permission), add it to the list of pending
382 // permission), add it to the list of pending injections. 377 // injections. If the injection does not finished, add it to the list of
383 if (invalidated_while_injecting_.count((*iter)->extension_id()) == 0 && 378 // running injections.
Devlin 2015/02/11 17:49:58 I don't think it's safe to remove this - can't scr
384 !(*iter)->TryToInject(run_location, 379 ScriptInjection* injection = *iter;
385 extensions_->GetByID((*iter)->extension_id()), 380 injection->SetScriptInjectionManager(this);
386 &scripts_run_info)) { 381 if (!injection->TryToInject(run_location,
382 extensions_->GetByID((*iter)->extension_id()))) {
387 pending_injections_.insert(pending_injections_.begin(), *iter); 383 pending_injections_.insert(pending_injections_.begin(), *iter);
388 iter = frame_injections.weak_erase(iter); 384 iter = frame_injections.weak_erase(iter);
385 } else if (!injection->is_complete()) {
386 running_injections_.insert(running_injections_.begin(), *iter);
387 iter = frame_injections.weak_erase(iter);
389 } else { 388 } else {
390 ++iter; 389 ++iter;
391 } 390 }
392 } 391 }
393
394 if (IsFrameValid(frame))
395 scripts_run_info.LogRun(frame, run_location);
396
397 invalidated_while_injecting_.clear();
398 } 392 }
399 393
400 void ScriptInjectionManager::HandleExecuteCode( 394 void ScriptInjectionManager::HandleExecuteCode(
401 const ExtensionMsg_ExecuteCode_Params& params, 395 const ExtensionMsg_ExecuteCode_Params& params,
402 content::RenderView* render_view) { 396 content::RenderView* render_view) {
403 // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it 397 // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it
404 // would indicate a logic error--the browser must direct this request to the 398 // would indicate a logic error--the browser must direct this request to the
405 // right renderer process to begin with. 399 // right renderer process to begin with.
406 blink::WebLocalFrame* main_frame = 400 blink::WebLocalFrame* main_frame =
407 render_view->GetWebView()->mainFrame()->toWebLocalFrame(); 401 render_view->GetWebView()->mainFrame()->toWebLocalFrame();
408 if (!main_frame) { 402 if (!main_frame) {
409 render_view->Send( 403 render_view->Send(
410 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), 404 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(),
411 params.request_id, 405 params.request_id,
412 "No main frame", 406 "No main frame",
413 GURL(std::string()), 407 GURL(std::string()),
414 base::ListValue())); 408 base::ListValue()));
415 return; 409 return;
416 } 410 }
417 411
418 scoped_ptr<ScriptInjection> injection(new ScriptInjection( 412 scoped_ptr<ScriptInjection> injection(new ScriptInjection(
419 scoped_ptr<ScriptInjector>( 413 scoped_ptr<ScriptInjector>(
420 new ProgrammaticScriptInjector(params, main_frame)), 414 new ProgrammaticScriptInjector(params, main_frame)),
421 main_frame, 415 main_frame,
422 params.extension_id, 416 params.extension_id,
423 static_cast<UserScript::RunLocation>(params.run_at), 417 static_cast<UserScript::RunLocation>(params.run_at),
424 ExtensionHelper::Get(render_view)->tab_id())); 418 ExtensionHelper::Get(render_view)->tab_id()));
425 419
426 ScriptsRunInfo scripts_run_info;
427 FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame); 420 FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame);
421 injection->SetScriptInjectionManager(this);
428 if (!injection->TryToInject( 422 if (!injection->TryToInject(
429 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second, 423 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second,
430 extensions_->GetByID(injection->extension_id()), 424 extensions_->GetByID(injection->extension_id()))) {
431 &scripts_run_info)) {
432 pending_injections_.push_back(injection.release()); 425 pending_injections_.push_back(injection.release());
426 } else if (!injection->is_complete()) {
427 running_injections_.push_back(injection.release());
433 } 428 }
434 } 429 }
435 430
436 void ScriptInjectionManager::HandleExecuteDeclarativeScript( 431 void ScriptInjectionManager::HandleExecuteDeclarativeScript(
437 blink::WebFrame* web_frame, 432 blink::WebFrame* web_frame,
438 int tab_id, 433 int tab_id,
439 const ExtensionId& extension_id, 434 const ExtensionId& extension_id,
440 int script_id, 435 int script_id,
441 const GURL& url) { 436 const GURL& url) {
442 const Extension* extension = extensions_->GetByID(extension_id); 437 const Extension* extension = extensions_->GetByID(extension_id);
443 // TODO(dcheng): This function signature should really be a WebLocalFrame, 438 // TODO(dcheng): This function signature should really be a WebLocalFrame,
444 // rather than trying to coerce it here. 439 // rather than trying to coerce it here.
445 scoped_ptr<ScriptInjection> injection = 440 scoped_ptr<ScriptInjection> injection =
446 user_script_set_manager_->GetInjectionForDeclarativeScript( 441 user_script_set_manager_->GetInjectionForDeclarativeScript(
447 script_id, 442 script_id,
448 web_frame->toWebLocalFrame(), 443 web_frame->toWebLocalFrame(),
449 tab_id, 444 tab_id,
450 url, 445 url,
451 extension); 446 extension);
452 if (injection.get()) { 447 if (injection.get()) {
453 ScriptsRunInfo scripts_run_info; 448 injection->SetScriptInjectionManager(this);
454 // TODO(markdittmer): Use return value of TryToInject for error handling. 449 // TODO(markdittmer): Use return value of TryToInject for error handling.
455 injection->TryToInject(UserScript::BROWSER_DRIVEN, 450 if (injection->TryToInject(UserScript::BROWSER_DRIVEN,
456 extension, 451 extension)) {
457 &scripts_run_info); 452 if (!injection->is_complete())
458 scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN); 453 running_injections_.push_back(injection.release());
454 }
459 } 455 }
460 } 456 }
461 457
462 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { 458 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) {
463 ScopedVector<ScriptInjection>::iterator iter = 459 ScopedVector<ScriptInjection>::iterator iter =
464 pending_injections_.begin(); 460 pending_injections_.begin();
465 for (; iter != pending_injections_.end(); ++iter) { 461 for (; iter != pending_injections_.end(); ++iter) {
466 if ((*iter)->request_id() == request_id) 462 if ((*iter)->request_id() == request_id)
467 break; 463 break;
468 } 464 }
469 if (iter == pending_injections_.end()) 465 if (iter == pending_injections_.end())
470 return; 466 return;
471 467
472 // At this point, because the request is present in pending_injections_, we 468 // At this point, because the request is present in pending_injections_, we
473 // know that this is the same page that issued the request (otherwise, 469 // know that this is the same page that issued the request (otherwise,
474 // RVOHelper's DidStartProvisionalLoad callback would have caused it to be 470 // RVOHelper's DidStartProvisionalLoad callback would have caused it to be
475 // cleared out). 471 // cleared out).
476 472
477 scoped_ptr<ScriptInjection> injection(*iter); 473 scoped_ptr<ScriptInjection> injection(*iter);
478 pending_injections_.weak_erase(iter); 474 pending_injections_.weak_erase(iter);
479 475
480 ScriptsRunInfo scripts_run_info; 476 injection->SetScriptInjectionManager(this);
481 if (injection->OnPermissionGranted(extensions_->GetByID( 477 if (injection->OnPermissionGranted(extensions_->GetByID(
482 injection->extension_id()), 478 injection->extension_id()))) {
483 &scripts_run_info)) { 479 if (!injection->is_complete())
484 scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED); 480 running_injections_.push_back(injection.Pass());
485 } 481 }
486 } 482 }
487 483
488 } // namespace extensions 484 } // namespace extensions
OLDNEW
« extensions/renderer/script_injection.cc ('K') | « extensions/renderer/script_injection_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698