session_restore.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 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/metrics/histogram.h"
15#include "base/scoped_ptr.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/renderer_host/render_widget_host.h"
21#include "chrome/browser/renderer_host/render_widget_host_view.h"
22#include "chrome/browser/sessions/session_service.h"
23#include "chrome/browser/sessions/session_types.h"
24#include "chrome/browser/tab_contents/navigation_controller.h"
25#include "chrome/browser/tab_contents/tab_contents.h"
26#include "chrome/browser/tab_contents/tab_contents_view.h"
27#include "chrome/browser/tabs/tab_strip_model.h"
28#include "chrome/browser/ui/browser.h"
29#include "chrome/browser/ui/browser_list.h"
30#include "chrome/browser/ui/browser_navigator.h"
31#include "chrome/browser/ui/browser_window.h"
32#include "chrome/common/notification_registrar.h"
33#include "chrome/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?
41static bool restoring = false;
42
43namespace {
44
45// TabLoader ------------------------------------------------------------------
46
47// Initial delay (see class decription for details).
48static 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.
58class 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
145TabLoader::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
153TabLoader::~TabLoader() {
154  DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
155          tabs_loading_.empty() && tabs_to_load_.empty());
156}
157
158void 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
166void 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
177void 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
195void 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->selected_index() != tab_index) {
206        // By default tabs are marked as visible. As only the selected tab is
207        // visible we need to explicitly tell non-selected tabs they are hidden.
208        // Without this call non-selected 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
228void 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        render_widget_hosts_loading_.erase(
271            tab_contents->GetRenderWidgetHostView()->GetRenderWidgetHost());
272      }
273      HandleTabClosedOrLoaded(&tab_contents->controller());
274      break;
275    }
276    case NotificationType::LOAD_STOP: {
277      NavigationController* tab = Source<NavigationController>(source).ptr();
278      render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab));
279      HandleTabClosedOrLoaded(tab);
280      break;
281    }
282    case NotificationType::RENDER_WIDGET_HOST_DID_PAINT: {
283      if (!got_first_paint_) {
284        RenderWidgetHost* render_widget_host =
285            Source<RenderWidgetHost>(source).ptr();
286        if (render_widget_hosts_to_paint_.find(render_widget_host) !=
287            render_widget_hosts_to_paint_.end()) {
288          // Got a paint for one of our renderers, so record time.
289          got_first_paint_ = true;
290          base::TimeDelta time_to_paint =
291              base::TimeTicks::Now() - restore_started_;
292          HISTOGRAM_CUSTOM_TIMES(
293              "SessionRestore.FirstTabPainted",
294              time_to_paint,
295              base::TimeDelta::FromMilliseconds(10),
296              base::TimeDelta::FromSeconds(100),
297              100);
298          // Record a time for the number of tabs, to help track down
299          // contention.
300          std::string time_for_count =
301              StringPrintf("SessionRestore.FirstTabPainted_%d", tab_count_);
302          scoped_refptr<base::Histogram> counter_for_count =
303              base::Histogram::FactoryTimeGet(
304                  time_for_count,
305                  base::TimeDelta::FromMilliseconds(10),
306                  base::TimeDelta::FromSeconds(100),
307                  100,
308                  base::Histogram::kNoFlags);
309          counter_for_count->AddTime(time_to_paint);
310        } else if (render_widget_hosts_loading_.find(render_widget_host) ==
311            render_widget_hosts_loading_.end()) {
312          // If this is a host for a tab we're not loading some other tab
313          // has rendered and there's no point tracking the time. This could
314          // happen because the user opened a different tab or restored tabs
315          // to an already existing browser and an existing tab painted.
316          got_first_paint_ = true;
317        }
318      }
319      break;
320    }
321    default:
322      NOTREACHED() << "Unknown notification received:" << type.value;
323  }
324  // Delete ourselves when we're not waiting for any more notifications.
325  if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
326      tabs_loading_.empty() && tabs_to_load_.empty())
327    delete this;
328}
329
330void TabLoader::RemoveTab(NavigationController* tab) {
331  registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
332                    Source<TabContents>(tab->tab_contents()));
333  registrar_.Remove(this, NotificationType::LOAD_STOP,
334                    Source<NavigationController>(tab));
335  registrar_.Remove(this, NotificationType::LOAD_START,
336                    Source<NavigationController>(tab));
337
338  TabsLoading::iterator i = tabs_loading_.find(tab);
339  if (i != tabs_loading_.end())
340    tabs_loading_.erase(i);
341
342  TabsToLoad::iterator j =
343      find(tabs_to_load_.begin(), tabs_to_load_.end(), tab);
344  if (j != tabs_to_load_.end())
345    tabs_to_load_.erase(j);
346}
347
348void TabLoader::ForceLoadTimerFired() {
349  force_load_delay_ *= 2;
350  LoadNextTab();
351}
352
353RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
354  TabContents* tab_contents = tab->tab_contents();
355  if (tab_contents) {
356    RenderWidgetHostView* render_widget_host_view =
357        tab_contents->GetRenderWidgetHostView();
358    if (render_widget_host_view)
359      return render_widget_host_view->GetRenderWidgetHost();
360  }
361  return NULL;
362}
363
364void TabLoader::RegisterForNotifications(NavigationController* controller) {
365  registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
366                 Source<TabContents>(controller->tab_contents()));
367  registrar_.Add(this, NotificationType::LOAD_STOP,
368                 Source<NavigationController>(controller));
369  registrar_.Add(this, NotificationType::LOAD_START,
370                 Source<NavigationController>(controller));
371  ++tab_count_;
372}
373
374void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
375  RemoveTab(tab);
376  if (loading_)
377    LoadNextTab();
378  if (tabs_loading_.empty() && tabs_to_load_.empty()) {
379    base::TimeDelta time_to_load =
380        base::TimeTicks::Now() - restore_started_;
381    HISTOGRAM_CUSTOM_TIMES(
382        "SessionRestore.AllTabsLoaded",
383        time_to_load,
384        base::TimeDelta::FromMilliseconds(10),
385        base::TimeDelta::FromSeconds(100),
386        100);
387    // Record a time for the number of tabs, to help track down contention.
388    std::string time_for_count =
389        StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_);
390    scoped_refptr<base::Histogram> counter_for_count =
391        base::Histogram::FactoryTimeGet(
392            time_for_count,
393            base::TimeDelta::FromMilliseconds(10),
394            base::TimeDelta::FromSeconds(100),
395            100,
396            base::Histogram::kNoFlags);
397    counter_for_count->AddTime(time_to_load);
398  }
399}
400
401// SessionRestoreImpl ---------------------------------------------------------
402
403// SessionRestoreImpl is responsible for fetching the set of tabs to create
404// from SessionService. SessionRestoreImpl deletes itself when done.
405
406class SessionRestoreImpl : public NotificationObserver {
407 public:
408  SessionRestoreImpl(Profile* profile,
409                     Browser* browser,
410                     bool synchronous,
411                     bool clobber_existing_window,
412                     bool always_create_tabbed_browser,
413                     const std::vector<GURL>& urls_to_open)
414      : profile_(profile),
415        browser_(browser),
416        synchronous_(synchronous),
417        clobber_existing_window_(clobber_existing_window),
418        always_create_tabbed_browser_(always_create_tabbed_browser),
419        urls_to_open_(urls_to_open),
420        restore_started_(base::TimeTicks::Now()) {
421  }
422
423  void Restore() {
424    SessionService* session_service = profile_->GetSessionService();
425    DCHECK(session_service);
426    SessionService::SessionCallback* callback =
427        NewCallback(this, &SessionRestoreImpl::OnGotSession);
428    session_service->GetLastSession(&request_consumer_, callback);
429
430    if (synchronous_) {
431      bool old_state = MessageLoop::current()->NestableTasksAllowed();
432      MessageLoop::current()->SetNestableTasksAllowed(true);
433      MessageLoop::current()->Run();
434      MessageLoop::current()->SetNestableTasksAllowed(old_state);
435      ProcessSessionWindows(&windows_);
436      delete this;
437      return;
438    }
439
440    if (browser_) {
441      registrar_.Add(this, NotificationType::BROWSER_CLOSED,
442                     Source<Browser>(browser_));
443    }
444  }
445
446  // Restore window(s) from a foreign session.
447  void RestoreForeignSession(
448      std::vector<SessionWindow*>::const_iterator begin,
449      std::vector<SessionWindow*>::const_iterator end) {
450    StartTabCreation();
451    // Create a browser instance to put the restored tabs in.
452    for (std::vector<SessionWindow*>::const_iterator i = begin;
453        i != end; ++i) {
454      Browser* browser = CreateRestoredBrowser(
455          static_cast<Browser::Type>((*i)->type),
456          (*i)->bounds,
457          (*i)->is_maximized);
458
459      // Restore and show the browser.
460      const int initial_tab_count = browser->tab_count();
461      int selected_tab_index = (*i)->selected_tab_index;
462      RestoreTabsToBrowser(*(*i), browser, selected_tab_index);
463      ShowBrowser(browser, initial_tab_count, selected_tab_index);
464      tab_loader_->TabIsLoading(
465          &browser->GetSelectedTabContents()->controller());
466      NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
467    }
468
469    // Always create in a new window
470    FinishedTabCreation(true, true);
471  }
472
473  // Restore a single tab from a foreign session.
474  // Note: we currently restore the tab to the last active browser.
475  void RestoreForeignTab(const SessionTab& tab) {
476    StartTabCreation();
477    Browser* current_browser =
478        browser_ ? browser_ : BrowserList::GetLastActive();
479    RestoreTab(tab, current_browser->tab_count(), current_browser, true);
480    NotifySessionServiceOfRestoredTabs(current_browser,
481                                       current_browser->tab_count());
482    FinishedTabCreation(true, true);
483  }
484
485  ~SessionRestoreImpl() {
486    STLDeleteElements(&windows_);
487    restoring = false;
488  }
489
490  virtual void Observe(NotificationType type,
491                       const NotificationSource& source,
492                       const NotificationDetails& details) {
493    switch (type.value) {
494      case NotificationType::BROWSER_CLOSED:
495        delete this;
496        return;
497
498      default:
499        NOTREACHED();
500        break;
501    }
502  }
503
504 private:
505  // Invoked when beginning to create new tabs. Resets the tab_loader_.
506  void StartTabCreation() {
507    tab_loader_.reset(new TabLoader(restore_started_));
508  }
509
510  // Invoked when done with creating all the tabs/browsers.
511  //
512  // |created_tabbed_browser| indicates whether a tabbed browser was created,
513  // or we used an existing tabbed browser.
514  //
515  // If successful, this begins loading tabs and deletes itself when all tabs
516  // have been loaded.
517  void FinishedTabCreation(bool succeeded, bool created_tabbed_browser) {
518    if (!created_tabbed_browser && always_create_tabbed_browser_) {
519      Browser* browser = Browser::Create(profile_);
520      if (urls_to_open_.empty()) {
521        // No tab browsers were created and no URLs were supplied on the command
522        // line. Add an empty URL, which is treated as opening the users home
523        // page.
524        urls_to_open_.push_back(GURL());
525      }
526      AppendURLsToBrowser(browser, urls_to_open_);
527      browser->window()->Show();
528    }
529
530    if (succeeded) {
531      DCHECK(tab_loader_.get());
532      // TabLoader delets itself when done loading.
533      tab_loader_.release()->StartLoading();
534    }
535
536    if (!synchronous_) {
537      // If we're not synchronous we need to delete ourself.
538      // NOTE: we must use DeleteLater here as most likely we're in a callback
539      // from the history service which doesn't deal well with deleting the
540      // object it is notifying.
541      MessageLoop::current()->DeleteSoon(FROM_HERE, this);
542    }
543  }
544
545  void OnGotSession(SessionService::Handle handle,
546                    std::vector<SessionWindow*>* windows) {
547    if (synchronous_) {
548      // See comment above windows_ as to why we don't process immediately.
549      windows_.swap(*windows);
550      MessageLoop::current()->Quit();
551      return;
552    }
553
554    ProcessSessionWindows(windows);
555  }
556
557  void ProcessSessionWindows(std::vector<SessionWindow*>* windows) {
558    if (windows->empty()) {
559      // Restore was unsuccessful.
560      FinishedTabCreation(false, false);
561      return;
562    }
563
564    StartTabCreation();
565
566    Browser* current_browser =
567        browser_ ? browser_ : BrowserList::GetLastActive();
568    // After the for loop this contains the last TABBED_BROWSER. Is null if no
569    // tabbed browsers exist.
570    Browser* last_browser = NULL;
571    bool has_tabbed_browser = false;
572    for (std::vector<SessionWindow*>::iterator i = windows->begin();
573         i != windows->end(); ++i) {
574      Browser* browser = NULL;
575      if (!has_tabbed_browser && (*i)->type == Browser::TYPE_NORMAL)
576        has_tabbed_browser = true;
577      if (i == windows->begin() && (*i)->type == Browser::TYPE_NORMAL &&
578          !clobber_existing_window_) {
579        // If there is an open tabbed browser window, use it. Otherwise fall
580        // through and create a new one.
581        browser = current_browser;
582        if (browser && (browser->type() != Browser::TYPE_NORMAL ||
583                        browser->profile()->IsOffTheRecord())) {
584          browser = NULL;
585        }
586      }
587      if (!browser) {
588        browser = CreateRestoredBrowser(
589            static_cast<Browser::Type>((*i)->type),
590            (*i)->bounds,
591            (*i)->is_maximized);
592      }
593      if ((*i)->type == Browser::TYPE_NORMAL)
594        last_browser = browser;
595      const int initial_tab_count = browser->tab_count();
596      int selected_tab_index = (*i)->selected_tab_index;
597      RestoreTabsToBrowser(*(*i), browser, selected_tab_index);
598      ShowBrowser(browser, initial_tab_count, selected_tab_index);
599      tab_loader_->TabIsLoading(
600          &browser->GetSelectedTabContents()->controller());
601      NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
602    }
603
604    // If we're restoring a session as the result of a crash and the session
605    // included at least one tabbed browser, then close the browser window
606    // that was opened when the user clicked to restore the session.
607    if (clobber_existing_window_ && current_browser && has_tabbed_browser &&
608        current_browser->type() == Browser::TYPE_NORMAL) {
609      current_browser->CloseAllTabs();
610    }
611    if (last_browser && !urls_to_open_.empty())
612      AppendURLsToBrowser(last_browser, urls_to_open_);
613    // If last_browser is NULL and urls_to_open_ is non-empty,
614    // FinishedTabCreation will create a new TabbedBrowser and add the urls to
615    // it.
616    FinishedTabCreation(true, has_tabbed_browser);
617  }
618
619  void RestoreTabsToBrowser(const SessionWindow& window,
620                            Browser* browser,
621                            int selected_tab_index) {
622    DCHECK(!window.tabs.empty());
623    for (std::vector<SessionTab*>::const_iterator i = window.tabs.begin();
624         i != window.tabs.end(); ++i) {
625      const SessionTab& tab = *(*i);
626      const int tab_index = static_cast<int>(i - window.tabs.begin());
627      // Don't schedule a load for the selected tab, as ShowBrowser() will
628      // already have done that.
629      RestoreTab(tab, tab_index, browser, tab_index != selected_tab_index);
630    }
631  }
632
633  void RestoreTab(const SessionTab& tab,
634                  const int tab_index,
635                  Browser* browser,
636                  bool schedule_load) {
637    DCHECK(!tab.navigations.empty());
638    int selected_index = tab.current_navigation_index;
639    selected_index = std::max(
640        0,
641        std::min(selected_index,
642                 static_cast<int>(tab.navigations.size() - 1)));
643    TabContents* tab_contents =
644        browser->AddRestoredTab(tab.navigations,
645                                tab_index,
646                                selected_index,
647                                tab.extension_app_id,
648                                false,
649                                tab.pinned,
650                                true,
651                                NULL);
652    if (schedule_load)
653      tab_loader_->ScheduleLoad(&tab_contents->controller());
654  }
655
656  Browser* CreateRestoredBrowser(Browser::Type type,
657                                 gfx::Rect bounds,
658                                 bool is_maximized) {
659    Browser* browser = new Browser(type, profile_);
660    browser->set_override_bounds(bounds);
661    browser->set_maximized_state(is_maximized ?
662        Browser::MAXIMIZED_STATE_MAXIMIZED :
663        Browser::MAXIMIZED_STATE_UNMAXIMIZED);
664    browser->CreateBrowserWindow();
665    return browser;
666  }
667
668  void ShowBrowser(Browser* browser,
669                   int initial_tab_count,
670                   int selected_session_index) {
671    if (browser_ == browser) {
672      browser->SelectTabContentsAt(browser->tab_count() - 1, true);
673      return;
674    }
675
676    DCHECK(browser);
677    DCHECK(browser->tab_count());
678    browser->SelectTabContentsAt(
679        std::min(initial_tab_count + std::max(0, selected_session_index),
680                 browser->tab_count() - 1), true);
681    browser->window()->Show();
682    // TODO(jcampan): http://crbug.com/8123 we should not need to set the
683    //                initial focus explicitly.
684    browser->GetSelectedTabContents()->view()->SetInitialFocus();
685  }
686
687  // Appends the urls in |urls| to |browser|.
688  void AppendURLsToBrowser(Browser* browser,
689                           const std::vector<GURL>& urls) {
690    for (size_t i = 0; i < urls.size(); ++i) {
691      int add_types = TabStripModel::ADD_FORCE_INDEX;
692      if (i == 0)
693        add_types |= TabStripModel::ADD_SELECTED;
694      int index = browser->GetIndexForInsertionDuringRestore(i);
695      browser::NavigateParams params(browser, urls[i],
696                                     PageTransition::START_PAGE);
697      params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
698      params.tabstrip_index = index;
699      params.tabstrip_add_types = add_types;
700      browser::Navigate(&params);
701    }
702  }
703
704  // Invokes TabRestored on the SessionService for all tabs in browser after
705  // initial_count.
706  void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
707    SessionService* session_service = profile_->GetSessionService();
708    for (int i = initial_count; i < browser->tab_count(); ++i)
709      session_service->TabRestored(&browser->GetTabContentsAt(i)->controller(),
710                                   browser->tabstrip_model()->IsTabPinned(i));
711  }
712
713  // The profile to create the sessions for.
714  Profile* profile_;
715
716  // The first browser to restore to, may be null.
717  Browser* browser_;
718
719  // Whether or not restore is synchronous.
720  const bool synchronous_;
721
722  // See description in RestoreSession (in .h).
723  const bool clobber_existing_window_;
724
725  // If true and there is an error or there are no windows to restore, we
726  // create a tabbed browser anyway. This is used on startup to make sure at
727  // at least one window is created.
728  const bool always_create_tabbed_browser_;
729
730  // Set of URLs to open in addition to those restored from the session.
731  std::vector<GURL> urls_to_open_;
732
733  // Used to get the session.
734  CancelableRequestConsumer request_consumer_;
735
736  // Responsible for loading the tabs.
737  scoped_ptr<TabLoader> tab_loader_;
738
739  // When synchronous we run a nested message loop. To avoid creating windows
740  // from the nested message loop (which can make exiting the nested message
741  // loop take a while) we cache the SessionWindows here and create the actual
742  // windows when the nested message loop exits.
743  std::vector<SessionWindow*> windows_;
744
745  NotificationRegistrar registrar_;
746
747  // The time we started the restore.
748  base::TimeTicks restore_started_;
749};
750
751}  // namespace
752
753// SessionRestore -------------------------------------------------------------
754
755static void Restore(Profile* profile,
756                    Browser* browser,
757                    bool synchronous,
758                    bool clobber_existing_window,
759                    bool always_create_tabbed_browser,
760                    const std::vector<GURL>& urls_to_open) {
761#if defined(OS_CHROMEOS)
762  chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
763      "SessionRestoreStarted", false);
764#endif
765  DCHECK(profile);
766  // Always restore from the original profile (incognito profiles have no
767  // session service).
768  profile = profile->GetOriginalProfile();
769  if (!profile->GetSessionService()) {
770    NOTREACHED();
771    return;
772  }
773  restoring = true;
774  profile->set_restored_last_session(true);
775  // SessionRestoreImpl takes care of deleting itself when done.
776  SessionRestoreImpl* restorer =
777      new SessionRestoreImpl(profile, browser, synchronous,
778                             clobber_existing_window,
779                             always_create_tabbed_browser, urls_to_open);
780  restorer->Restore();
781}
782
783// static
784void SessionRestore::RestoreSession(Profile* profile,
785                                    Browser* browser,
786                                    bool clobber_existing_window,
787                                    bool always_create_tabbed_browser,
788                                    const std::vector<GURL>& urls_to_open) {
789  Restore(profile, browser, false, clobber_existing_window,
790          always_create_tabbed_browser, urls_to_open);
791}
792
793// static
794void SessionRestore::RestoreForeignSessionWindows(
795    Profile* profile,
796    std::vector<SessionWindow*>::const_iterator begin,
797    std::vector<SessionWindow*>::const_iterator end) {
798  // Create a SessionRestore object to eventually restore the tabs.
799  std::vector<GURL> gurls;
800  SessionRestoreImpl restorer(profile,
801      static_cast<Browser*>(NULL), true, false, true, gurls);
802  restorer.RestoreForeignSession(begin, end);
803}
804
805// static
806void SessionRestore::RestoreForeignSessionTab(Profile* profile,
807    const SessionTab& tab) {
808  // Create a SessionRestore object to eventually restore the tabs.
809  std::vector<GURL> gurls;
810  SessionRestoreImpl restorer(profile,
811      static_cast<Browser*>(NULL), true, false, true, gurls);
812  restorer.RestoreForeignTab(tab);
813}
814
815// static
816void SessionRestore::RestoreSessionSynchronously(
817    Profile* profile,
818    const std::vector<GURL>& urls_to_open) {
819  Restore(profile, NULL, true, false, true, urls_to_open);
820}
821
822// static
823bool SessionRestore::IsRestoring() {
824  return restoring;
825}
826