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

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

Issue 146983002: Move pending prerender logic into PrerenderLinkManager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 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) 2012 The Chromium Authors. All rights reserved. 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 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_link_manager.h" 5 #include "chrome/browser/prerender/prerender_link_manager.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <set> 8 #include <set>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "chrome/browser/prerender/prerender_contents.h" 12 #include "chrome/browser/prerender/prerender_contents.h"
13 #include "chrome/browser/prerender/prerender_handle.h" 13 #include "chrome/browser/prerender/prerender_handle.h"
14 #include "chrome/browser/prerender/prerender_manager.h" 14 #include "chrome/browser/prerender/prerender_manager.h"
15 #include "chrome/browser/prerender/prerender_manager_factory.h" 15 #include "chrome/browser/prerender/prerender_manager_factory.h"
16 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/tab_contents/tab_util.h"
17 #include "chrome/common/prerender_messages.h" 18 #include "chrome/common/prerender_messages.h"
18 #include "content/public/browser/render_process_host.h" 19 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h" 20 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/session_storage_namespace.h" 21 #include "content/public/browser/session_storage_namespace.h"
21 #include "content/public/common/referrer.h" 22 #include "content/public/common/referrer.h"
22 #include "ui/gfx/size.h" 23 #include "ui/gfx/size.h"
23 #include "url/gurl.h" 24 #include "url/gurl.h"
24 25
25 using base::TimeDelta; 26 using base::TimeDelta;
26 using base::TimeTicks; 27 using base::TimeTicks;
27 using content::RenderViewHost; 28 using content::RenderViewHost;
28 using content::SessionStorageNamespace; 29 using content::SessionStorageNamespace;
29 30
30 namespace { 31 namespace {
31 32
32 void Send(int child_id, IPC::Message* raw_message) { 33 void Send(int child_id, IPC::Message* raw_message) {
33 using content::RenderProcessHost; 34 using content::RenderProcessHost;
34 scoped_ptr<IPC::Message> own_message(raw_message); 35 scoped_ptr<IPC::Message> own_message(raw_message);
35 36
36 RenderProcessHost* render_process_host = RenderProcessHost::FromID(child_id); 37 RenderProcessHost* render_process_host = RenderProcessHost::FromID(child_id);
37 if (!render_process_host) 38 if (!render_process_host)
38 return; 39 return;
39 render_process_host->Send(own_message.release()); 40 render_process_host->Send(own_message.release());
40 } 41 }
41 42
42 } // namespace 43 } // namespace
43 44
44 namespace prerender { 45 namespace prerender {
45 46
47 // Helper class to implement PrerenderContents::Observer and watch prerenders
48 // which launch other prerenders.
49 class PrerenderLinkManager::PendingPrerenderManager
50 : public PrerenderContents::Observer {
51 public:
52 explicit PendingPrerenderManager(PrerenderLinkManager* link_manager)
53 : link_manager_(link_manager) {
54 }
55
56 ~PendingPrerenderManager() {
57 DCHECK(observed_launchers_.empty());
58 for (std::set<PrerenderContents*>::iterator i = observed_launchers_.begin();
59 i != observed_launchers_.end(); ++i) {
60 (*i)->RemoveObserver(this);
61 }
62 }
63
64 void ObserveLauncher(PrerenderContents* launcher) {
65 DCHECK_EQ(FINAL_STATUS_MAX, launcher->final_status());
66 if (observed_launchers_.find(launcher) != observed_launchers_.end())
67 return;
68 observed_launchers_.insert(launcher);
69 launcher->AddObserver(this);
70 }
71
72 virtual void OnPrerenderStart(PrerenderContents* launcher) OVERRIDE {
73 }
74 virtual void OnPrerenderStop(PrerenderContents* launcher) OVERRIDE {
75 observed_launchers_.erase(launcher);
76 if (launcher->final_status() == FINAL_STATUS_USED) {
77 link_manager_->StartPendingPrerendersForLauncher(launcher);
davidben 2014/01/24 17:50:43 (This does result in AddPrerender being called whi
78 } else {
79 link_manager_->CancelPendingPrerendersForLauncher(launcher);
80 }
81 }
82
83 private:
84 // A pointer to the parent PrerenderLinkManager.
85 PrerenderLinkManager* link_manager_;
86
87 // The set of PrerenderContentses being observed. Lifetimes are managed by
88 // OnPrerenderStop.
89 std::set<PrerenderContents*> observed_launchers_;
90 };
91
46 PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager) 92 PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager)
47 : has_shutdown_(false), 93 : has_shutdown_(false),
48 manager_(manager) { 94 manager_(manager),
95 pending_prerender_manager_(new PendingPrerenderManager(this)) {
49 } 96 }
50 97
51 PrerenderLinkManager::~PrerenderLinkManager() { 98 PrerenderLinkManager::~PrerenderLinkManager() {
52 for (std::list<LinkPrerender>::iterator i = prerenders_.begin(); 99 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
53 i != prerenders_.end(); ++i) { 100 i != prerenders_.end(); ++i) {
54 if (i->handle) { 101 if (i->handle) {
55 DCHECK(!i->handle->IsPrerendering()) 102 DCHECK(!i->handle->IsPrerendering())
56 << "All running prerenders should stop at the same time as the " 103 << "All running prerenders should stop at the same time as the "
57 << "PrerenderManager."; 104 << "PrerenderManager.";
58 delete i->handle; 105 delete i->handle;
(...skipping 11 matching lines...) Expand all
70 DCHECK_EQ(static_cast<LinkPrerender*>(NULL), 117 DCHECK_EQ(static_cast<LinkPrerender*>(NULL),
71 FindByLauncherChildIdAndPrerenderId(launcher_child_id, 118 FindByLauncherChildIdAndPrerenderId(launcher_child_id,
72 prerender_id)); 119 prerender_id));
73 content::RenderProcessHost* rph = 120 content::RenderProcessHost* rph =
74 content::RenderProcessHost::FromID(launcher_child_id); 121 content::RenderProcessHost::FromID(launcher_child_id);
75 // Guests inside <webview> do not support cross-process navigation and so we 122 // Guests inside <webview> do not support cross-process navigation and so we
76 // do not allow guests to prerender content. 123 // do not allow guests to prerender content.
77 if (rph && rph->IsGuest()) 124 if (rph && rph->IsGuest())
78 return; 125 return;
79 126
127 // Check if the launcher is itself an unswapped prerender.
128 content::WebContents* web_contents = tab_util::GetWebContentsByID(
129 launcher_child_id, render_view_route_id);
130 if (web_contents == NULL)
131 return;
132 PrerenderContents* prerender_contents =
133 manager_->GetPrerenderContents(web_contents);
134 if (prerender_contents &&
135 prerender_contents->final_status() != FINAL_STATUS_MAX) {
136 // The launcher is a prerender about to be destroyed asynchronously, but
137 // its AddLinkRelPrerender message raced with shutdown. Ignore it.
138 DCHECK_NE(FINAL_STATUS_USED, prerender_contents->final_status());
139 return;
140 }
141
80 LinkPrerender 142 LinkPrerender
81 prerender(launcher_child_id, prerender_id, url, referrer, size, 143 prerender(launcher_child_id, prerender_id, url, referrer, size,
82 render_view_route_id, manager_->GetCurrentTimeTicks()); 144 render_view_route_id, manager_->GetCurrentTimeTicks(),
145 prerender_contents);
83 prerenders_.push_back(prerender); 146 prerenders_.push_back(prerender);
84 StartPrerenders(); 147 if (prerender_contents) {
148 pending_prerender_manager_->ObserveLauncher(prerender_contents);
149 } else {
150 StartPrerenders();
151 }
85 } 152 }
86 153
87 void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) { 154 void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
88 LinkPrerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id, 155 LinkPrerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
89 prerender_id); 156 prerender_id);
90 if (!prerender) 157 if (!prerender)
91 return; 158 return;
92 159
93 CancelPrerender(prerender); 160 CancelPrerender(prerender);
94 StartPrerenders(); 161 StartPrerenders();
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 } 198 }
132 } 199 }
133 200
134 PrerenderLinkManager::LinkPrerender::LinkPrerender( 201 PrerenderLinkManager::LinkPrerender::LinkPrerender(
135 int launcher_child_id, 202 int launcher_child_id,
136 int prerender_id, 203 int prerender_id,
137 const GURL& url, 204 const GURL& url,
138 const content::Referrer& referrer, 205 const content::Referrer& referrer,
139 const gfx::Size& size, 206 const gfx::Size& size,
140 int render_view_route_id, 207 int render_view_route_id,
141 TimeTicks creation_time) : launcher_child_id(launcher_child_id), 208 TimeTicks creation_time,
142 prerender_id(prerender_id), 209 PrerenderContents* deferred_launcher)
143 url(url), 210 : launcher_child_id(launcher_child_id),
144 referrer(referrer), 211 prerender_id(prerender_id),
145 size(size), 212 url(url),
146 render_view_route_id(render_view_route_id), 213 referrer(referrer),
147 creation_time(creation_time), 214 size(size),
148 handle(NULL), 215 render_view_route_id(render_view_route_id),
149 is_match_complete_replacement(false), 216 creation_time(creation_time),
150 has_been_abandoned(false) { 217 deferred_launcher(deferred_launcher),
218 handle(NULL),
219 is_match_complete_replacement(false),
220 has_been_abandoned(false) {
151 } 221 }
152 222
153 PrerenderLinkManager::LinkPrerender::~LinkPrerender() { 223 PrerenderLinkManager::LinkPrerender::~LinkPrerender() {
154 DCHECK_EQ(static_cast<PrerenderHandle*>(NULL), handle) 224 DCHECK_EQ(static_cast<PrerenderHandle*>(NULL), handle)
155 << "The PrerenderHandle should be destroyed before its Prerender."; 225 << "The PrerenderHandle should be destroyed before its Prerender.";
156 } 226 }
157 227
158 bool PrerenderLinkManager::IsEmpty() const { 228 bool PrerenderLinkManager::IsEmpty() const {
159 return prerenders_.empty(); 229 return prerenders_.empty();
160 } 230 }
(...skipping 16 matching lines...) Expand all
177 std::list<LinkPrerender*> abandoned_prerenders; 247 std::list<LinkPrerender*> abandoned_prerenders;
178 std::list<std::list<LinkPrerender>::iterator> pending_prerenders; 248 std::list<std::list<LinkPrerender>::iterator> pending_prerenders;
179 std::multiset<std::pair<int, int> > 249 std::multiset<std::pair<int, int> >
180 running_launcher_and_render_view_routes; 250 running_launcher_and_render_view_routes;
181 251
182 // Scan the list, counting how many prerenders have handles (and so were added 252 // Scan the list, counting how many prerenders have handles (and so were added
183 // to the PrerenderManager). The count is done for the system as a whole, and 253 // to the PrerenderManager). The count is done for the system as a whole, and
184 // also per launcher. 254 // also per launcher.
185 for (std::list<LinkPrerender>::iterator i = prerenders_.begin(); 255 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
186 i != prerenders_.end(); ++i) { 256 i != prerenders_.end(); ++i) {
257 // Skip prerenders launched by a prerender.
258 if (i->deferred_launcher)
259 continue;
187 if (!i->handle) { 260 if (!i->handle) {
188 pending_prerenders.push_back(i); 261 pending_prerenders.push_back(i);
189 } else { 262 } else {
190 ++total_started_prerender_count; 263 ++total_started_prerender_count;
191 if (i->has_been_abandoned) { 264 if (i->has_been_abandoned) {
192 abandoned_prerenders.push_back(&(*i)); 265 abandoned_prerenders.push_back(&(*i));
193 } else { 266 } else {
194 // We do not count abandoned prerenders towards their launcher, since it 267 // We do not count abandoned prerenders towards their launcher, since it
195 // has already navigated on to another page. 268 // has already navigated on to another page.
196 std::pair<int, int> launcher_and_render_view_route( 269 std::pair<int, int> launcher_and_render_view_route(
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 i->handle = NULL; 386 i->handle = NULL;
314 prerenders_.erase(i); 387 prerenders_.erase(i);
315 if (own_handle) 388 if (own_handle)
316 own_handle->OnCancel(); 389 own_handle->OnCancel();
317 return; 390 return;
318 } 391 }
319 } 392 }
320 NOTREACHED(); 393 NOTREACHED();
321 } 394 }
322 395
396 void PrerenderLinkManager::StartPendingPrerendersForLauncher(
397 PrerenderContents* launcher) {
398 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
399 i != prerenders_.end(); ++i) {
400 if (i->deferred_launcher == launcher)
401 i->deferred_launcher = NULL;
402 }
403 StartPrerenders();
404 }
405
406 void PrerenderLinkManager::CancelPendingPrerendersForLauncher(
407 PrerenderContents* launcher) {
408 // Remove all pending prerenders for this launcher.
409 std::list<LinkPrerender>::iterator iter = prerenders_.begin();
410 while (iter != prerenders_.end()) {
411 // Increment iterator first so it isn't invalidated.
412 std::list<LinkPrerender>::iterator current = iter++;
413 if (current->deferred_launcher == launcher) {
414 DCHECK(!current->handle);
415 prerenders_.erase(current);
416 }
417 }
418 }
419
323 void PrerenderLinkManager::Shutdown() { 420 void PrerenderLinkManager::Shutdown() {
324 has_shutdown_ = true; 421 has_shutdown_ = true;
325 } 422 }
326 423
327 // In practice, this is always called from either 424 // In practice, this is always called from either
328 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending 425 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending
329 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom. 426 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom.
330 void PrerenderLinkManager::OnPrerenderStart( 427 void PrerenderLinkManager::OnPrerenderStart(
331 PrerenderHandle* prerender_handle) { 428 PrerenderHandle* prerender_handle) {
332 LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle); 429 LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 DCHECK(!prerender->is_match_complete_replacement); 468 DCHECK(!prerender->is_match_complete_replacement);
372 prerender->is_match_complete_replacement = true; 469 prerender->is_match_complete_replacement = true;
373 Send(prerender->launcher_child_id, 470 Send(prerender->launcher_child_id,
374 new PrerenderMsg_OnPrerenderStop(prerender->prerender_id)); 471 new PrerenderMsg_OnPrerenderStop(prerender->prerender_id));
375 // Do not call RemovePrerender here. The replacement needs to stay connected 472 // Do not call RemovePrerender here. The replacement needs to stay connected
376 // to the HTMLLinkElement in the renderer so it notices renderer-triggered 473 // to the HTMLLinkElement in the renderer so it notices renderer-triggered
377 // cancelations. 474 // cancelations.
378 } 475 }
379 476
380 } // namespace prerender 477 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698