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

Side by Side Diff: chrome/browser/prerender/prerender_contents.cc

Issue 7038012: Safely cancel prerenders on threads other than the UI thread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: sync Created 9 years, 7 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/prerender/prerender_contents.h" 5 #include "chrome/browser/prerender/prerender_contents.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/process_util.h" 10 #include "base/process_util.h"
11 #include "base/task.h" 11 #include "base/task.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/background_contents_service.h" 13 #include "chrome/browser/background_contents_service.h"
14 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/history/history_marshaling.h" 15 #include "chrome/browser/history/history_marshaling.h"
16 #include "chrome/browser/prerender/prerender_final_status.h" 16 #include "chrome/browser/prerender/prerender_final_status.h"
17 #include "chrome/browser/prerender/prerender_manager.h" 17 #include "chrome/browser/prerender/prerender_manager.h"
18 #include "chrome/browser/prerender/prerender_render_widget_host_view.h" 18 #include "chrome/browser/prerender/prerender_render_widget_host_view.h"
19 #include "chrome/browser/prerender/prerender_tracker.h"
19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/renderer_preferences_util.h" 21 #include "chrome/browser/renderer_preferences_util.h"
21 #include "chrome/browser/ui/login/login_prompt.h" 22 #include "chrome/browser/ui/login/login_prompt.h"
22 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 23 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
23 #include "chrome/common/extensions/extension_constants.h" 24 #include "chrome/common/extensions/extension_constants.h"
24 #include "chrome/common/extensions/extension_messages.h" 25 #include "chrome/common/extensions/extension_messages.h"
25 #include "chrome/common/icon_messages.h" 26 #include "chrome/common/icon_messages.h"
26 #include "chrome/common/render_messages.h" 27 #include "chrome/common/render_messages.h"
27 #include "chrome/common/url_constants.h" 28 #include "chrome/common/url_constants.h"
28 #include "content/browser/browsing_instance.h" 29 #include "content/browser/browsing_instance.h"
(...skipping 25 matching lines...) Expand all
54 bool operator()(const GURL& url) const { 55 bool operator()(const GURL& url) const {
55 return url.scheme() == url_.scheme() && 56 return url.scheme() == url_.scheme() &&
56 url.host() == url_.host() && 57 url.host() == url_.host() &&
57 url.port() == url_.port() && 58 url.port() == url_.port() &&
58 url.path() == url_.path() && 59 url.path() == url_.path() &&
59 url.query() == url_.query(); 60 url.query() == url_.query();
60 } 61 }
61 GURL url_; 62 GURL url_;
62 }; 63 };
63 64
64 void AddChildRoutePair(ResourceDispatcherHost* resource_dispatcher_host,
65 int child_id, int route_id) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
67 resource_dispatcher_host->AddPrerenderChildRoutePair(child_id, route_id);
68 }
69
70 void RemoveChildRoutePair(ResourceDispatcherHost* resource_dispatcher_host,
71 int child_id, int route_id) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
73 resource_dispatcher_host->RemovePrerenderChildRoutePair(child_id, route_id);
74 }
75
76 } // end namespace 65 } // end namespace
77 66
78 class PrerenderContentsFactoryImpl : public PrerenderContents::Factory { 67 class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
79 public: 68 public:
80 virtual PrerenderContents* CreatePrerenderContents( 69 virtual PrerenderContents* CreatePrerenderContents(
81 PrerenderManager* prerender_manager, Profile* profile, const GURL& url, 70 PrerenderManager* prerender_manager, Profile* profile, const GURL& url,
82 const GURL& referrer) OVERRIDE { 71 const GURL& referrer) OVERRIDE {
83 return new PrerenderContents(prerender_manager, profile, url, referrer); 72 return new PrerenderContents(prerender_manager, profile, url, referrer);
84 } 73 }
85 }; 74 };
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 const GURL& referrer) 128 const GURL& referrer)
140 : prerender_manager_(prerender_manager), 129 : prerender_manager_(prerender_manager),
141 render_view_host_(NULL), 130 render_view_host_(NULL),
142 prerender_url_(url), 131 prerender_url_(url),
143 referrer_(referrer), 132 referrer_(referrer),
144 profile_(profile), 133 profile_(profile),
145 page_id_(0), 134 page_id_(0),
146 ALLOW_THIS_IN_INITIALIZER_LIST(tab_contents_observer_registrar_(this)), 135 ALLOW_THIS_IN_INITIALIZER_LIST(tab_contents_observer_registrar_(this)),
147 has_stopped_loading_(false), 136 has_stopped_loading_(false),
148 final_status_(FINAL_STATUS_MAX), 137 final_status_(FINAL_STATUS_MAX),
149 prerendering_has_started_(false) { 138 prerendering_has_started_(false),
139 child_id_(-1),
140 route_id_(-1) {
150 DCHECK(prerender_manager != NULL); 141 DCHECK(prerender_manager != NULL);
151 } 142 }
152 143
153 bool PrerenderContents::Init() { 144 bool PrerenderContents::Init() {
154 if (!AddAliasURL(prerender_url_)) 145 if (!AddAliasURL(prerender_url_))
155 return false; 146 return false;
156 return true; 147 return true;
157 } 148 }
158 149
159 // static 150 // static
(...skipping 20 matching lines...) Expand all
180 render_view_host_->CreateRenderView(string16()); 171 render_view_host_->CreateRenderView(string16());
181 172
182 OnRenderViewHostCreated(render_view_host_); 173 OnRenderViewHostCreated(render_view_host_);
183 174
184 // Give the RVH a PrerenderRenderWidgetHostView, both so its size can be set 175 // Give the RVH a PrerenderRenderWidgetHostView, both so its size can be set
185 // and so that the prerender can be cancelled under certain circumstances. 176 // and so that the prerender can be cancelled under certain circumstances.
186 PrerenderRenderWidgetHostView* view = 177 PrerenderRenderWidgetHostView* view =
187 new PrerenderRenderWidgetHostView(render_view_host_, this); 178 new PrerenderRenderWidgetHostView(render_view_host_, this);
188 view->Init(source_render_view_host->view()); 179 view->Init(source_render_view_host->view());
189 180
190 // Register this with the ResourceDispatcherHost as a prerender 181 child_id_ = render_view_host_->process()->id();
191 // RenderViewHost. This must be done before the Navigate message to catch all 182 route_id_ = render_view_host_->routing_id();
192 // resource requests, but as it is on the same thread as the Navigate message
193 // (IO) there is no race condition.
194 int process_id = render_view_host_->process()->id();
195 int view_id = render_view_host_->routing_id();
196 183
197 BrowserThread::PostTask( 184 // Register this with the PrerenderTracker as a prerendering RenderViewHost.
198 BrowserThread::IO, FROM_HERE, 185 // This must be done before the Navigate message to catch all resource
199 NewRunnableFunction(&AddChildRoutePair, 186 // requests.
200 g_browser_process->resource_dispatcher_host(), 187 PrerenderTracker::GetInstance()->OnPrerenderingStarted(child_id_, route_id_,
201 process_id, view_id)); 188 prerender_manager_);
202 189
203 // Close ourselves when the application is shutting down. 190 // Close ourselves when the application is shutting down.
204 notification_registrar_.Add(this, NotificationType::APP_TERMINATING, 191 notification_registrar_.Add(this, NotificationType::APP_TERMINATING,
205 NotificationService::AllSources()); 192 NotificationService::AllSources());
206 193
207 // Register for our parent profile to shutdown, so we can shut ourselves down 194 // Register for our parent profile to shutdown, so we can shut ourselves down
208 // as well (should only be called for OTR profiles, as we should receive 195 // as well (should only be called for OTR profiles, as we should receive
209 // APP_TERMINATING before non-OTR profiles are destroyed). 196 // APP_TERMINATING before non-OTR profiles are destroyed).
210 // TODO(tburkard): figure out if this is needed. 197 // TODO(tburkard): figure out if this is needed.
211 notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, 198 notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 // Set the size of the new TC to that of the old TC. 272 // Set the size of the new TC to that of the old TC.
286 gfx::Rect tab_bounds; 273 gfx::Rect tab_bounds;
287 source_tc->view()->GetContainerBounds(&tab_bounds); 274 source_tc->view()->GetContainerBounds(&tab_bounds);
288 prerender_contents_->view()->SizeContents(tab_bounds.size()); 275 prerender_contents_->view()->SizeContents(tab_bounds.size());
289 } 276 }
290 277
291 // Register as an observer of the RenderViewHost so we get messages. 278 // Register as an observer of the RenderViewHost so we get messages.
292 render_view_host_observer_.reset( 279 render_view_host_observer_.reset(
293 new PrerenderRenderViewHostObserver(this, render_view_host_mutable())); 280 new PrerenderRenderViewHostObserver(this, render_view_host_mutable()));
294 281
295 int process_id; 282 child_id_ = render_view_host()->process()->id();
296 int view_id; 283 route_id_ = render_view_host()->routing_id();
297 CHECK(GetChildId(&process_id));
298 CHECK(GetRouteId(&view_id));
299 284
300 // Register this with the ResourceDispatcherHost as a prerender 285 // Register this with the ResourceDispatcherHost as a prerender
301 // RenderViewHost. This must be done before the Navigate message to catch all 286 // RenderViewHost. This must be done before the Navigate message to catch all
302 // resource requests, but as it is on the same thread as the Navigate message 287 // resource requests, but as it is on the same thread as the Navigate message
303 // (IO) there is no race condition. 288 // (IO) there is no race condition.
304 BrowserThread::PostTask( 289 PrerenderTracker::GetInstance()->OnPrerenderingStarted(child_id_, route_id_,
305 BrowserThread::IO, FROM_HERE, 290 prerender_manager_);
306 NewRunnableFunction(&AddChildRoutePair,
307 g_browser_process->resource_dispatcher_host(),
308 process_id, view_id));
309 291
310 // Close ourselves when the application is shutting down. 292 // Close ourselves when the application is shutting down.
311 notification_registrar_.Add(this, NotificationType::APP_TERMINATING, 293 notification_registrar_.Add(this, NotificationType::APP_TERMINATING,
312 NotificationService::AllSources()); 294 NotificationService::AllSources());
313 295
314 // Register for our parent profile to shutdown, so we can shut ourselves down 296 // Register for our parent profile to shutdown, so we can shut ourselves down
315 // as well (should only be called for OTR profiles, as we should receive 297 // as well (should only be called for OTR profiles, as we should receive
316 // APP_TERMINATING before non-OTR profiles are destroyed). 298 // APP_TERMINATING before non-OTR profiles are destroyed).
317 // TODO(tburkard): figure out if this is needed. 299 // TODO(tburkard): figure out if this is needed.
318 notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, 300 notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
(...skipping 27 matching lines...) Expand all
346 328
347 DCHECK(load_start_time_.is_null()); 329 DCHECK(load_start_time_.is_null());
348 load_start_time_ = base::TimeTicks::Now(); 330 load_start_time_ = base::TimeTicks::Now();
349 331
350 new_contents->controller().LoadURL(prerender_url_, 332 new_contents->controller().LoadURL(prerender_url_,
351 referrer_, PageTransition::LINK); 333 referrer_, PageTransition::LINK);
352 } 334 }
353 335
354 bool PrerenderContents::GetChildId(int* child_id) const { 336 bool PrerenderContents::GetChildId(int* child_id) const {
355 CHECK(child_id); 337 CHECK(child_id);
356 const RenderViewHost* prerender_render_view_host = render_view_host(); 338 DCHECK_GE(child_id_, -1);
357 if (prerender_render_view_host) { 339 *child_id = child_id_;
358 *child_id = prerender_render_view_host->process()->id(); 340 return child_id_ != -1;
359 return true;
360 }
361 return false;
362 } 341 }
363 342
364 bool PrerenderContents::GetRouteId(int* route_id) const { 343 bool PrerenderContents::GetRouteId(int* route_id) const {
365 CHECK(route_id); 344 CHECK(route_id);
366 const RenderViewHost* prerender_render_view_host = render_view_host(); 345 DCHECK_GE(route_id_, -1);
367 if (prerender_render_view_host) { 346 *route_id = route_id_;
368 *route_id = prerender_render_view_host->routing_id(); 347 return route_id_ != -1;
369 return true;
370 }
371 return false;
372 } 348 }
373 349
374 void PrerenderContents::set_final_status(FinalStatus final_status) { 350 void PrerenderContents::set_final_status(FinalStatus final_status) {
375 DCHECK(final_status >= FINAL_STATUS_USED && final_status < FINAL_STATUS_MAX); 351 DCHECK(final_status >= FINAL_STATUS_USED && final_status < FINAL_STATUS_MAX);
376 DCHECK(final_status_ == FINAL_STATUS_MAX || 352 DCHECK(final_status_ == FINAL_STATUS_MAX ||
377 final_status_ == FINAL_STATUS_CONTROL_GROUP); 353 final_status_ == FINAL_STATUS_CONTROL_GROUP);
378 354
379 // Don't override final_status_ if it's FINAL_STATUS_CONTROL_GROUP, 355 // Don't override final_status_ if it's FINAL_STATUS_CONTROL_GROUP,
380 // otherwise data will be collected in the Prerender.FinalStatus histogram. 356 // otherwise data will be collected in the Prerender.FinalStatus histogram.
381 if (final_status_ == FINAL_STATUS_CONTROL_GROUP) 357 if (final_status_ == FINAL_STATUS_CONTROL_GROUP)
382 return; 358 return;
383 359
384 final_status_ = final_status; 360 final_status_ = final_status;
385 } 361 }
386 362
387 FinalStatus PrerenderContents::final_status() const { 363 FinalStatus PrerenderContents::final_status() const {
388 return final_status_; 364 return final_status_;
389 } 365 }
390 366
391 PrerenderContents::~PrerenderContents() { 367 PrerenderContents::~PrerenderContents() {
392 DCHECK(final_status_ != FINAL_STATUS_MAX); 368 DCHECK(final_status_ != FINAL_STATUS_MAX);
393 369
394 // If we haven't even started prerendering, we were just in the control 370 // If we haven't even started prerendering, we were just in the control
395 // group, which means we do not want to record the status. 371 // group, which means we do not want to record the status.
396 if (prerendering_has_started()) 372 if (prerendering_has_started())
397 RecordFinalStatus(final_status_); 373 RecordFinalStatus(final_status_);
398 374
399 if (render_view_host_ || prerender_contents_.get()) { 375 // Only delete the RenderViewHost if we own it.
400 RenderViewHost* prerender_render_view_host = render_view_host_mutable(); 376 if (render_view_host_)
377 render_view_host_->Shutdown();
401 378
402 int process_id = prerender_render_view_host->process()->id(); 379 if (child_id_ != -1 && route_id_ != -1) {
403 int view_id = prerender_render_view_host->routing_id(); 380 PrerenderTracker::GetInstance()->OnPrerenderingFinished(
404 381 child_id_, route_id_);
405 BrowserThread::PostTask(
406 BrowserThread::IO, FROM_HERE,
407 NewRunnableFunction(&RemoveChildRoutePair,
408 g_browser_process->resource_dispatcher_host(),
409 process_id, view_id));
410
411 // Only delete the RenderViewHost if we own it.
412 if (render_view_host_)
413 render_view_host_->Shutdown();
414 } 382 }
415 } 383 }
416 384
417 RenderViewHostDelegate::View* PrerenderContents::GetViewDelegate() { 385 RenderViewHostDelegate::View* PrerenderContents::GetViewDelegate() {
418 return this; 386 return this;
419 } 387 }
420 388
421 const GURL& PrerenderContents::GetURL() const { 389 const GURL& PrerenderContents::GetURL() const {
422 return url_; 390 return url_;
423 } 391 }
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 } 700 }
733 701
734 void PrerenderContents::DidStopLoading() { 702 void PrerenderContents::DidStopLoading() {
735 has_stopped_loading_ = true; 703 has_stopped_loading_ = true;
736 } 704 }
737 705
738 void PrerenderContents::Destroy(FinalStatus final_status) { 706 void PrerenderContents::Destroy(FinalStatus final_status) {
739 if (prerender_manager_->IsPendingDelete(this)) 707 if (prerender_manager_->IsPendingDelete(this))
740 return; 708 return;
741 709
710 if (child_id_ != -1 && route_id_ != -1) {
711 // Cancel the prerender in the PrerenderTracker. This is needed
712 // because destroy may be called directly from the UI thread without calling
713 // TryCancel(). This is difficult to completely avoid, since prerendering
714 // can be cancelled before a RenderView is created.
715 bool is_cancelled =
716 PrerenderTracker::GetInstance()->TryCancel(child_id_, route_id_,
717 final_status);
718 CHECK(is_cancelled);
719
720 // A different final status may have been set already from another thread.
721 // If so, use it instead.
722 if (!PrerenderTracker::GetInstance()->GetFinalStatus(child_id_, route_id_,
723 &final_status)) {
724 NOTREACHED();
725 }
726 }
727
742 prerender_manager_->MoveEntryToPendingDelete(this); 728 prerender_manager_->MoveEntryToPendingDelete(this);
743 set_final_status(final_status); 729 set_final_status(final_status);
744 // We may destroy the PrerenderContents before we have initialized the 730 // We may destroy the PrerenderContents before we have initialized the
745 // RenderViewHost. Otherwise set the Observer's PrerenderContents to NULL to 731 // RenderViewHost. Otherwise set the Observer's PrerenderContents to NULL to
746 // avoid any more messages being sent. 732 // avoid any more messages being sent.
747 if (render_view_host_observer_.get()) 733 if (render_view_host_observer_.get())
748 render_view_host_observer_->set_prerender_contents(NULL); 734 render_view_host_observer_->set_prerender_contents(NULL);
749 } 735 }
750 736
751 void PrerenderContents::RendererUnresponsive(RenderViewHost* render_view_host, 737 void PrerenderContents::RendererUnresponsive(RenderViewHost* render_view_host,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
817 } 803 }
818 return render_view_host_; 804 return render_view_host_;
819 } 805 }
820 806
821 void PrerenderContents::CommitHistory(TabContents* tc) { 807 void PrerenderContents::CommitHistory(TabContents* tc) {
822 if (tab_contents_delegate_.get()) 808 if (tab_contents_delegate_.get())
823 tab_contents_delegate_->CommitHistory(tc); 809 tab_contents_delegate_->CommitHistory(tc);
824 } 810 }
825 811
826 } // namespace prerender 812 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698