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?
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->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
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        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
331void 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
349void TabLoader::ForceLoadTimerFired() {
350  force_load_delay_ *= 2;
351  LoadNextTab();
352}
353
354RenderWidgetHost* 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
365void 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
375void 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
407class SessionRestoreImpl : public NotificationObserver {
408 public:
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
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.
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.
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
488  ~SessionRestoreImpl() {
489    STLDeleteElements(&windows_);
490    restoring = false;
491  }
492
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_.
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.
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
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
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
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
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
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
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|.
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.
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
778static 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
807void 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
817void 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
829void 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
839Browser* 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
846bool SessionRestore::IsRestoring() {
847  return restoring;
848}
849