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