| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |