• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/sessions/session_restore.h"
6 
7 #include <algorithm>
8 #include <list>
9 #include <set>
10 #include <vector>
11 
12 #include "base/callback.h"
13 #include "base/command_line.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/metrics/histogram.h"
16 #include "base/stl_util-inl.h"
17 #include "base/string_util.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sessions/session_service.h"
21 #include "chrome/browser/sessions/session_types.h"
22 #include "chrome/browser/tabs/tab_strip_model.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_list.h"
25 #include "chrome/browser/ui/browser_navigator.h"
26 #include "chrome/browser/ui/browser_window.h"
27 #include "content/browser/renderer_host/render_widget_host.h"
28 #include "content/browser/renderer_host/render_widget_host_view.h"
29 #include "content/browser/tab_contents/navigation_controller.h"
30 #include "content/browser/tab_contents/tab_contents.h"
31 #include "content/browser/tab_contents/tab_contents_view.h"
32 #include "content/common/notification_registrar.h"
33 #include "content/common/notification_service.h"
34 
35 #if defined(OS_CHROMEOS)
36 #include "chrome/browser/chromeos/boot_times_loader.h"
37 #include "chrome/browser/chromeos/network_state_notifier.h"
38 #endif
39 
40 // Are we in the process of restoring?
41 static bool restoring = false;
42 
43 namespace {
44 
45 // TabLoader ------------------------------------------------------------------
46 
47 // Initial delay (see class decription for details).
48 static const int kInitialDelayTimerMS = 100;
49 
50 // TabLoader is responsible for loading tabs after session restore creates
51 // tabs. New tabs are loaded after the current tab finishes loading, or a delay
52 // is reached (initially kInitialDelayTimerMS). If the delay is reached before
53 // a tab finishes loading a new tab is loaded and the time of the delay
54 // doubled. When all tabs are loading TabLoader deletes itself.
55 //
56 // This is not part of SessionRestoreImpl so that synchronous destruction
57 // of SessionRestoreImpl doesn't have timing problems.
58 class TabLoader : public NotificationObserver {
59  public:
60   explicit TabLoader(base::TimeTicks restore_started);
61   ~TabLoader();
62 
63   // Schedules a tab for loading.
64   void ScheduleLoad(NavigationController* controller);
65 
66   // Notifies the loader that a tab has been scheduled for loading through
67   // some other mechanism.
68   void TabIsLoading(NavigationController* controller);
69 
70   // Invokes |LoadNextTab| to load a tab.
71   //
72   // This must be invoked once to start loading.
73   void StartLoading();
74 
75  private:
76   typedef std::set<NavigationController*> TabsLoading;
77   typedef std::list<NavigationController*> TabsToLoad;
78   typedef std::set<RenderWidgetHost*> RenderWidgetHostSet;
79 
80   // Loads the next tab. If there are no more tabs to load this deletes itself,
81   // otherwise |force_load_timer_| is restarted.
82   void LoadNextTab();
83 
84   // NotificationObserver method. Removes the specified tab and loads the next
85   // tab.
86   virtual void Observe(NotificationType type,
87                        const NotificationSource& source,
88                        const NotificationDetails& details);
89 
90   // Removes the listeners from the specified tab and removes the tab from
91   // the set of tabs to load and list of tabs we're waiting to get a load
92   // from.
93   void RemoveTab(NavigationController* tab);
94 
95   // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes
96   // |LoadNextTab| to load the next tab
97   void ForceLoadTimerFired();
98 
99   // Returns the RenderWidgetHost associated with a tab if there is one,
100   // NULL otherwise.
101   static RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab);
102 
103   // Register for necessary notificaitons on a tab navigation controller.
104   void RegisterForNotifications(NavigationController* controller);
105 
106   // Called when a tab goes away or a load completes.
107   void HandleTabClosedOrLoaded(NavigationController* controller);
108 
109   NotificationRegistrar registrar_;
110 
111   // Current delay before a new tab is loaded. See class description for
112   // details.
113   int64 force_load_delay_;
114 
115   // Has Load been invoked?
116   bool loading_;
117 
118   // Have we recorded the times for a tab paint?
119   bool got_first_paint_;
120 
121   // The set of tabs we've initiated loading on. This does NOT include the
122   // selected tabs.
123   TabsLoading tabs_loading_;
124 
125   // The tabs we need to load.
126   TabsToLoad tabs_to_load_;
127 
128   // The renderers we have started loading into.
129   RenderWidgetHostSet render_widget_hosts_loading_;
130 
131   // The renderers we have loaded and are waiting on to paint.
132   RenderWidgetHostSet render_widget_hosts_to_paint_;
133 
134   // The number of tabs that have been restored.
135   int tab_count_;
136 
137   base::OneShotTimer<TabLoader> force_load_timer_;
138 
139   // The time the restore process started.
140   base::TimeTicks restore_started_;
141 
142   DISALLOW_COPY_AND_ASSIGN(TabLoader);
143 };
144 
TabLoader(base::TimeTicks restore_started)145 TabLoader::TabLoader(base::TimeTicks restore_started)
146     : force_load_delay_(kInitialDelayTimerMS),
147       loading_(false),
148       got_first_paint_(false),
149       tab_count_(0),
150       restore_started_(restore_started) {
151 }
152 
~TabLoader()153 TabLoader::~TabLoader() {
154   DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
155           tabs_loading_.empty() && tabs_to_load_.empty());
156 }
157 
ScheduleLoad(NavigationController * controller)158 void TabLoader::ScheduleLoad(NavigationController* controller) {
159   DCHECK(controller);
160   DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
161          tabs_to_load_.end());
162   tabs_to_load_.push_back(controller);
163   RegisterForNotifications(controller);
164 }
165 
TabIsLoading(NavigationController * controller)166 void TabLoader::TabIsLoading(NavigationController* controller) {
167   DCHECK(controller);
168   DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
169          tabs_loading_.end());
170   tabs_loading_.insert(controller);
171   RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
172   DCHECK(render_widget_host);
173   render_widget_hosts_loading_.insert(render_widget_host);
174   RegisterForNotifications(controller);
175 }
176 
StartLoading()177 void TabLoader::StartLoading() {
178   registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT,
179                  NotificationService::AllSources());
180 #if defined(OS_CHROMEOS)
181   if (chromeos::NetworkStateNotifier::is_connected()) {
182     loading_ = true;
183     LoadNextTab();
184   } else {
185     // Start listening to network state notification now.
186     registrar_.Add(this, NotificationType::NETWORK_STATE_CHANGED,
187                    NotificationService::AllSources());
188   }
189 #else
190   loading_ = true;
191   LoadNextTab();
192 #endif
193 }
194 
LoadNextTab()195 void TabLoader::LoadNextTab() {
196   if (!tabs_to_load_.empty()) {
197     NavigationController* tab = tabs_to_load_.front();
198     DCHECK(tab);
199     tabs_loading_.insert(tab);
200     tabs_to_load_.pop_front();
201     tab->LoadIfNecessary();
202     if (tab->tab_contents()) {
203       int tab_index;
204       Browser* browser = Browser::GetBrowserForController(tab, &tab_index);
205       if (browser && browser->active_index() != tab_index) {
206         // By default tabs are marked as visible. As only the active tab is
207         // visible we need to explicitly tell non-active tabs they are hidden.
208         // Without this call non-active tabs are not marked as backgrounded.
209         //
210         // NOTE: We need to do this here rather than when the tab is added to
211         // the Browser as at that time not everything has been created, so that
212         // the call would do nothing.
213         tab->tab_contents()->WasHidden();
214       }
215     }
216   }
217 
218   if (!tabs_to_load_.empty()) {
219     force_load_timer_.Stop();
220     // Each time we load a tab we also set a timer to force us to start loading
221     // the next tab if this one doesn't load quickly enough.
222     force_load_timer_.Start(
223         base::TimeDelta::FromMilliseconds(force_load_delay_),
224         this, &TabLoader::ForceLoadTimerFired);
225   }
226 }
227 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)228 void TabLoader::Observe(NotificationType type,
229                         const NotificationSource& source,
230                         const NotificationDetails& details) {
231   switch (type.value) {
232 #if defined(OS_CHROMEOS)
233     case NotificationType::NETWORK_STATE_CHANGED: {
234       chromeos::NetworkStateDetails* state_details =
235           Details<chromeos::NetworkStateDetails>(details).ptr();
236       switch (state_details->state()) {
237         case chromeos::NetworkStateDetails::CONNECTED:
238           if (!loading_) {
239             loading_ = true;
240             LoadNextTab();
241           }
242           // Start loading
243           break;
244         case chromeos::NetworkStateDetails::CONNECTING:
245         case chromeos::NetworkStateDetails::DISCONNECTED:
246           // Disconnected while loading. Set loading_ false so
247           // that it stops trying to load next tab.
248           loading_ = false;
249           break;
250         default:
251           NOTREACHED() << "Unknown nework state notification:"
252                        << state_details->state();
253       }
254       break;
255     }
256 #endif
257     case NotificationType::LOAD_START: {
258       // Add this render_widget_host to the set of those we're waiting for
259       // paints on. We want to only record stats for paints that occur after
260       // a load has finished.
261       NavigationController* tab = Source<NavigationController>(source).ptr();
262       RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab);
263       DCHECK(render_widget_host);
264       render_widget_hosts_loading_.insert(render_widget_host);
265       break;
266     }
267     case NotificationType::TAB_CONTENTS_DESTROYED: {
268       TabContents* tab_contents = Source<TabContents>(source).ptr();
269       if (!got_first_paint_) {
270         RenderWidgetHost* render_widget_host =
271             GetRenderWidgetHost(&tab_contents->controller());
272         render_widget_hosts_loading_.erase(render_widget_host);
273       }
274       HandleTabClosedOrLoaded(&tab_contents->controller());
275       break;
276     }
277     case NotificationType::LOAD_STOP: {
278       NavigationController* tab = Source<NavigationController>(source).ptr();
279       render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab));
280       HandleTabClosedOrLoaded(tab);
281       break;
282     }
283     case NotificationType::RENDER_WIDGET_HOST_DID_PAINT: {
284       if (!got_first_paint_) {
285         RenderWidgetHost* render_widget_host =
286             Source<RenderWidgetHost>(source).ptr();
287         if (render_widget_hosts_to_paint_.find(render_widget_host) !=
288             render_widget_hosts_to_paint_.end()) {
289           // Got a paint for one of our renderers, so record time.
290           got_first_paint_ = true;
291           base::TimeDelta time_to_paint =
292               base::TimeTicks::Now() - restore_started_;
293           UMA_HISTOGRAM_CUSTOM_TIMES(
294               "SessionRestore.FirstTabPainted",
295               time_to_paint,
296               base::TimeDelta::FromMilliseconds(10),
297               base::TimeDelta::FromSeconds(100),
298               100);
299           // Record a time for the number of tabs, to help track down
300           // contention.
301           std::string time_for_count =
302               StringPrintf("SessionRestore.FirstTabPainted_%d", tab_count_);
303           base::Histogram* counter_for_count =
304               base::Histogram::FactoryTimeGet(
305                   time_for_count,
306                   base::TimeDelta::FromMilliseconds(10),
307                   base::TimeDelta::FromSeconds(100),
308                   100,
309                   base::Histogram::kUmaTargetedHistogramFlag);
310           counter_for_count->AddTime(time_to_paint);
311         } else if (render_widget_hosts_loading_.find(render_widget_host) ==
312             render_widget_hosts_loading_.end()) {
313           // If this is a host for a tab we're not loading some other tab
314           // has rendered and there's no point tracking the time. This could
315           // happen because the user opened a different tab or restored tabs
316           // to an already existing browser and an existing tab painted.
317           got_first_paint_ = true;
318         }
319       }
320       break;
321     }
322     default:
323       NOTREACHED() << "Unknown notification received:" << type.value;
324   }
325   // Delete ourselves when we're not waiting for any more notifications.
326   if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
327       tabs_loading_.empty() && tabs_to_load_.empty())
328     delete this;
329 }
330 
RemoveTab(NavigationController * tab)331 void TabLoader::RemoveTab(NavigationController* tab) {
332   registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
333                     Source<TabContents>(tab->tab_contents()));
334   registrar_.Remove(this, NotificationType::LOAD_STOP,
335                     Source<NavigationController>(tab));
336   registrar_.Remove(this, NotificationType::LOAD_START,
337                     Source<NavigationController>(tab));
338 
339   TabsLoading::iterator i = tabs_loading_.find(tab);
340   if (i != tabs_loading_.end())
341     tabs_loading_.erase(i);
342 
343   TabsToLoad::iterator j =
344       find(tabs_to_load_.begin(), tabs_to_load_.end(), tab);
345   if (j != tabs_to_load_.end())
346     tabs_to_load_.erase(j);
347 }
348 
ForceLoadTimerFired()349 void TabLoader::ForceLoadTimerFired() {
350   force_load_delay_ *= 2;
351   LoadNextTab();
352 }
353 
GetRenderWidgetHost(NavigationController * tab)354 RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
355   TabContents* tab_contents = tab->tab_contents();
356   if (tab_contents) {
357     RenderWidgetHostView* render_widget_host_view =
358         tab_contents->GetRenderWidgetHostView();
359     if (render_widget_host_view)
360       return render_widget_host_view->GetRenderWidgetHost();
361   }
362   return NULL;
363 }
364 
RegisterForNotifications(NavigationController * controller)365 void TabLoader::RegisterForNotifications(NavigationController* controller) {
366   registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
367                  Source<TabContents>(controller->tab_contents()));
368   registrar_.Add(this, NotificationType::LOAD_STOP,
369                  Source<NavigationController>(controller));
370   registrar_.Add(this, NotificationType::LOAD_START,
371                  Source<NavigationController>(controller));
372   ++tab_count_;
373 }
374 
HandleTabClosedOrLoaded(NavigationController * tab)375 void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
376   RemoveTab(tab);
377   if (loading_)
378     LoadNextTab();
379   if (tabs_loading_.empty() && tabs_to_load_.empty()) {
380     base::TimeDelta time_to_load =
381         base::TimeTicks::Now() - restore_started_;
382     UMA_HISTOGRAM_CUSTOM_TIMES(
383         "SessionRestore.AllTabsLoaded",
384         time_to_load,
385         base::TimeDelta::FromMilliseconds(10),
386         base::TimeDelta::FromSeconds(100),
387         100);
388     // Record a time for the number of tabs, to help track down contention.
389     std::string time_for_count =
390         StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_);
391     base::Histogram* counter_for_count =
392         base::Histogram::FactoryTimeGet(
393             time_for_count,
394             base::TimeDelta::FromMilliseconds(10),
395             base::TimeDelta::FromSeconds(100),
396             100,
397             base::Histogram::kUmaTargetedHistogramFlag);
398     counter_for_count->AddTime(time_to_load);
399   }
400 }
401 
402 // SessionRestoreImpl ---------------------------------------------------------
403 
404 // SessionRestoreImpl is responsible for fetching the set of tabs to create
405 // from SessionService. SessionRestoreImpl deletes itself when done.
406 
407 class SessionRestoreImpl : public NotificationObserver {
408  public:
SessionRestoreImpl(Profile * profile,Browser * browser,bool synchronous,bool clobber_existing_window,bool always_create_tabbed_browser,const std::vector<GURL> & urls_to_open)409   SessionRestoreImpl(Profile* profile,
410                      Browser* browser,
411                      bool synchronous,
412                      bool clobber_existing_window,
413                      bool always_create_tabbed_browser,
414                      const std::vector<GURL>& urls_to_open)
415       : profile_(profile),
416         browser_(browser),
417         synchronous_(synchronous),
418         clobber_existing_window_(clobber_existing_window),
419         always_create_tabbed_browser_(always_create_tabbed_browser),
420         urls_to_open_(urls_to_open),
421         restore_started_(base::TimeTicks::Now()) {
422   }
423 
Restore()424   Browser* Restore() {
425     SessionService* session_service = profile_->GetSessionService();
426     DCHECK(session_service);
427     SessionService::SessionCallback* callback =
428         NewCallback(this, &SessionRestoreImpl::OnGotSession);
429     session_service->GetLastSession(&request_consumer_, callback);
430 
431     if (synchronous_) {
432       bool old_state = MessageLoop::current()->NestableTasksAllowed();
433       MessageLoop::current()->SetNestableTasksAllowed(true);
434       MessageLoop::current()->Run();
435       MessageLoop::current()->SetNestableTasksAllowed(old_state);
436       Browser* browser = ProcessSessionWindows(&windows_);
437       delete this;
438       return browser;
439     }
440 
441     if (browser_) {
442       registrar_.Add(this, NotificationType::BROWSER_CLOSED,
443                      Source<Browser>(browser_));
444     }
445 
446     return browser_;
447   }
448 
449   // Restore window(s) from a foreign session.
RestoreForeignSession(std::vector<SessionWindow * >::const_iterator begin,std::vector<SessionWindow * >::const_iterator end)450   void RestoreForeignSession(
451       std::vector<SessionWindow*>::const_iterator begin,
452       std::vector<SessionWindow*>::const_iterator end) {
453     StartTabCreation();
454     // Create a browser instance to put the restored tabs in.
455     for (std::vector<SessionWindow*>::const_iterator i = begin;
456         i != end; ++i) {
457       Browser* browser = CreateRestoredBrowser(
458           static_cast<Browser::Type>((*i)->type),
459           (*i)->bounds,
460           (*i)->is_maximized);
461 
462       // Restore and show the browser.
463       const int initial_tab_count = browser->tab_count();
464       int selected_tab_index = (*i)->selected_tab_index;
465       RestoreTabsToBrowser(*(*i), browser, selected_tab_index);
466       ShowBrowser(browser, initial_tab_count, selected_tab_index);
467       tab_loader_->TabIsLoading(
468           &browser->GetSelectedTabContents()->controller());
469       NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
470     }
471 
472     // Always create in a new window
473     FinishedTabCreation(true, true);
474   }
475 
476   // Restore a single tab from a foreign session.
477   // Note: we currently restore the tab to the last active browser.
RestoreForeignTab(const SessionTab & tab)478   void RestoreForeignTab(const SessionTab& tab) {
479     StartTabCreation();
480     Browser* current_browser =
481         browser_ ? browser_ : BrowserList::GetLastActive();
482     RestoreTab(tab, current_browser->tab_count(), current_browser, true);
483     NotifySessionServiceOfRestoredTabs(current_browser,
484                                        current_browser->tab_count());
485     FinishedTabCreation(true, true);
486   }
487 
~SessionRestoreImpl()488   ~SessionRestoreImpl() {
489     STLDeleteElements(&windows_);
490     restoring = false;
491   }
492 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)493   virtual void Observe(NotificationType type,
494                        const NotificationSource& source,
495                        const NotificationDetails& details) {
496     switch (type.value) {
497       case NotificationType::BROWSER_CLOSED:
498         delete this;
499         return;
500 
501       default:
502         NOTREACHED();
503         break;
504     }
505   }
506 
507  private:
508   // Invoked when beginning to create new tabs. Resets the tab_loader_.
StartTabCreation()509   void StartTabCreation() {
510     tab_loader_.reset(new TabLoader(restore_started_));
511   }
512 
513   // Invoked when done with creating all the tabs/browsers.
514   //
515   // |created_tabbed_browser| indicates whether a tabbed browser was created,
516   // or we used an existing tabbed browser.
517   //
518   // If successful, this begins loading tabs and deletes itself when all tabs
519   // have been loaded.
520   //
521   // Returns the Browser that was created, if any.
FinishedTabCreation(bool succeeded,bool created_tabbed_browser)522   Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) {
523     Browser* browser = NULL;
524     if (!created_tabbed_browser && always_create_tabbed_browser_) {
525       browser = Browser::Create(profile_);
526       if (urls_to_open_.empty()) {
527         // No tab browsers were created and no URLs were supplied on the command
528         // line. Add an empty URL, which is treated as opening the users home
529         // page.
530         urls_to_open_.push_back(GURL());
531       }
532       AppendURLsToBrowser(browser, urls_to_open_);
533       browser->window()->Show();
534     }
535 
536     if (succeeded) {
537       DCHECK(tab_loader_.get());
538       // TabLoader delets itself when done loading.
539       tab_loader_.release()->StartLoading();
540     }
541 
542     if (!synchronous_) {
543       // If we're not synchronous we need to delete ourself.
544       // NOTE: we must use DeleteLater here as most likely we're in a callback
545       // from the history service which doesn't deal well with deleting the
546       // object it is notifying.
547       MessageLoop::current()->DeleteSoon(FROM_HERE, this);
548     }
549 
550     return browser;
551   }
552 
OnGotSession(SessionService::Handle handle,std::vector<SessionWindow * > * windows)553   void OnGotSession(SessionService::Handle handle,
554                     std::vector<SessionWindow*>* windows) {
555     if (synchronous_) {
556       // See comment above windows_ as to why we don't process immediately.
557       windows_.swap(*windows);
558       MessageLoop::current()->Quit();
559       return;
560     }
561 
562     ProcessSessionWindows(windows);
563   }
564 
ProcessSessionWindows(std::vector<SessionWindow * > * windows)565   Browser* ProcessSessionWindows(std::vector<SessionWindow*>* windows) {
566     if (windows->empty()) {
567       // Restore was unsuccessful.
568       return FinishedTabCreation(false, false);
569     }
570 
571     StartTabCreation();
572 
573     Browser* current_browser =
574         browser_ ? browser_ : BrowserList::GetLastActive();
575     // After the for loop this contains the last TABBED_BROWSER. Is null if no
576     // tabbed browsers exist.
577     Browser* last_browser = NULL;
578     bool has_tabbed_browser = false;
579     for (std::vector<SessionWindow*>::iterator i = windows->begin();
580          i != windows->end(); ++i) {
581       Browser* browser = NULL;
582       if (!has_tabbed_browser && (*i)->type == Browser::TYPE_NORMAL)
583         has_tabbed_browser = true;
584       if (i == windows->begin() && (*i)->type == Browser::TYPE_NORMAL &&
585           !clobber_existing_window_) {
586         // If there is an open tabbed browser window, use it. Otherwise fall
587         // through and create a new one.
588         browser = current_browser;
589         if (browser && (browser->type() != Browser::TYPE_NORMAL ||
590                         browser->profile()->IsOffTheRecord())) {
591           browser = NULL;
592         }
593       }
594       if (!browser) {
595         browser = CreateRestoredBrowser(
596             static_cast<Browser::Type>((*i)->type),
597             (*i)->bounds,
598             (*i)->is_maximized);
599       }
600       if ((*i)->type == Browser::TYPE_NORMAL)
601         last_browser = browser;
602       const int initial_tab_count = browser->tab_count();
603       int selected_tab_index = (*i)->selected_tab_index;
604       RestoreTabsToBrowser(*(*i), browser, selected_tab_index);
605       ShowBrowser(browser, initial_tab_count, selected_tab_index);
606       tab_loader_->TabIsLoading(
607           &browser->GetSelectedTabContents()->controller());
608       NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
609     }
610 
611     // If we're restoring a session as the result of a crash and the session
612     // included at least one tabbed browser, then close the browser window
613     // that was opened when the user clicked to restore the session.
614     if (clobber_existing_window_ && current_browser && has_tabbed_browser &&
615         current_browser->type() == Browser::TYPE_NORMAL) {
616       current_browser->CloseAllTabs();
617     }
618     if (last_browser && !urls_to_open_.empty())
619       AppendURLsToBrowser(last_browser, urls_to_open_);
620     // If last_browser is NULL and urls_to_open_ is non-empty,
621     // FinishedTabCreation will create a new TabbedBrowser and add the urls to
622     // it.
623     Browser* finished_browser = FinishedTabCreation(true, has_tabbed_browser);
624     if (finished_browser)
625       last_browser = finished_browser;
626     return last_browser;
627   }
628 
RestoreTabsToBrowser(const SessionWindow & window,Browser * browser,int selected_tab_index)629   void RestoreTabsToBrowser(const SessionWindow& window,
630                             Browser* browser,
631                             int selected_tab_index) {
632     DCHECK(!window.tabs.empty());
633     for (std::vector<SessionTab*>::const_iterator i = window.tabs.begin();
634          i != window.tabs.end(); ++i) {
635       const SessionTab& tab = *(*i);
636       const int tab_index = static_cast<int>(i - window.tabs.begin());
637       // Don't schedule a load for the selected tab, as ShowBrowser() will
638       // already have done that.
639       RestoreTab(tab, tab_index, browser, tab_index != selected_tab_index);
640     }
641   }
642 
RestoreTab(const SessionTab & tab,const int tab_index,Browser * browser,bool schedule_load)643   void RestoreTab(const SessionTab& tab,
644                   const int tab_index,
645                   Browser* browser,
646                   bool schedule_load) {
647     DCHECK(!tab.navigations.empty());
648     int selected_index = tab.current_navigation_index;
649     selected_index = std::max(
650         0,
651         std::min(selected_index,
652                  static_cast<int>(tab.navigations.size() - 1)));
653 
654     // Record an app launch, if applicable.
655     GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url();
656     if (
657 #if defined(OS_CHROMEOS)
658         browser->profile()->GetExtensionService() &&
659 #endif
660         browser->profile()->GetExtensionService()->IsInstalledApp(url)) {
661       UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
662                                 extension_misc::APP_LAUNCH_SESSION_RESTORE,
663                                 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
664     }
665 
666     TabContents* tab_contents =
667         browser->AddRestoredTab(tab.navigations,
668                                 tab_index,
669                                 selected_index,
670                                 tab.extension_app_id,
671                                 false,
672                                 tab.pinned,
673                                 true,
674                                 NULL);
675     if (schedule_load)
676       tab_loader_->ScheduleLoad(&tab_contents->controller());
677   }
678 
CreateRestoredBrowser(Browser::Type type,gfx::Rect bounds,bool is_maximized)679   Browser* CreateRestoredBrowser(Browser::Type type,
680                                  gfx::Rect bounds,
681                                  bool is_maximized) {
682     Browser* browser = new Browser(type, profile_);
683     browser->set_override_bounds(bounds);
684     browser->set_maximized_state(is_maximized ?
685         Browser::MAXIMIZED_STATE_MAXIMIZED :
686         Browser::MAXIMIZED_STATE_UNMAXIMIZED);
687     browser->InitBrowserWindow();
688     return browser;
689   }
690 
ShowBrowser(Browser * browser,int initial_tab_count,int selected_session_index)691   void ShowBrowser(Browser* browser,
692                    int initial_tab_count,
693                    int selected_session_index) {
694     if (browser_ == browser) {
695       browser->ActivateTabAt(browser->tab_count() - 1, true);
696       return;
697     }
698 
699     DCHECK(browser);
700     DCHECK(browser->tab_count());
701     browser->ActivateTabAt(
702         std::min(initial_tab_count + std::max(0, selected_session_index),
703                  browser->tab_count() - 1), true);
704     browser->window()->Show();
705     // TODO(jcampan): http://crbug.com/8123 we should not need to set the
706     //                initial focus explicitly.
707     browser->GetSelectedTabContents()->view()->SetInitialFocus();
708   }
709 
710   // Appends the urls in |urls| to |browser|.
AppendURLsToBrowser(Browser * browser,const std::vector<GURL> & urls)711   void AppendURLsToBrowser(Browser* browser,
712                            const std::vector<GURL>& urls) {
713     for (size_t i = 0; i < urls.size(); ++i) {
714       int add_types = TabStripModel::ADD_FORCE_INDEX;
715       if (i == 0)
716         add_types |= TabStripModel::ADD_ACTIVE;
717       int index = browser->GetIndexForInsertionDuringRestore(i);
718       browser::NavigateParams params(browser, urls[i],
719                                      PageTransition::START_PAGE);
720       params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
721       params.tabstrip_index = index;
722       params.tabstrip_add_types = add_types;
723       browser::Navigate(&params);
724     }
725   }
726 
727   // Invokes TabRestored on the SessionService for all tabs in browser after
728   // initial_count.
NotifySessionServiceOfRestoredTabs(Browser * browser,int initial_count)729   void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
730     SessionService* session_service = profile_->GetSessionService();
731     for (int i = initial_count; i < browser->tab_count(); ++i)
732       session_service->TabRestored(&browser->GetTabContentsAt(i)->controller(),
733                                    browser->tabstrip_model()->IsTabPinned(i));
734   }
735 
736   // The profile to create the sessions for.
737   Profile* profile_;
738 
739   // The first browser to restore to, may be null.
740   Browser* browser_;
741 
742   // Whether or not restore is synchronous.
743   const bool synchronous_;
744 
745   // See description in RestoreSession (in .h).
746   const bool clobber_existing_window_;
747 
748   // If true and there is an error or there are no windows to restore, we
749   // create a tabbed browser anyway. This is used on startup to make sure at
750   // at least one window is created.
751   const bool always_create_tabbed_browser_;
752 
753   // Set of URLs to open in addition to those restored from the session.
754   std::vector<GURL> urls_to_open_;
755 
756   // Used to get the session.
757   CancelableRequestConsumer request_consumer_;
758 
759   // Responsible for loading the tabs.
760   scoped_ptr<TabLoader> tab_loader_;
761 
762   // When synchronous we run a nested message loop. To avoid creating windows
763   // from the nested message loop (which can make exiting the nested message
764   // loop take a while) we cache the SessionWindows here and create the actual
765   // windows when the nested message loop exits.
766   std::vector<SessionWindow*> windows_;
767 
768   NotificationRegistrar registrar_;
769 
770   // The time we started the restore.
771   base::TimeTicks restore_started_;
772 };
773 
774 }  // namespace
775 
776 // SessionRestore -------------------------------------------------------------
777 
Restore(Profile * profile,Browser * browser,bool synchronous,bool clobber_existing_window,bool always_create_tabbed_browser,const std::vector<GURL> & urls_to_open)778 static Browser* Restore(Profile* profile,
779                         Browser* browser,
780                         bool synchronous,
781                         bool clobber_existing_window,
782                         bool always_create_tabbed_browser,
783                         const std::vector<GURL>& urls_to_open) {
784 #if defined(OS_CHROMEOS)
785   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
786       "SessionRestoreStarted", false);
787 #endif
788   DCHECK(profile);
789   // Always restore from the original profile (incognito profiles have no
790   // session service).
791   profile = profile->GetOriginalProfile();
792   if (!profile->GetSessionService()) {
793     NOTREACHED();
794     return NULL;
795   }
796   restoring = true;
797   profile->set_restored_last_session(true);
798   // SessionRestoreImpl takes care of deleting itself when done.
799   SessionRestoreImpl* restorer =
800       new SessionRestoreImpl(profile, browser, synchronous,
801                              clobber_existing_window,
802                              always_create_tabbed_browser, urls_to_open);
803   return restorer->Restore();
804 }
805 
806 // static
RestoreSession(Profile * profile,Browser * browser,bool clobber_existing_window,bool always_create_tabbed_browser,const std::vector<GURL> & urls_to_open)807 void SessionRestore::RestoreSession(Profile* profile,
808                                     Browser* browser,
809                                     bool clobber_existing_window,
810                                     bool always_create_tabbed_browser,
811                                     const std::vector<GURL>& urls_to_open) {
812   Restore(profile, browser, false, clobber_existing_window,
813           always_create_tabbed_browser, urls_to_open);
814 }
815 
816 // static
RestoreForeignSessionWindows(Profile * profile,std::vector<SessionWindow * >::const_iterator begin,std::vector<SessionWindow * >::const_iterator end)817 void SessionRestore::RestoreForeignSessionWindows(
818     Profile* profile,
819     std::vector<SessionWindow*>::const_iterator begin,
820     std::vector<SessionWindow*>::const_iterator end) {
821   // Create a SessionRestore object to eventually restore the tabs.
822   std::vector<GURL> gurls;
823   SessionRestoreImpl restorer(profile,
824       static_cast<Browser*>(NULL), true, false, true, gurls);
825   restorer.RestoreForeignSession(begin, end);
826 }
827 
828 // static
RestoreForeignSessionTab(Profile * profile,const SessionTab & tab)829 void SessionRestore::RestoreForeignSessionTab(Profile* profile,
830     const SessionTab& tab) {
831   // Create a SessionRestore object to eventually restore the tabs.
832   std::vector<GURL> gurls;
833   SessionRestoreImpl restorer(profile,
834       static_cast<Browser*>(NULL), true, false, true, gurls);
835   restorer.RestoreForeignTab(tab);
836 }
837 
838 // static
RestoreSessionSynchronously(Profile * profile,const std::vector<GURL> & urls_to_open)839 Browser* SessionRestore::RestoreSessionSynchronously(
840     Profile* profile,
841     const std::vector<GURL>& urls_to_open) {
842   return Restore(profile, NULL, true, false, true, urls_to_open);
843 }
844 
845 // static
IsRestoring()846 bool SessionRestore::IsRestoring() {
847   return restoring;
848 }
849