Home | History | Annotate | Download | only in sessions
      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 
    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 
    153 TabLoader::~TabLoader() {
    154   DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
    155           tabs_loading_.empty() && tabs_to_load_.empty());
    156 }
    157 
    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 
    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 
    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 
    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 
    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 
    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 
    349 void TabLoader::ForceLoadTimerFired() {
    350   force_load_delay_ *= 2;
    351   LoadNextTab();
    352 }
    353 
    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 
    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 
    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:
    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 
    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
    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
    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
    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
    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
    846 bool SessionRestore::IsRestoring() {
    847   return restoring;
    848 }
    849