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

Side by Side Diff: chrome/browser/sessions/session_restore.cc

Issue 10122007: Session restore: Use the same TabLoader for all profiles. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Code review. Created 8 years, 8 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/sessions/session_restore.h" 5 #include "chrome/browser/sessions/session_restore.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <list> 8 #include <list>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 #include "chrome/browser/chromeos/boot_times_loader.h" 47 #include "chrome/browser/chromeos/boot_times_loader.h"
48 #endif 48 #endif
49 49
50 using content::NavigationController; 50 using content::NavigationController;
51 using content::RenderWidgetHost; 51 using content::RenderWidgetHost;
52 using content::WebContents; 52 using content::WebContents;
53 53
54 namespace { 54 namespace {
55 55
56 class SessionRestoreImpl; 56 class SessionRestoreImpl;
57 class TabLoader;
58
59 TabLoader* shared_tab_loader = NULL;
57 60
58 // Pointers to SessionRestoreImpls which are currently restoring the session. 61 // Pointers to SessionRestoreImpls which are currently restoring the session.
59 std::set<SessionRestoreImpl*>* active_session_restorers = NULL; 62 std::set<SessionRestoreImpl*>* active_session_restorers = NULL;
60 63
61 // TabLoader ------------------------------------------------------------------ 64 // TabLoader ------------------------------------------------------------------
62 65
63 // Initial delay (see class decription for details). 66 // Initial delay (see class decription for details).
64 static const int kInitialDelayTimerMS = 100; 67 static const int kInitialDelayTimerMS = 100;
65 68
66 // TabLoader is responsible for loading tabs after session restore creates 69 // TabLoader is responsible for loading tabs after session restore creates
67 // tabs. New tabs are loaded after the current tab finishes loading, or a delay 70 // tabs. New tabs are loaded after the current tab finishes loading, or a delay
68 // is reached (initially kInitialDelayTimerMS). If the delay is reached before 71 // is reached (initially kInitialDelayTimerMS). If the delay is reached before
69 // a tab finishes loading a new tab is loaded and the time of the delay 72 // a tab finishes loading a new tab is loaded and the time of the delay
70 // doubled. When all tabs are loading TabLoader deletes itself. 73 // doubled.
74 //
75 // TabLoader keeps a reference to itself when it's loading. When it has finished
76 // loading, it drops the reference. If another profile is restored while the
77 // TabLoader is loading, it will schedule its tabs to get loaded by the same
78 // TabLoader. When doing the scheduling, it holds a reference to the TabLoader.
71 // 79 //
72 // This is not part of SessionRestoreImpl so that synchronous destruction 80 // This is not part of SessionRestoreImpl so that synchronous destruction
73 // of SessionRestoreImpl doesn't have timing problems. 81 // of SessionRestoreImpl doesn't have timing problems.
74 class TabLoader : public content::NotificationObserver, 82 class TabLoader : public content::NotificationObserver,
75 public net::NetworkChangeNotifier::OnlineStateObserver { 83 public net::NetworkChangeNotifier::OnlineStateObserver,
84 public base::RefCounted<TabLoader> {
76 public: 85 public:
77 explicit TabLoader(base::TimeTicks restore_started); 86 // Retrieves a pointer to the TabLoader instance shared between profiles, or
78 virtual ~TabLoader(); 87 // creates a new TabLoader if it doesn't exist. If a TabLoader is created, its
88 // starting timestamp is set to |restore_started|.
89 static TabLoader* GetTabLoader(base::TimeTicks restore_started);
79 90
80 // Schedules a tab for loading. 91 // Schedules a tab for loading.
81 void ScheduleLoad(NavigationController* controller); 92 void ScheduleLoad(NavigationController* controller);
82 93
83 // Notifies the loader that a tab has been scheduled for loading through 94 // Notifies the loader that a tab has been scheduled for loading through
84 // some other mechanism. 95 // some other mechanism.
85 void TabIsLoading(NavigationController* controller); 96 void TabIsLoading(NavigationController* controller);
86 97
87 // Invokes |LoadNextTab| to load a tab. 98 // Invokes |LoadNextTab| to load a tab.
88 // 99 //
89 // This must be invoked once to start loading. 100 // This must be invoked once to start loading.
90 void StartLoading(); 101 void StartLoading();
91 102
92 private: 103 private:
104 friend class base::RefCounted<TabLoader>;
105
93 typedef std::set<NavigationController*> TabsLoading; 106 typedef std::set<NavigationController*> TabsLoading;
94 typedef std::list<NavigationController*> TabsToLoad; 107 typedef std::list<NavigationController*> TabsToLoad;
95 typedef std::set<RenderWidgetHost*> RenderWidgetHostSet; 108 typedef std::set<RenderWidgetHost*> RenderWidgetHostSet;
96 109
110 explicit TabLoader(base::TimeTicks restore_started);
111 virtual ~TabLoader();
112
97 // Loads the next tab. If there are no more tabs to load this deletes itself, 113 // Loads the next tab. If there are no more tabs to load this deletes itself,
98 // otherwise |force_load_timer_| is restarted. 114 // otherwise |force_load_timer_| is restarted.
99 void LoadNextTab(); 115 void LoadNextTab();
100 116
101 // NotificationObserver method. Removes the specified tab and loads the next 117 // NotificationObserver method. Removes the specified tab and loads the next
102 // tab. 118 // tab.
103 virtual void Observe(int type, 119 virtual void Observe(int type,
104 const content::NotificationSource& source, 120 const content::NotificationSource& source,
105 const content::NotificationDetails& details) OVERRIDE; 121 const content::NotificationDetails& details) OVERRIDE;
106 122
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 int tab_count_; 171 int tab_count_;
156 172
157 base::OneShotTimer<TabLoader> force_load_timer_; 173 base::OneShotTimer<TabLoader> force_load_timer_;
158 174
159 // The time the restore process started. 175 // The time the restore process started.
160 base::TimeTicks restore_started_; 176 base::TimeTicks restore_started_;
161 177
162 // Max number of tabs that were loaded in parallel (for metrics). 178 // Max number of tabs that were loaded in parallel (for metrics).
163 size_t max_parallel_tab_loads_; 179 size_t max_parallel_tab_loads_;
164 180
181 // For keeping TabLoader alive while it's loading even if no
182 // SessionRestoreImpls reference it.
183 scoped_refptr<TabLoader> this_retainer_;
184
165 DISALLOW_COPY_AND_ASSIGN(TabLoader); 185 DISALLOW_COPY_AND_ASSIGN(TabLoader);
166 }; 186 };
167 187
168 TabLoader::TabLoader(base::TimeTicks restore_started) 188 // static
169 : force_load_delay_(kInitialDelayTimerMS), 189 TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) {
170 loading_(false), 190 if (!shared_tab_loader)
171 got_first_paint_(false), 191 shared_tab_loader = new TabLoader(restore_started);
172 tab_count_(0), 192 return shared_tab_loader;
173 restore_started_(restore_started),
174 max_parallel_tab_loads_(0) {
175 }
176
177 TabLoader::~TabLoader() {
178 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
179 tabs_loading_.empty() && tabs_to_load_.empty());
180 net::NetworkChangeNotifier::RemoveOnlineStateObserver(this);
181 } 193 }
182 194
183 void TabLoader::ScheduleLoad(NavigationController* controller) { 195 void TabLoader::ScheduleLoad(NavigationController* controller) {
184 DCHECK(controller); 196 DCHECK(controller);
185 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) == 197 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
186 tabs_to_load_.end()); 198 tabs_to_load_.end());
187 tabs_to_load_.push_back(controller); 199 tabs_to_load_.push_back(controller);
188 RegisterForNotifications(controller); 200 RegisterForNotifications(controller);
189 } 201 }
190 202
191 void TabLoader::TabIsLoading(NavigationController* controller) { 203 void TabLoader::TabIsLoading(NavigationController* controller) {
192 DCHECK(controller); 204 DCHECK(controller);
193 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) == 205 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
194 tabs_loading_.end()); 206 tabs_loading_.end());
195 tabs_loading_.insert(controller); 207 tabs_loading_.insert(controller);
196 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller); 208 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
197 DCHECK(render_widget_host); 209 DCHECK(render_widget_host);
198 render_widget_hosts_loading_.insert(render_widget_host); 210 render_widget_hosts_loading_.insert(render_widget_host);
199 RegisterForNotifications(controller); 211 RegisterForNotifications(controller);
200 } 212 }
201 213
202 void TabLoader::StartLoading() { 214 void TabLoader::StartLoading() {
215 // When multiple profiles are using the same TabLoader, another profile might
216 // already have started loading. In that case, the tabs scheduled for loading
217 // by this profile are already in the loading queue, and they will get loaded
218 // eventually.
219 if (loading_)
220 return;
203 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_PAINT, 221 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_PAINT,
204 content::NotificationService::AllSources()); 222 content::NotificationService::AllSources());
223 this_retainer_ = this;
205 #if defined(OS_CHROMEOS) 224 #if defined(OS_CHROMEOS)
206 if (!net::NetworkChangeNotifier::IsOffline()) { 225 if (!net::NetworkChangeNotifier::IsOffline()) {
207 loading_ = true; 226 loading_ = true;
208 LoadNextTab(); 227 LoadNextTab();
209 } else { 228 } else {
210 net::NetworkChangeNotifier::AddOnlineStateObserver(this); 229 net::NetworkChangeNotifier::AddOnlineStateObserver(this);
211 } 230 }
212 #else 231 #else
213 loading_ = true; 232 loading_ = true;
214 LoadNextTab(); 233 LoadNextTab();
215 #endif 234 #endif
216 } 235 }
217 236
237 TabLoader::TabLoader(base::TimeTicks restore_started)
238 : force_load_delay_(kInitialDelayTimerMS),
239 loading_(false),
240 got_first_paint_(false),
241 tab_count_(0),
242 restore_started_(restore_started),
243 max_parallel_tab_loads_(0) {
244 }
245
246 TabLoader::~TabLoader() {
247 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
248 tabs_loading_.empty() && tabs_to_load_.empty());
249 net::NetworkChangeNotifier::RemoveOnlineStateObserver(this);
250 shared_tab_loader = NULL;
251 }
252
218 void TabLoader::LoadNextTab() { 253 void TabLoader::LoadNextTab() {
219 if (!tabs_to_load_.empty()) { 254 if (!tabs_to_load_.empty()) {
220 NavigationController* tab = tabs_to_load_.front(); 255 NavigationController* tab = tabs_to_load_.front();
221 DCHECK(tab); 256 DCHECK(tab);
222 tabs_loading_.insert(tab); 257 tabs_loading_.insert(tab);
223 if (tabs_loading_.size() > max_parallel_tab_loads_) 258 if (tabs_loading_.size() > max_parallel_tab_loads_)
224 max_parallel_tab_loads_ = tabs_loading_.size(); 259 max_parallel_tab_loads_ = tabs_loading_.size();
225 tabs_to_load_.pop_front(); 260 tabs_to_load_.pop_front();
226 tab->LoadIfNecessary(); 261 tab->LoadIfNecessary();
227 if (tab->GetWebContents()) { 262 if (tab->GetWebContents()) {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 // happen because the user opened a different tab or restored tabs 353 // happen because the user opened a different tab or restored tabs
319 // to an already existing browser and an existing tab painted. 354 // to an already existing browser and an existing tab painted.
320 got_first_paint_ = true; 355 got_first_paint_ = true;
321 } 356 }
322 } 357 }
323 break; 358 break;
324 } 359 }
325 default: 360 default:
326 NOTREACHED() << "Unknown notification received:" << type; 361 NOTREACHED() << "Unknown notification received:" << type;
327 } 362 }
328 // Delete ourselves when we're not waiting for any more notifications. 363 // Delete ourselves when we're not waiting for any more notifications. If this
364 // was not the last reference, a SessionRestoreImpl holding a reference will
365 // eventually call StartLoading (which assigns this_retainer_), or drop the
366 // reference without initiating a load.
329 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 367 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
330 tabs_loading_.empty() && tabs_to_load_.empty()) 368 tabs_loading_.empty() && tabs_to_load_.empty())
331 delete this; 369 this_retainer_ = NULL;
332 } 370 }
333 371
334 void TabLoader::OnOnlineStateChanged(bool online) { 372 void TabLoader::OnOnlineStateChanged(bool online) {
335 if (online) { 373 if (online) {
336 if (!loading_) { 374 if (!loading_) {
337 loading_ = true; 375 loading_ = true;
338 LoadNextTab(); 376 LoadNextTab();
339 } 377 }
340 } else { 378 } else {
341 loading_ = false; 379 loading_ = false;
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 NOTREACHED(); 627 NOTREACHED();
590 break; 628 break;
591 } 629 }
592 } 630 }
593 631
594 Profile* profile() { return profile_; } 632 Profile* profile() { return profile_; }
595 633
596 private: 634 private:
597 // Invoked when beginning to create new tabs. Resets the tab_loader_. 635 // Invoked when beginning to create new tabs. Resets the tab_loader_.
598 void StartTabCreation() { 636 void StartTabCreation() {
599 tab_loader_.reset(new TabLoader(restore_started_)); 637 tab_loader_ = TabLoader::GetTabLoader(restore_started_);
600 } 638 }
601 639
602 // Invoked when done with creating all the tabs/browsers. 640 // Invoked when done with creating all the tabs/browsers.
603 // 641 //
604 // |created_tabbed_browser| indicates whether a tabbed browser was created, 642 // |created_tabbed_browser| indicates whether a tabbed browser was created,
605 // or we used an existing tabbed browser. 643 // or we used an existing tabbed browser.
606 // 644 //
607 // If successful, this begins loading tabs and deletes itself when all tabs 645 // If successful, this begins loading tabs and deletes itself when all tabs
608 // have been loaded. 646 // have been loaded.
609 // 647 //
610 // Returns the Browser that was created, if any. 648 // Returns the Browser that was created, if any.
611 Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) { 649 Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) {
612 Browser* browser = NULL; 650 Browser* browser = NULL;
613 if (!created_tabbed_browser && always_create_tabbed_browser_) { 651 if (!created_tabbed_browser && always_create_tabbed_browser_) {
614 browser = Browser::Create(profile_); 652 browser = Browser::Create(profile_);
615 if (urls_to_open_.empty()) { 653 if (urls_to_open_.empty()) {
616 // No tab browsers were created and no URLs were supplied on the command 654 // No tab browsers were created and no URLs were supplied on the command
617 // line. Add an empty URL, which is treated as opening the users home 655 // line. Add an empty URL, which is treated as opening the users home
618 // page. 656 // page.
619 urls_to_open_.push_back(GURL()); 657 urls_to_open_.push_back(GURL());
620 } 658 }
621 AppendURLsToBrowser(browser, urls_to_open_); 659 AppendURLsToBrowser(browser, urls_to_open_);
622 browser->window()->Show(); 660 browser->window()->Show();
623 } 661 }
624 662
625 if (succeeded) { 663 if (succeeded) {
626 DCHECK(tab_loader_.get()); 664 DCHECK(tab_loader_.get());
627 // TabLoader deletes itself when done loading. 665 // TabLoader deletes itself when done loading.
628 tab_loader_.release()->StartLoading(); 666 tab_loader_->StartLoading();
667 tab_loader_ = NULL;
629 } 668 }
630 669
631 if (!synchronous_) { 670 if (!synchronous_) {
632 // If we're not synchronous we need to delete ourself. 671 // If we're not synchronous we need to delete ourself.
633 // NOTE: we must use DeleteLater here as most likely we're in a callback 672 // NOTE: we must use DeleteLater here as most likely we're in a callback
634 // from the history service which doesn't deal well with deleting the 673 // from the history service which doesn't deal well with deleting the
635 // object it is notifying. 674 // object it is notifying.
636 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 675 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
637 } 676 }
638 677
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
936 // at least one window is created. 975 // at least one window is created.
937 const bool always_create_tabbed_browser_; 976 const bool always_create_tabbed_browser_;
938 977
939 // Set of URLs to open in addition to those restored from the session. 978 // Set of URLs to open in addition to those restored from the session.
940 std::vector<GURL> urls_to_open_; 979 std::vector<GURL> urls_to_open_;
941 980
942 // Used to get the session. 981 // Used to get the session.
943 CancelableRequestConsumer request_consumer_; 982 CancelableRequestConsumer request_consumer_;
944 983
945 // Responsible for loading the tabs. 984 // Responsible for loading the tabs.
946 scoped_ptr<TabLoader> tab_loader_; 985 scoped_refptr<TabLoader> tab_loader_;
947 986
948 // When synchronous we run a nested message loop. To avoid creating windows 987 // When synchronous we run a nested message loop. To avoid creating windows
949 // from the nested message loop (which can make exiting the nested message 988 // from the nested message loop (which can make exiting the nested message
950 // loop take a while) we cache the SessionWindows here and create the actual 989 // loop take a while) we cache the SessionWindows here and create the actual
951 // windows when the nested message loop exits. 990 // windows when the nested message loop exits.
952 std::vector<SessionWindow*> windows_; 991 std::vector<SessionWindow*> windows_;
953 992
954 content::NotificationRegistrar registrar_; 993 content::NotificationRegistrar registrar_;
955 994
956 // The time we started the restore. 995 // The time we started the restore.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 if (active_session_restorers == NULL) 1059 if (active_session_restorers == NULL)
1021 return false; 1060 return false;
1022 for (std::set<SessionRestoreImpl*>::const_iterator it = 1061 for (std::set<SessionRestoreImpl*>::const_iterator it =
1023 active_session_restorers->begin(); 1062 active_session_restorers->begin();
1024 it != active_session_restorers->end(); ++it) { 1063 it != active_session_restorers->end(); ++it) {
1025 if ((*it)->profile() == profile) 1064 if ((*it)->profile() == profile)
1026 return true; 1065 return true;
1027 } 1066 }
1028 return false; 1067 return false;
1029 } 1068 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698