1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/prerender/prerender_contents.h"
11 #include "base/bind.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/history/history_tab_helper.h"
15 #include "chrome/browser/prerender/prerender_field_trial.h"
16 #include "chrome/browser/prerender/prerender_final_status.h"
17 #include "chrome/browser/prerender/prerender_handle.h"
18 #include "chrome/browser/prerender/prerender_manager.h"
19 #include "chrome/browser/prerender/prerender_manager_factory.h"
20 #include "chrome/browser/prerender/prerender_resource_throttle.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/tab_helpers.h"
24 #include "chrome/browser/ui/web_contents_sizer.h"
25 #include "chrome/common/prerender_messages.h"
26 #include "chrome/common/render_messages.h"
27 #include "chrome/common/url_constants.h"
28 #include "components/history/core/browser/history_types.h"
29 #include "content/public/browser/browser_child_process_host.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/render_frame_host.h"
33 #include "content/public/browser/render_process_host.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/resource_request_details.h"
36 #include "content/public/browser/session_storage_namespace.h"
37 #include "content/public/browser/web_contents.h"
38 #include "content/public/browser/web_contents_delegate.h"
39 #include "content/public/common/frame_navigate_params.h"
40 #include "ui/base/page_transition_types.h"
41 #include "ui/gfx/geometry/rect.h"
43 using content::BrowserThread
;
44 using content::DownloadItem
;
45 using content::OpenURLParams
;
46 using content::RenderViewHost
;
47 using content::ResourceRedirectDetails
;
48 using content::ResourceType
;
49 using content::SessionStorageNamespace
;
50 using content::WebContents
;
57 std::vector
<base::WeakPtr
<PrerenderResourceThrottle
> > throttles
) {
58 for (size_t i
= 0; i
< throttles
.size(); i
++) {
60 throttles
[i
]->Resume();
66 class PrerenderContentsFactoryImpl
: public PrerenderContents::Factory
{
68 PrerenderContents
* CreatePrerenderContents(
69 PrerenderManager
* prerender_manager
,
72 const content::Referrer
& referrer
,
74 uint8 experiment_id
) override
{
75 return new PrerenderContents(prerender_manager
, profile
,
76 url
, referrer
, origin
, experiment_id
);
80 // WebContentsDelegateImpl -----------------------------------------------------
82 class PrerenderContents::WebContentsDelegateImpl
83 : public content::WebContentsDelegate
{
85 explicit WebContentsDelegateImpl(PrerenderContents
* prerender_contents
)
86 : prerender_contents_(prerender_contents
) {
89 // content::WebContentsDelegate implementation:
90 WebContents
* OpenURLFromTab(WebContents
* source
,
91 const OpenURLParams
& params
) override
{
92 // |OpenURLFromTab| is typically called when a frame performs a navigation
93 // that requires the browser to perform the transition instead of WebKit.
94 // Examples include prerendering a site that redirects to an app URL,
95 // or if --enable-strict-site-isolation is specified and the prerendered
96 // frame redirects to a different origin.
97 // TODO(cbentzel): Consider supporting this if it is a common case during
99 prerender_contents_
->Destroy(FINAL_STATUS_OPEN_URL
);
103 void CloseContents(content::WebContents
* contents
) override
{
104 prerender_contents_
->Destroy(FINAL_STATUS_CLOSED
);
107 void CanDownload(RenderViewHost
* render_view_host
,
109 const std::string
& request_method
,
110 const base::Callback
<void(bool)>& callback
) override
{
111 prerender_contents_
->Destroy(FINAL_STATUS_DOWNLOAD
);
112 // Cancel the download.
116 bool ShouldCreateWebContents(
117 WebContents
* web_contents
,
119 int main_frame_route_id
,
120 WindowContainerType window_container_type
,
121 const base::string16
& frame_name
,
122 const GURL
& target_url
,
123 const std::string
& partition_id
,
124 SessionStorageNamespace
* session_storage_namespace
) override
{
125 // Since we don't want to permit child windows that would have a
126 // window.opener property, terminate prerendering.
127 prerender_contents_
->Destroy(FINAL_STATUS_CREATE_NEW_WINDOW
);
132 bool OnGoToEntryOffset(int offset
) override
{
133 // This isn't allowed because the history merge operation
134 // does not work if there are renderer issued challenges.
135 // TODO(cbentzel): Cancel in this case? May not need to do
136 // since render-issued offset navigations are not guaranteed,
137 // but indicates that the page cares about the history.
141 bool ShouldSuppressDialogs(WebContents
* source
) override
{
142 // We still want to show the user the message when they navigate to this
143 // page, so cancel this prerender.
144 prerender_contents_
->Destroy(FINAL_STATUS_JAVASCRIPT_ALERT
);
145 // Always suppress JavaScript messages if they're triggered by a page being
150 void RegisterProtocolHandler(WebContents
* web_contents
,
151 const std::string
& protocol
,
153 bool user_gesture
) override
{
154 // TODO(mmenke): Consider supporting this if it is a common case during
156 prerender_contents_
->Destroy(FINAL_STATUS_REGISTER_PROTOCOL_HANDLER
);
159 gfx::Size
GetSizeForNewRenderView(WebContents
* web_contents
) const override
{
160 // Have to set the size of the RenderView on initialization to be sure it is
161 // set before the RenderView is hidden on all platforms (esp. Android).
162 return prerender_contents_
->size_
;
166 PrerenderContents
* prerender_contents_
;
169 void PrerenderContents::Observer::OnPrerenderStopLoading(
170 PrerenderContents
* contents
) {
173 void PrerenderContents::Observer::OnPrerenderDomContentLoaded(
174 PrerenderContents
* contents
) {
177 void PrerenderContents::Observer::OnPrerenderCreatedMatchCompleteReplacement(
178 PrerenderContents
* contents
, PrerenderContents
* replacement
) {
181 PrerenderContents::Observer::Observer() {
184 PrerenderContents::Observer::~Observer() {
187 PrerenderContents::PrerenderContents(
188 PrerenderManager
* prerender_manager
,
191 const content::Referrer
& referrer
,
194 : prerendering_has_started_(false),
195 session_storage_namespace_id_(-1),
196 prerender_manager_(prerender_manager
),
201 has_stopped_loading_(false),
202 has_finished_loading_(false),
203 final_status_(FINAL_STATUS_MAX
),
204 match_complete_status_(MATCH_COMPLETE_DEFAULT
),
205 prerendering_has_been_cancelled_(false),
209 experiment_id_(experiment_id
),
211 DCHECK(prerender_manager
!= NULL
);
214 PrerenderContents
* PrerenderContents::CreateMatchCompleteReplacement() {
215 PrerenderContents
* new_contents
= prerender_manager_
->CreatePrerenderContents(
216 prerender_url(), referrer(), origin(), experiment_id());
218 new_contents
->load_start_time_
= load_start_time_
;
219 new_contents
->session_storage_namespace_id_
= session_storage_namespace_id_
;
220 new_contents
->set_match_complete_status(
221 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING
);
223 const bool did_init
= new_contents
->Init();
225 DCHECK_EQ(alias_urls_
.front(), new_contents
->alias_urls_
.front());
226 DCHECK_EQ(1u, new_contents
->alias_urls_
.size());
227 new_contents
->alias_urls_
= alias_urls_
;
228 // Erase all but the first alias URL; the replacement has adopted the
229 // remainder without increasing the renderer-side reference count.
230 alias_urls_
.resize(1);
231 new_contents
->set_match_complete_status(
232 PrerenderContents::MATCH_COMPLETE_REPLACEMENT
);
233 NotifyPrerenderCreatedMatchCompleteReplacement(new_contents
);
237 bool PrerenderContents::Init() {
238 return AddAliasURL(prerender_url_
);
242 PrerenderContents::Factory
* PrerenderContents::CreateFactory() {
243 return new PrerenderContentsFactoryImpl();
247 PrerenderContents
* PrerenderContents::FromWebContents(
248 content::WebContents
* web_contents
) {
251 PrerenderManager
* prerender_manager
= PrerenderManagerFactory::GetForProfile(
252 Profile::FromBrowserContext(web_contents
->GetBrowserContext()));
253 if (!prerender_manager
)
255 return prerender_manager
->GetPrerenderContents(web_contents
);
258 void PrerenderContents::StartPrerendering(
259 const gfx::Size
& size
,
260 SessionStorageNamespace
* session_storage_namespace
) {
261 DCHECK(profile_
!= NULL
);
262 DCHECK(!size
.IsEmpty());
263 DCHECK(!prerendering_has_started_
);
264 DCHECK(prerender_contents_
.get() == NULL
);
265 DCHECK(size_
.IsEmpty());
266 DCHECK_EQ(1U, alias_urls_
.size());
268 session_storage_namespace_id_
= session_storage_namespace
->id();
271 DCHECK(load_start_time_
.is_null());
272 load_start_time_
= base::TimeTicks::Now();
274 // Everything after this point sets up the WebContents object and associated
275 // RenderView for the prerender page. Don't do this for members of the
277 if (prerender_manager_
->IsControlGroup(experiment_id()))
280 if (origin_
== ORIGIN_LOCAL_PREDICTOR
&&
281 IsLocalPredictorPrerenderAlwaysControlEnabled()) {
285 prerendering_has_started_
= true;
287 prerender_contents_
.reset(CreateWebContents(session_storage_namespace
));
288 TabHelpers::AttachTabHelpers(prerender_contents_
.get());
289 content::WebContentsObserver::Observe(prerender_contents_
.get());
291 web_contents_delegate_
.reset(new WebContentsDelegateImpl(this));
292 prerender_contents_
.get()->SetDelegate(web_contents_delegate_
.get());
293 // Set the size of the prerender WebContents.
294 ResizeWebContents(prerender_contents_
.get(), size_
);
296 // TODO(davidben): This logic assumes each prerender has at most one
297 // route. https://crbug.com/440544
298 child_id_
= GetRenderViewHost()->GetProcess()->GetID();
299 route_id_
= GetRenderViewHost()->GetRoutingID();
301 // TODO(davidben): This logic assumes each prerender has at most one
302 // process. https://crbug.com/440544
303 prerender_manager()->AddPrerenderProcessHost(
304 GetRenderViewHost()->GetProcess());
306 NotifyPrerenderStart();
308 // Close ourselves when the application is shutting down.
309 notification_registrar_
.Add(this, chrome::NOTIFICATION_APP_TERMINATING
,
310 content::NotificationService::AllSources());
312 // Register to inform new RenderViews that we're prerendering.
313 notification_registrar_
.Add(
314 this, content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED
,
315 content::Source
<WebContents
>(prerender_contents_
.get()));
317 // Transfer over the user agent override.
318 prerender_contents_
.get()->SetUserAgentOverride(
319 prerender_manager_
->config().user_agent_override
);
321 content::NavigationController::LoadURLParams
load_url_params(
323 load_url_params
.referrer
= referrer_
;
324 load_url_params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
325 if (origin_
== ORIGIN_OMNIBOX
) {
326 load_url_params
.transition_type
= ui::PageTransitionFromInt(
327 ui::PAGE_TRANSITION_TYPED
|
328 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
);
329 } else if (origin_
== ORIGIN_INSTANT
) {
330 load_url_params
.transition_type
= ui::PageTransitionFromInt(
331 ui::PAGE_TRANSITION_GENERATED
|
332 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
);
334 load_url_params
.override_user_agent
=
335 prerender_manager_
->config().is_overriding_user_agent
?
336 content::NavigationController::UA_OVERRIDE_TRUE
:
337 content::NavigationController::UA_OVERRIDE_FALSE
;
338 prerender_contents_
.get()->GetController().LoadURLWithParams(load_url_params
);
341 bool PrerenderContents::GetChildId(int* child_id
) const {
343 DCHECK_GE(child_id_
, -1);
344 *child_id
= child_id_
;
345 return child_id_
!= -1;
348 bool PrerenderContents::GetRouteId(int* route_id
) const {
350 DCHECK_GE(route_id_
, -1);
351 *route_id
= route_id_
;
352 return route_id_
!= -1;
355 void PrerenderContents::SetFinalStatus(FinalStatus final_status
) {
356 DCHECK_GE(final_status
, FINAL_STATUS_USED
);
357 DCHECK_LT(final_status
, FINAL_STATUS_MAX
);
359 DCHECK_EQ(FINAL_STATUS_MAX
, final_status_
);
361 final_status_
= final_status
;
364 PrerenderContents::~PrerenderContents() {
365 DCHECK_NE(FINAL_STATUS_MAX
, final_status());
367 prerendering_has_been_cancelled() || final_status() == FINAL_STATUS_USED
);
368 DCHECK_NE(ORIGIN_MAX
, origin());
370 prerender_manager_
->RecordFinalStatusWithMatchCompleteStatus(
371 origin(), experiment_id(), match_complete_status(), final_status());
373 bool used
= final_status() == FINAL_STATUS_USED
||
374 final_status() == FINAL_STATUS_WOULD_HAVE_BEEN_USED
;
375 prerender_manager_
->RecordNetworkBytes(origin(), used
, network_bytes_
);
377 // Broadcast the removal of aliases.
378 for (content::RenderProcessHost::iterator host_iterator
=
379 content::RenderProcessHost::AllHostsIterator();
380 !host_iterator
.IsAtEnd();
381 host_iterator
.Advance()) {
382 content::RenderProcessHost
* host
= host_iterator
.GetCurrentValue();
383 host
->Send(new PrerenderMsg_OnPrerenderRemoveAliases(alias_urls_
));
386 // If we still have a WebContents, clean up anything we need to and then
388 if (prerender_contents_
.get())
389 delete ReleasePrerenderContents();
392 void PrerenderContents::AddObserver(Observer
* observer
) {
393 DCHECK_EQ(FINAL_STATUS_MAX
, final_status_
);
394 observer_list_
.AddObserver(observer
);
397 void PrerenderContents::RemoveObserver(Observer
* observer
) {
398 observer_list_
.RemoveObserver(observer
);
401 void PrerenderContents::Observe(int type
,
402 const content::NotificationSource
& source
,
403 const content::NotificationDetails
& details
) {
405 // TODO(davidben): Try to remove this in favor of relying on
406 // FINAL_STATUS_PROFILE_DESTROYED.
407 case chrome::NOTIFICATION_APP_TERMINATING
:
408 Destroy(FINAL_STATUS_APP_TERMINATING
);
411 case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED
: {
412 if (prerender_contents_
.get()) {
413 DCHECK_EQ(content::Source
<WebContents
>(source
).ptr(),
414 prerender_contents_
.get());
416 content::Details
<RenderViewHost
> new_render_view_host(details
);
417 OnRenderViewHostCreated(new_render_view_host
.ptr());
419 // Make sure the size of the RenderViewHost has been passed to the new
420 // RenderView. Otherwise, the size may not be sent until the
421 // RenderViewReady event makes it from the render process to the UI
422 // thread of the browser process. When the RenderView receives its
423 // size, is also sets itself to be visible, which would then break the
425 new_render_view_host
->WasResized();
426 prerender_contents_
->WasHidden();
432 NOTREACHED() << "Unexpected notification sent.";
437 void PrerenderContents::OnRenderViewHostCreated(
438 RenderViewHost
* new_render_view_host
) {
441 WebContents
* PrerenderContents::CreateWebContents(
442 SessionStorageNamespace
* session_storage_namespace
) {
443 // TODO(ajwong): Remove the temporary map once prerendering is aware of
444 // multiple session storage namespaces per tab.
445 content::SessionStorageNamespaceMap session_storage_namespace_map
;
446 session_storage_namespace_map
[std::string()] = session_storage_namespace
;
447 return WebContents::CreateWithSessionStorage(
448 WebContents::CreateParams(profile_
), session_storage_namespace_map
);
451 void PrerenderContents::NotifyPrerenderStart() {
452 DCHECK_EQ(FINAL_STATUS_MAX
, final_status_
);
453 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnPrerenderStart(this));
456 void PrerenderContents::NotifyPrerenderStopLoading() {
457 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnPrerenderStopLoading(this));
460 void PrerenderContents::NotifyPrerenderDomContentLoaded() {
461 FOR_EACH_OBSERVER(Observer
, observer_list_
,
462 OnPrerenderDomContentLoaded(this));
465 void PrerenderContents::NotifyPrerenderStop() {
466 DCHECK_NE(FINAL_STATUS_MAX
, final_status_
);
467 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnPrerenderStop(this));
468 observer_list_
.Clear();
471 void PrerenderContents::NotifyPrerenderCreatedMatchCompleteReplacement(
472 PrerenderContents
* replacement
) {
473 FOR_EACH_OBSERVER(Observer
, observer_list_
,
474 OnPrerenderCreatedMatchCompleteReplacement(this,
478 bool PrerenderContents::OnMessageReceived(const IPC::Message
& message
) {
480 // The following messages we do want to consume.
481 IPC_BEGIN_MESSAGE_MAP(PrerenderContents
, message
)
482 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CancelPrerenderForPrinting
,
483 OnCancelPrerenderForPrinting
)
484 IPC_MESSAGE_UNHANDLED(handled
= false)
485 IPC_END_MESSAGE_MAP()
490 bool PrerenderContents::CheckURL(const GURL
& url
) {
491 if (!url
.SchemeIsHTTPOrHTTPS()) {
492 DCHECK_NE(MATCH_COMPLETE_REPLACEMENT_PENDING
, match_complete_status_
);
493 Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME
);
496 if (match_complete_status_
!= MATCH_COMPLETE_REPLACEMENT_PENDING
&&
497 prerender_manager_
->HasRecentlyBeenNavigatedTo(origin(), url
)) {
498 Destroy(FINAL_STATUS_RECENTLY_VISITED
);
504 bool PrerenderContents::AddAliasURL(const GURL
& url
) {
508 alias_urls_
.push_back(url
);
510 for (content::RenderProcessHost::iterator host_iterator
=
511 content::RenderProcessHost::AllHostsIterator();
512 !host_iterator
.IsAtEnd();
513 host_iterator
.Advance()) {
514 content::RenderProcessHost
* host
= host_iterator
.GetCurrentValue();
515 host
->Send(new PrerenderMsg_OnPrerenderAddAlias(url
));
521 bool PrerenderContents::Matches(
523 const SessionStorageNamespace
* session_storage_namespace
) const {
524 // TODO(davidben): Remove any consumers that pass in a NULL
525 // session_storage_namespace and only test with matches.
526 if (session_storage_namespace
&&
527 session_storage_namespace_id_
!= session_storage_namespace
->id()) {
530 return std::count_if(alias_urls_
.begin(), alias_urls_
.end(),
531 std::bind2nd(std::equal_to
<GURL
>(), url
)) != 0;
534 void PrerenderContents::RenderProcessGone(base::TerminationStatus status
) {
535 Destroy(FINAL_STATUS_RENDERER_CRASHED
);
538 void PrerenderContents::RenderFrameCreated(
539 content::RenderFrameHost
* render_frame_host
) {
540 // When a new RenderFrame is created for a prerendering WebContents, tell the
541 // new RenderFrame it's being used for prerendering before any navigations
542 // occur. Note that this is always triggered before the first navigation, so
543 // there's no need to send the message just after the WebContents is created.
544 render_frame_host
->Send(new PrerenderMsg_SetIsPrerendering(
545 render_frame_host
->GetRoutingID(), true));
548 void PrerenderContents::DidStopLoading() {
549 has_stopped_loading_
= true;
550 NotifyPrerenderStopLoading();
553 void PrerenderContents::DocumentLoadedInFrame(
554 content::RenderFrameHost
* render_frame_host
) {
555 if (!render_frame_host
->GetParent())
556 NotifyPrerenderDomContentLoaded();
559 void PrerenderContents::DidStartProvisionalLoadForFrame(
560 content::RenderFrameHost
* render_frame_host
,
561 const GURL
& validated_url
,
563 bool is_iframe_srcdoc
) {
564 if (!render_frame_host
->GetParent()) {
565 if (!CheckURL(validated_url
))
568 // Usually, this event fires if the user clicks or enters a new URL.
569 // Neither of these can happen in the case of an invisible prerender.
570 // So the cause is: Some JavaScript caused a new URL to be loaded. In that
571 // case, the spinner would start again in the browser, so we must reset
572 // has_stopped_loading_ so that the spinner won't be stopped.
573 has_stopped_loading_
= false;
574 has_finished_loading_
= false;
578 void PrerenderContents::DidFinishLoad(
579 content::RenderFrameHost
* render_frame_host
,
580 const GURL
& validated_url
) {
581 if (!render_frame_host
->GetParent())
582 has_finished_loading_
= true;
585 void PrerenderContents::DidNavigateMainFrame(
586 const content::LoadCommittedDetails
& details
,
587 const content::FrameNavigateParams
& params
) {
588 // If the prerender made a second navigation entry, abort the prerender. This
589 // avoids having to correctly implement a complex history merging case (this
590 // interacts with location.replace) and correctly synchronize with the
591 // renderer. The final status may be monitored to see we need to revisit this
592 // decision. This does not affect client redirects as those do not push new
593 // history entries. (Calls to location.replace, navigations before onload, and
594 // <meta http-equiv=refresh> with timeouts under 1 second do not create
595 // entries in Blink.)
596 if (prerender_contents_
->GetController().GetEntryCount() > 1) {
597 Destroy(FINAL_STATUS_NEW_NAVIGATION_ENTRY
);
601 // Add each redirect as an alias. |params.url| is included in
602 // |params.redirects|.
604 // TODO(davidben): We do not correctly patch up history for renderer-initated
605 // navigations which add history entries. http://crbug.com/305660.
606 for (size_t i
= 0; i
< params
.redirects
.size(); i
++) {
607 if (!AddAliasURL(params
.redirects
[i
]))
612 void PrerenderContents::DidGetRedirectForResourceRequest(
613 content::RenderFrameHost
* render_frame_host
,
614 const content::ResourceRedirectDetails
& details
) {
615 // DidGetRedirectForResourceRequest can come for any resource on a page. If
616 // it's a redirect on the top-level resource, the name needs to be remembered
617 // for future matching, and if it redirects to an https resource, it needs to
618 // be canceled. If a subresource is redirected, nothing changes.
619 if (details
.resource_type
!= content::RESOURCE_TYPE_MAIN_FRAME
)
621 CheckURL(details
.new_url
);
624 void PrerenderContents::Destroy(FinalStatus final_status
) {
625 DCHECK_NE(final_status
, FINAL_STATUS_USED
);
627 if (prerendering_has_been_cancelled_
)
630 SetFinalStatus(final_status
);
632 prerendering_has_been_cancelled_
= true;
633 prerender_manager_
->AddToHistory(this);
634 prerender_manager_
->MoveEntryToPendingDelete(this, final_status
);
636 // Note that if this PrerenderContents was made into a MatchComplete
637 // replacement by MoveEntryToPendingDelete, NotifyPrerenderStop will
638 // not reach the PrerenderHandle. Rather
639 // OnPrerenderCreatedMatchCompleteReplacement will propogate that
640 // information to the referer.
641 if (!prerender_manager_
->IsControlGroup(experiment_id()) &&
642 (prerendering_has_started() ||
643 match_complete_status() == MATCH_COMPLETE_REPLACEMENT
)) {
644 NotifyPrerenderStop();
648 base::ProcessMetrics
* PrerenderContents::MaybeGetProcessMetrics() {
649 if (process_metrics_
.get() == NULL
) {
650 // If a PrenderContents hasn't started prerending, don't be fully formed.
651 if (!GetRenderViewHost() || !GetRenderViewHost()->GetProcess())
653 base::ProcessHandle handle
= GetRenderViewHost()->GetProcess()->GetHandle();
654 if (handle
== base::kNullProcessHandle
)
656 #if !defined(OS_MACOSX)
657 process_metrics_
.reset(base::ProcessMetrics::CreateProcessMetrics(handle
));
659 process_metrics_
.reset(base::ProcessMetrics::CreateProcessMetrics(
661 content::BrowserChildProcessHost::GetPortProvider()));
665 return process_metrics_
.get();
668 void PrerenderContents::DestroyWhenUsingTooManyResources() {
669 base::ProcessMetrics
* metrics
= MaybeGetProcessMetrics();
673 size_t private_bytes
, shared_bytes
;
674 if (metrics
->GetMemoryBytes(&private_bytes
, &shared_bytes
) &&
675 private_bytes
> prerender_manager_
->config().max_bytes
) {
676 Destroy(FINAL_STATUS_MEMORY_LIMIT_EXCEEDED
);
680 WebContents
* PrerenderContents::ReleasePrerenderContents() {
681 prerender_contents_
->SetDelegate(NULL
);
682 content::WebContentsObserver::Observe(NULL
);
683 return prerender_contents_
.release();
686 RenderViewHost
* PrerenderContents::GetRenderViewHostMutable() {
687 return const_cast<RenderViewHost
*>(GetRenderViewHost());
690 const RenderViewHost
* PrerenderContents::GetRenderViewHost() const {
691 if (!prerender_contents_
.get())
693 return prerender_contents_
->GetRenderViewHost();
696 void PrerenderContents::DidNavigate(
697 const history::HistoryAddPageArgs
& add_page_args
) {
698 add_page_vector_
.push_back(add_page_args
);
701 void PrerenderContents::CommitHistory(WebContents
* tab
) {
702 HistoryTabHelper
* history_tab_helper
= HistoryTabHelper::FromWebContents(tab
);
703 for (size_t i
= 0; i
< add_page_vector_
.size(); ++i
)
704 history_tab_helper
->UpdateHistoryForNavigation(add_page_vector_
[i
]);
707 base::Value
* PrerenderContents::GetAsValue() const {
708 if (!prerender_contents_
.get())
710 base::DictionaryValue
* dict_value
= new base::DictionaryValue();
711 dict_value
->SetString("url", prerender_url_
.spec());
712 base::TimeTicks current_time
= base::TimeTicks::Now();
713 base::TimeDelta duration
= current_time
- load_start_time_
;
714 dict_value
->SetInteger("duration", duration
.InSeconds());
715 dict_value
->SetBoolean("is_loaded", prerender_contents_
&&
716 !prerender_contents_
->IsLoading());
720 bool PrerenderContents::IsCrossSiteNavigationPending() const {
721 if (!prerender_contents_
)
723 return (prerender_contents_
->GetSiteInstance() !=
724 prerender_contents_
->GetPendingSiteInstance());
727 void PrerenderContents::PrepareForUse() {
728 SetFinalStatus(FINAL_STATUS_USED
);
730 if (prerender_contents_
.get()) {
731 prerender_contents_
->SendToAllFrames(
732 new PrerenderMsg_SetIsPrerendering(MSG_ROUTING_NONE
, false));
735 NotifyPrerenderStop();
737 BrowserThread::PostTask(
740 base::Bind(&ResumeThrottles
, resource_throttles_
));
741 resource_throttles_
.clear();
744 void PrerenderContents::OnCancelPrerenderForPrinting() {
745 Destroy(FINAL_STATUS_WINDOW_PRINT
);
748 void PrerenderContents::AddResourceThrottle(
749 const base::WeakPtr
<PrerenderResourceThrottle
>& throttle
) {
750 resource_throttles_
.push_back(throttle
);
753 void PrerenderContents::AddNetworkBytes(int64 bytes
) {
754 network_bytes_
+= bytes
;
757 } // namespace prerender