Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sessions / session_restore.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
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 <string>
11
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/memory/scoped_vector.h"
18 #include "base/metrics/histogram.h"
19 #include "base/platform_file.h"
20 #include "base/run_loop.h"
21 #include "base/stl_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/task/cancelable_task_tracker.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/performance_monitor/startup_timer.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/search/search.h"
29 #include "chrome/browser/sessions/session_service.h"
30 #include "chrome/browser/sessions/session_service_factory.h"
31 #include "chrome/browser/sessions/session_types.h"
32 #include "chrome/browser/ui/browser.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_navigator.h"
35 #include "chrome/browser/ui/browser_tabrestore.h"
36 #include "chrome/browser/ui/browser_tabstrip.h"
37 #include "chrome/browser/ui/browser_window.h"
38 #include "chrome/browser/ui/tabs/tab_strip_model.h"
39 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
40 #include "chrome/common/url_constants.h"
41 #include "content/public/browser/child_process_security_policy.h"
42 #include "content/public/browser/dom_storage_context.h"
43 #include "content/public/browser/navigation_controller.h"
44 #include "content/public/browser/notification_registrar.h"
45 #include "content/public/browser/notification_service.h"
46 #include "content/public/browser/render_process_host.h"
47 #include "content/public/browser/render_widget_host.h"
48 #include "content/public/browser/render_widget_host_view.h"
49 #include "content/public/browser/session_storage_namespace.h"
50 #include "content/public/browser/storage_partition.h"
51 #include "content/public/browser/web_contents.h"
52 #include "extensions/browser/extension_registry.h"
53 #include "extensions/common/extension_set.h"
54 #include "net/base/network_change_notifier.h"
55
56 #if defined(OS_CHROMEOS)
57 #include "chrome/browser/chromeos/boot_times_loader.h"
58 #endif
59
60 using content::NavigationController;
61 using content::RenderWidgetHost;
62 using content::WebContents;
63
64 namespace {
65
66 class SessionRestoreImpl;
67 class TabLoader;
68
69 TabLoader* shared_tab_loader = NULL;
70
71 // Pointers to SessionRestoreImpls which are currently restoring the session.
72 std::set<SessionRestoreImpl*>* active_session_restorers = NULL;
73
74 // TabLoader ------------------------------------------------------------------
75
76 // Initial delay (see class decription for details).
77 static const int kInitialDelayTimerMS = 100;
78
79 // TabLoader is responsible for loading tabs after session restore creates
80 // tabs. New tabs are loaded after the current tab finishes loading, or a delay
81 // is reached (initially kInitialDelayTimerMS). If the delay is reached before
82 // a tab finishes loading a new tab is loaded and the time of the delay
83 // doubled.
84 //
85 // TabLoader keeps a reference to itself when it's loading. When it has finished
86 // loading, it drops the reference. If another profile is restored while the
87 // TabLoader is loading, it will schedule its tabs to get loaded by the same
88 // TabLoader. When doing the scheduling, it holds a reference to the TabLoader.
89 //
90 // This is not part of SessionRestoreImpl so that synchronous destruction
91 // of SessionRestoreImpl doesn't have timing problems.
92 class TabLoader : public content::NotificationObserver,
93                   public net::NetworkChangeNotifier::ConnectionTypeObserver,
94                   public base::RefCounted<TabLoader> {
95  public:
96   // Retrieves a pointer to the TabLoader instance shared between profiles, or
97   // creates a new TabLoader if it doesn't exist. If a TabLoader is created, its
98   // starting timestamp is set to |restore_started|.
99   static TabLoader* GetTabLoader(base::TimeTicks restore_started);
100
101   // Schedules a tab for loading.
102   void ScheduleLoad(NavigationController* controller);
103
104   // Notifies the loader that a tab has been scheduled for loading through
105   // some other mechanism.
106   void TabIsLoading(NavigationController* controller);
107
108   // Invokes |LoadNextTab| to load a tab.
109   //
110   // This must be invoked once to start loading.
111   void StartLoading();
112
113  private:
114   friend class base::RefCounted<TabLoader>;
115
116   typedef std::set<NavigationController*> TabsLoading;
117   typedef std::list<NavigationController*> TabsToLoad;
118   typedef std::set<RenderWidgetHost*> RenderWidgetHostSet;
119
120   explicit TabLoader(base::TimeTicks restore_started);
121   virtual ~TabLoader();
122
123   // Loads the next tab. If there are no more tabs to load this deletes itself,
124   // otherwise |force_load_timer_| is restarted.
125   void LoadNextTab();
126
127   // NotificationObserver method. Removes the specified tab and loads the next
128   // tab.
129   virtual void Observe(int type,
130                        const content::NotificationSource& source,
131                        const content::NotificationDetails& details) OVERRIDE;
132
133   // net::NetworkChangeNotifier::ConnectionTypeObserver overrides.
134   virtual void OnConnectionTypeChanged(
135       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
136
137   // Removes the listeners from the specified tab and removes the tab from
138   // the set of tabs to load and list of tabs we're waiting to get a load
139   // from.
140   void RemoveTab(NavigationController* tab);
141
142   // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes
143   // |LoadNextTab| to load the next tab
144   void ForceLoadTimerFired();
145
146   // Returns the RenderWidgetHost associated with a tab if there is one,
147   // NULL otherwise.
148   static RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab);
149
150   // Register for necessary notifications on a tab navigation controller.
151   void RegisterForNotifications(NavigationController* controller);
152
153   // Called when a tab goes away or a load completes.
154   void HandleTabClosedOrLoaded(NavigationController* controller);
155
156   content::NotificationRegistrar registrar_;
157
158   // Current delay before a new tab is loaded. See class description for
159   // details.
160   int64 force_load_delay_;
161
162   // Has Load been invoked?
163   bool loading_;
164
165   // Have we recorded the times for a tab paint?
166   bool got_first_paint_;
167
168   // The set of tabs we've initiated loading on. This does NOT include the
169   // selected tabs.
170   TabsLoading tabs_loading_;
171
172   // The tabs we need to load.
173   TabsToLoad tabs_to_load_;
174
175   // The renderers we have started loading into.
176   RenderWidgetHostSet render_widget_hosts_loading_;
177
178   // The renderers we have loaded and are waiting on to paint.
179   RenderWidgetHostSet render_widget_hosts_to_paint_;
180
181   // The number of tabs that have been restored.
182   int tab_count_;
183
184   base::OneShotTimer<TabLoader> force_load_timer_;
185
186   // The time the restore process started.
187   base::TimeTicks restore_started_;
188
189   // Max number of tabs that were loaded in parallel (for metrics).
190   size_t max_parallel_tab_loads_;
191
192   // For keeping TabLoader alive while it's loading even if no
193   // SessionRestoreImpls reference it.
194   scoped_refptr<TabLoader> this_retainer_;
195
196   DISALLOW_COPY_AND_ASSIGN(TabLoader);
197 };
198
199 // static
200 TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) {
201   if (!shared_tab_loader)
202     shared_tab_loader = new TabLoader(restore_started);
203   return shared_tab_loader;
204 }
205
206 void TabLoader::ScheduleLoad(NavigationController* controller) {
207   DCHECK(controller);
208   DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
209          tabs_to_load_.end());
210   tabs_to_load_.push_back(controller);
211   RegisterForNotifications(controller);
212 }
213
214 void TabLoader::TabIsLoading(NavigationController* controller) {
215   DCHECK(controller);
216   DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
217          tabs_loading_.end());
218   tabs_loading_.insert(controller);
219   RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
220   DCHECK(render_widget_host);
221   render_widget_hosts_loading_.insert(render_widget_host);
222   RegisterForNotifications(controller);
223 }
224
225 void TabLoader::StartLoading() {
226   // When multiple profiles are using the same TabLoader, another profile might
227   // already have started loading. In that case, the tabs scheduled for loading
228   // by this profile are already in the loading queue, and they will get loaded
229   // eventually.
230   if (loading_)
231     return;
232   registrar_.Add(
233       this,
234       content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
235       content::NotificationService::AllSources());
236   this_retainer_ = this;
237 #if defined(OS_CHROMEOS)
238   if (!net::NetworkChangeNotifier::IsOffline()) {
239     loading_ = true;
240     LoadNextTab();
241   } else {
242     net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
243   }
244 #else
245   loading_ = true;
246   LoadNextTab();
247 #endif
248 }
249
250 TabLoader::TabLoader(base::TimeTicks restore_started)
251     : force_load_delay_(kInitialDelayTimerMS),
252       loading_(false),
253       got_first_paint_(false),
254       tab_count_(0),
255       restore_started_(restore_started),
256       max_parallel_tab_loads_(0) {
257 }
258
259 TabLoader::~TabLoader() {
260   DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
261           tabs_loading_.empty() && tabs_to_load_.empty());
262   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
263   shared_tab_loader = NULL;
264 }
265
266 void TabLoader::LoadNextTab() {
267   if (!tabs_to_load_.empty()) {
268     NavigationController* tab = tabs_to_load_.front();
269     DCHECK(tab);
270     tabs_loading_.insert(tab);
271     if (tabs_loading_.size() > max_parallel_tab_loads_)
272       max_parallel_tab_loads_ = tabs_loading_.size();
273     tabs_to_load_.pop_front();
274     tab->LoadIfNecessary();
275     content::WebContents* contents = tab->GetWebContents();
276     if (contents) {
277       Browser* browser = chrome::FindBrowserWithWebContents(contents);
278       if (browser &&
279           browser->tab_strip_model()->GetActiveWebContents() != contents) {
280         // By default tabs are marked as visible. As only the active tab is
281         // visible we need to explicitly tell non-active tabs they are hidden.
282         // Without this call non-active tabs are not marked as backgrounded.
283         //
284         // NOTE: We need to do this here rather than when the tab is added to
285         // the Browser as at that time not everything has been created, so that
286         // the call would do nothing.
287         contents->WasHidden();
288       }
289     }
290   }
291
292   if (!tabs_to_load_.empty()) {
293     force_load_timer_.Stop();
294     // Each time we load a tab we also set a timer to force us to start loading
295     // the next tab if this one doesn't load quickly enough.
296     force_load_timer_.Start(FROM_HERE,
297         base::TimeDelta::FromMilliseconds(force_load_delay_),
298         this, &TabLoader::ForceLoadTimerFired);
299   }
300
301   // When the session restore is done synchronously, notification is sent from
302   // SessionRestoreImpl::Restore .
303   if (tabs_to_load_.empty() && !SessionRestore::IsRestoringSynchronously()) {
304     content::NotificationService::current()->Notify(
305         chrome::NOTIFICATION_SESSION_RESTORE_DONE,
306         content::NotificationService::AllSources(),
307         content::NotificationService::NoDetails());
308   }
309 }
310
311 void TabLoader::Observe(int type,
312                         const content::NotificationSource& source,
313                         const content::NotificationDetails& details) {
314   switch (type) {
315     case content::NOTIFICATION_LOAD_START: {
316       // Add this render_widget_host to the set of those we're waiting for
317       // paints on. We want to only record stats for paints that occur after
318       // a load has finished.
319       NavigationController* tab =
320           content::Source<NavigationController>(source).ptr();
321       RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab);
322       DCHECK(render_widget_host);
323       render_widget_hosts_loading_.insert(render_widget_host);
324       break;
325     }
326     case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
327       WebContents* web_contents = content::Source<WebContents>(source).ptr();
328       if (!got_first_paint_) {
329         RenderWidgetHost* render_widget_host =
330             GetRenderWidgetHost(&web_contents->GetController());
331         render_widget_hosts_loading_.erase(render_widget_host);
332       }
333       HandleTabClosedOrLoaded(&web_contents->GetController());
334       break;
335     }
336     case content::NOTIFICATION_LOAD_STOP: {
337       NavigationController* tab =
338           content::Source<NavigationController>(source).ptr();
339       render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab));
340       HandleTabClosedOrLoaded(tab);
341       break;
342     }
343     case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
344       RenderWidgetHost* render_widget_host =
345           content::Source<RenderWidgetHost>(source).ptr();
346       if (!got_first_paint_ && render_widget_host->GetView() &&
347           render_widget_host->GetView()->IsShowing()) {
348         if (render_widget_hosts_to_paint_.find(render_widget_host) !=
349             render_widget_hosts_to_paint_.end()) {
350           // Got a paint for one of our renderers, so record time.
351           got_first_paint_ = true;
352           base::TimeDelta time_to_paint =
353               base::TimeTicks::Now() - restore_started_;
354           UMA_HISTOGRAM_CUSTOM_TIMES(
355               "SessionRestore.FirstTabPainted",
356               time_to_paint,
357               base::TimeDelta::FromMilliseconds(10),
358               base::TimeDelta::FromSeconds(100),
359               100);
360           // Record a time for the number of tabs, to help track down
361           // contention.
362           std::string time_for_count =
363               base::StringPrintf("SessionRestore.FirstTabPainted_%d",
364                                  tab_count_);
365           base::HistogramBase* counter_for_count =
366               base::Histogram::FactoryTimeGet(
367                   time_for_count,
368                   base::TimeDelta::FromMilliseconds(10),
369                   base::TimeDelta::FromSeconds(100),
370                   100,
371                   base::Histogram::kUmaTargetedHistogramFlag);
372           counter_for_count->AddTime(time_to_paint);
373         } else if (render_widget_hosts_loading_.find(render_widget_host) ==
374             render_widget_hosts_loading_.end()) {
375           // If this is a host for a tab we're not loading some other tab
376           // has rendered and there's no point tracking the time. This could
377           // happen because the user opened a different tab or restored tabs
378           // to an already existing browser and an existing tab painted.
379           got_first_paint_ = true;
380         }
381       }
382       break;
383     }
384     default:
385       NOTREACHED() << "Unknown notification received:" << type;
386   }
387   // Delete ourselves when we're not waiting for any more notifications. If this
388   // was not the last reference, a SessionRestoreImpl holding a reference will
389   // eventually call StartLoading (which assigns this_retainer_), or drop the
390   // reference without initiating a load.
391   if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
392       tabs_loading_.empty() && tabs_to_load_.empty())
393     this_retainer_ = NULL;
394 }
395
396 void TabLoader::OnConnectionTypeChanged(
397     net::NetworkChangeNotifier::ConnectionType type) {
398   if (type != net::NetworkChangeNotifier::CONNECTION_NONE) {
399     if (!loading_) {
400       loading_ = true;
401       LoadNextTab();
402     }
403   } else {
404     loading_ = false;
405   }
406 }
407
408 void TabLoader::RemoveTab(NavigationController* tab) {
409   registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
410                     content::Source<WebContents>(tab->GetWebContents()));
411   registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
412                     content::Source<NavigationController>(tab));
413   registrar_.Remove(this, content::NOTIFICATION_LOAD_START,
414                     content::Source<NavigationController>(tab));
415
416   TabsLoading::iterator i = tabs_loading_.find(tab);
417   if (i != tabs_loading_.end())
418     tabs_loading_.erase(i);
419
420   TabsToLoad::iterator j =
421       find(tabs_to_load_.begin(), tabs_to_load_.end(), tab);
422   if (j != tabs_to_load_.end())
423     tabs_to_load_.erase(j);
424 }
425
426 void TabLoader::ForceLoadTimerFired() {
427   force_load_delay_ *= 2;
428   LoadNextTab();
429 }
430
431 RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
432   WebContents* web_contents = tab->GetWebContents();
433   if (web_contents) {
434     content::RenderWidgetHostView* render_widget_host_view =
435         web_contents->GetRenderWidgetHostView();
436     if (render_widget_host_view)
437       return render_widget_host_view->GetRenderWidgetHost();
438   }
439   return NULL;
440 }
441
442 void TabLoader::RegisterForNotifications(NavigationController* controller) {
443   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
444                  content::Source<WebContents>(controller->GetWebContents()));
445   registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
446                  content::Source<NavigationController>(controller));
447   registrar_.Add(this, content::NOTIFICATION_LOAD_START,
448                  content::Source<NavigationController>(controller));
449   ++tab_count_;
450 }
451
452 void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
453   RemoveTab(tab);
454   if (loading_)
455     LoadNextTab();
456   if (tabs_loading_.empty() && tabs_to_load_.empty()) {
457     base::TimeDelta time_to_load =
458         base::TimeTicks::Now() - restore_started_;
459     performance_monitor::StartupTimer::SetElapsedSessionRestoreTime(
460         time_to_load);
461     UMA_HISTOGRAM_CUSTOM_TIMES(
462         "SessionRestore.AllTabsLoaded",
463         time_to_load,
464         base::TimeDelta::FromMilliseconds(10),
465         base::TimeDelta::FromSeconds(100),
466         100);
467     // Record a time for the number of tabs, to help track down contention.
468     std::string time_for_count =
469         base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_);
470     base::HistogramBase* counter_for_count =
471         base::Histogram::FactoryTimeGet(
472             time_for_count,
473             base::TimeDelta::FromMilliseconds(10),
474             base::TimeDelta::FromSeconds(100),
475             100,
476             base::Histogram::kUmaTargetedHistogramFlag);
477     counter_for_count->AddTime(time_to_load);
478
479     UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
480                              max_parallel_tab_loads_);
481   }
482 }
483
484 // SessionRestoreImpl ---------------------------------------------------------
485
486 // SessionRestoreImpl is responsible for fetching the set of tabs to create
487 // from SessionService. SessionRestoreImpl deletes itself when done.
488
489 class SessionRestoreImpl : public content::NotificationObserver {
490  public:
491   SessionRestoreImpl(Profile* profile,
492                      Browser* browser,
493                      chrome::HostDesktopType host_desktop_type,
494                      bool synchronous,
495                      bool clobber_existing_tab,
496                      bool always_create_tabbed_browser,
497                      const std::vector<GURL>& urls_to_open)
498       : profile_(profile),
499         browser_(browser),
500         host_desktop_type_(host_desktop_type),
501         synchronous_(synchronous),
502         clobber_existing_tab_(clobber_existing_tab),
503         always_create_tabbed_browser_(always_create_tabbed_browser),
504         urls_to_open_(urls_to_open),
505         active_window_id_(0),
506         restore_started_(base::TimeTicks::Now()),
507         browser_shown_(false) {
508     // For sanity's sake, if |browser| is non-null: force |host_desktop_type| to
509     // be the same as |browser|'s desktop type.
510     DCHECK(!browser || browser->host_desktop_type() == host_desktop_type);
511
512     if (active_session_restorers == NULL)
513       active_session_restorers = new std::set<SessionRestoreImpl*>();
514
515     // Only one SessionRestoreImpl should be operating on the profile at the
516     // same time.
517     std::set<SessionRestoreImpl*>::const_iterator it;
518     for (it = active_session_restorers->begin();
519          it != active_session_restorers->end(); ++it) {
520       if ((*it)->profile_ == profile)
521         break;
522     }
523     DCHECK(it == active_session_restorers->end());
524
525     active_session_restorers->insert(this);
526
527     // When asynchronous its possible for there to be no windows. To make sure
528     // Chrome doesn't prematurely exit AddRef the process. We'll release in the
529     // destructor when restore is done.
530     g_browser_process->AddRefModule();
531   }
532
533   bool synchronous() const { return synchronous_; }
534
535   Browser* Restore() {
536     SessionService* session_service =
537         SessionServiceFactory::GetForProfile(profile_);
538     DCHECK(session_service);
539     session_service->GetLastSession(
540         base::Bind(&SessionRestoreImpl::OnGotSession, base::Unretained(this)),
541         &cancelable_task_tracker_);
542
543     if (synchronous_) {
544       {
545         base::MessageLoop::ScopedNestableTaskAllower allow(
546             base::MessageLoop::current());
547         base::RunLoop loop;
548         quit_closure_for_sync_restore_ = loop.QuitClosure();
549         loop.Run();
550         quit_closure_for_sync_restore_ = base::Closure();
551       }
552       Browser* browser = ProcessSessionWindows(&windows_, active_window_id_);
553       delete this;
554       content::NotificationService::current()->Notify(
555           chrome::NOTIFICATION_SESSION_RESTORE_DONE,
556           content::NotificationService::AllSources(),
557           content::NotificationService::NoDetails());
558       return browser;
559     }
560
561     if (browser_) {
562       registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
563                      content::Source<Browser>(browser_));
564     }
565
566     return browser_;
567   }
568
569   // Restore window(s) from a foreign session. Returns newly created Browsers.
570   std::vector<Browser*> RestoreForeignSession(
571       std::vector<const SessionWindow*>::const_iterator begin,
572       std::vector<const SessionWindow*>::const_iterator end) {
573     StartTabCreation();
574     std::vector<Browser*> browsers;
575     // Create a browser instance to put the restored tabs in.
576     for (std::vector<const SessionWindow*>::const_iterator i = begin;
577          i != end; ++i) {
578       Browser* browser = CreateRestoredBrowser(
579           static_cast<Browser::Type>((*i)->type),
580           (*i)->bounds,
581           (*i)->show_state,
582           (*i)->app_name);
583       browsers.push_back(browser);
584
585       // Restore and show the browser.
586       const int initial_tab_count = 0;
587       int selected_tab_index = std::max(
588           0,
589           std::min((*i)->selected_tab_index,
590                    static_cast<int>((*i)->tabs.size()) - 1));
591       RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
592                            selected_tab_index);
593       NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
594     }
595
596     // Always create in a new window
597     FinishedTabCreation(true, true);
598     return browsers;
599   }
600
601   // Restore a single tab from a foreign session.
602   // Opens in the tab in the last active browser, unless disposition is
603   // NEW_WINDOW, in which case the tab will be opened in a new browser. Returns
604   // the WebContents of the restored tab.
605   WebContents* RestoreForeignTab(const SessionTab& tab,
606                                  WindowOpenDisposition disposition) {
607     DCHECK(!tab.navigations.empty());
608     int selected_index = tab.current_navigation_index;
609     selected_index = std::max(
610         0,
611         std::min(selected_index,
612                  static_cast<int>(tab.navigations.size() - 1)));
613
614     bool use_new_window = disposition == NEW_WINDOW;
615
616     Browser* browser = use_new_window ?
617         new Browser(Browser::CreateParams(profile_, host_desktop_type_)) :
618         browser_;
619
620     RecordAppLaunchForTab(browser, tab, selected_index);
621
622     WebContents* web_contents;
623     if (disposition == CURRENT_TAB) {
624       DCHECK(!use_new_window);
625       web_contents = chrome::ReplaceRestoredTab(browser,
626                                                 tab.navigations,
627                                                 selected_index,
628                                                 true,
629                                                 tab.extension_app_id,
630                                                 NULL,
631                                                 tab.user_agent_override);
632     } else {
633       int tab_index =
634           use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
635       web_contents = chrome::AddRestoredTab(
636           browser,
637           tab.navigations,
638           tab_index,
639           selected_index,
640           tab.extension_app_id,
641           disposition == NEW_FOREGROUND_TAB,  // selected
642           tab.pinned,
643           true,
644           NULL,
645           tab.user_agent_override);
646       // Start loading the tab immediately.
647       web_contents->GetController().LoadIfNecessary();
648     }
649
650     if (use_new_window) {
651       browser->tab_strip_model()->ActivateTabAt(0, true);
652       browser->window()->Show();
653     }
654     NotifySessionServiceOfRestoredTabs(browser,
655                                        browser->tab_strip_model()->count());
656
657     // Since FinishedTabCreation() is not called here, |this| will leak if we
658     // are not in sychronous mode.
659     DCHECK(synchronous_);
660     return web_contents;
661   }
662
663   virtual ~SessionRestoreImpl() {
664     STLDeleteElements(&windows_);
665
666     active_session_restorers->erase(this);
667     if (active_session_restorers->empty()) {
668       delete active_session_restorers;
669       active_session_restorers = NULL;
670     }
671
672     g_browser_process->ReleaseModule();
673   }
674
675   virtual void Observe(int type,
676                        const content::NotificationSource& source,
677                        const content::NotificationDetails& details) OVERRIDE {
678     switch (type) {
679       case chrome::NOTIFICATION_BROWSER_CLOSED:
680         delete this;
681         return;
682
683       default:
684         NOTREACHED();
685         break;
686     }
687   }
688
689   Profile* profile() { return profile_; }
690
691  private:
692   // Invoked when beginning to create new tabs. Resets the tab_loader_.
693   void StartTabCreation() {
694     tab_loader_ = TabLoader::GetTabLoader(restore_started_);
695   }
696
697   // Invoked when done with creating all the tabs/browsers.
698   //
699   // |created_tabbed_browser| indicates whether a tabbed browser was created,
700   // or we used an existing tabbed browser.
701   //
702   // If successful, this begins loading tabs and deletes itself when all tabs
703   // have been loaded.
704   //
705   // Returns the Browser that was created, if any.
706   Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) {
707     Browser* browser = NULL;
708     if (!created_tabbed_browser && always_create_tabbed_browser_) {
709       browser = new Browser(Browser::CreateParams(profile_,
710                                                   host_desktop_type_));
711       if (urls_to_open_.empty()) {
712         // No tab browsers were created and no URLs were supplied on the command
713         // line. Add an empty URL, which is treated as opening the users home
714         // page.
715         urls_to_open_.push_back(GURL());
716       }
717       AppendURLsToBrowser(browser, urls_to_open_);
718       browser->window()->Show();
719     }
720
721     if (succeeded) {
722       DCHECK(tab_loader_.get());
723       // TabLoader deletes itself when done loading.
724       tab_loader_->StartLoading();
725       tab_loader_ = NULL;
726     }
727
728     if (!synchronous_) {
729       // If we're not synchronous we need to delete ourself.
730       // NOTE: we must use DeleteLater here as most likely we're in a callback
731       // from the history service which doesn't deal well with deleting the
732       // object it is notifying.
733       base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
734
735       // The delete may take a while and at this point we no longer care about
736       // if the browser is deleted. Don't listen to anything. This avoid a
737       // possible double delete too (if browser is closed before DeleteSoon() is
738       // processed).
739       registrar_.RemoveAll();
740     }
741
742 #if defined(OS_CHROMEOS)
743     chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
744         "SessionRestore-End", false);
745 #endif
746     return browser;
747   }
748
749   void OnGotSession(ScopedVector<SessionWindow> windows,
750                     SessionID::id_type active_window_id) {
751     base::TimeDelta time_to_got_sessions =
752         base::TimeTicks::Now() - restore_started_;
753     UMA_HISTOGRAM_CUSTOM_TIMES(
754         "SessionRestore.TimeToGotSessions",
755         time_to_got_sessions,
756         base::TimeDelta::FromMilliseconds(10),
757         base::TimeDelta::FromSeconds(1000),
758         100);
759 #if defined(OS_CHROMEOS)
760     chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
761         "SessionRestore-GotSession", false);
762 #endif
763     if (synchronous_) {
764       // See comment above windows_ as to why we don't process immediately.
765       windows_.swap(windows.get());
766       active_window_id_ = active_window_id;
767       CHECK(!quit_closure_for_sync_restore_.is_null());
768       quit_closure_for_sync_restore_.Run();
769       return;
770     }
771
772     ProcessSessionWindows(&windows.get(), active_window_id);
773   }
774
775   Browser* ProcessSessionWindows(std::vector<SessionWindow*>* windows,
776                                  SessionID::id_type active_window_id) {
777     VLOG(1) << "ProcessSessionWindows " << windows->size();
778     base::TimeDelta time_to_process_sessions =
779         base::TimeTicks::Now() - restore_started_;
780     UMA_HISTOGRAM_CUSTOM_TIMES(
781         "SessionRestore.TimeToProcessSessions",
782         time_to_process_sessions,
783         base::TimeDelta::FromMilliseconds(10),
784         base::TimeDelta::FromSeconds(1000),
785         100);
786
787     if (windows->empty()) {
788       // Restore was unsuccessful. The DOM storage system can also delete its
789       // data, since no session restore will happen at a later point in time.
790       content::BrowserContext::GetDefaultStoragePartition(profile_)->
791           GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
792       return FinishedTabCreation(false, false);
793     }
794
795 #if defined(OS_CHROMEOS)
796     chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
797         "SessionRestore-CreatingTabs-Start", false);
798 #endif
799     StartTabCreation();
800
801     // After the for loop this contains the last TABBED_BROWSER. Is null if no
802     // tabbed browsers exist.
803     Browser* last_browser = NULL;
804     bool has_tabbed_browser = false;
805
806     // After the for loop, this contains the browser to activate, if one of the
807     // windows has the same id as specified in active_window_id.
808     Browser* browser_to_activate = NULL;
809 #if defined(OS_WIN)
810     int selected_tab_to_activate = -1;
811 #endif
812
813     // Determine if there is a visible window.
814     bool has_visible_browser = false;
815     for (std::vector<SessionWindow*>::iterator i = windows->begin();
816          i != windows->end(); ++i) {
817       if ((*i)->show_state != ui::SHOW_STATE_MINIMIZED)
818         has_visible_browser = true;
819     }
820
821     for (std::vector<SessionWindow*>::iterator i = windows->begin();
822          i != windows->end(); ++i) {
823       Browser* browser = NULL;
824       if (!has_tabbed_browser && (*i)->type == Browser::TYPE_TABBED)
825         has_tabbed_browser = true;
826       if (i == windows->begin() && (*i)->type == Browser::TYPE_TABBED &&
827           browser_ && browser_->is_type_tabbed() &&
828           !browser_->profile()->IsOffTheRecord()) {
829         // The first set of tabs is added to the existing browser.
830         browser = browser_;
831       } else {
832 #if defined(OS_CHROMEOS)
833         chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
834             "SessionRestore-CreateRestoredBrowser-Start", false);
835 #endif
836         // Show the first window if none are visible.
837         ui::WindowShowState show_state = (*i)->show_state;
838         if (!has_visible_browser) {
839           show_state = ui::SHOW_STATE_NORMAL;
840           has_visible_browser = true;
841         }
842         browser = CreateRestoredBrowser(
843             static_cast<Browser::Type>((*i)->type),
844             (*i)->bounds,
845             show_state,
846             (*i)->app_name);
847 #if defined(OS_CHROMEOS)
848         chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
849             "SessionRestore-CreateRestoredBrowser-End", false);
850 #endif
851       }
852       if ((*i)->type == Browser::TYPE_TABBED)
853         last_browser = browser;
854       WebContents* active_tab =
855           browser->tab_strip_model()->GetActiveWebContents();
856       int initial_tab_count = browser->tab_strip_model()->count();
857       bool close_active_tab = clobber_existing_tab_ &&
858                               i == windows->begin() &&
859                               (*i)->type == Browser::TYPE_TABBED &&
860                               active_tab && browser == browser_ &&
861                               (*i)->tabs.size() > 0;
862       if (close_active_tab)
863         --initial_tab_count;
864       int selected_tab_index =
865           initial_tab_count > 0 ? browser->tab_strip_model()->active_index()
866                                 : std::max(0,
867                                     std::min((*i)->selected_tab_index,
868                                     static_cast<int>((*i)->tabs.size()) - 1));
869       if ((*i)->window_id.id() == active_window_id) {
870         browser_to_activate = browser;
871 #if defined(OS_WIN)
872         selected_tab_to_activate = selected_tab_index;
873 #endif
874       }
875       RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
876                            selected_tab_index);
877       NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
878       // This needs to be done after restore because closing the last tab will
879       // close the whole window.
880       if (close_active_tab)
881         chrome::CloseWebContents(browser, active_tab, true);
882 #if defined(OS_WIN)
883         selected_tab_to_activate = -1;
884 #endif
885     }
886
887     if (browser_to_activate && browser_to_activate->is_type_tabbed())
888       last_browser = browser_to_activate;
889
890     if (last_browser && !urls_to_open_.empty())
891       AppendURLsToBrowser(last_browser, urls_to_open_);
892 #if defined(OS_CHROMEOS)
893     chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
894         "SessionRestore-CreatingTabs-End", false);
895 #endif
896     if (browser_to_activate)
897       browser_to_activate->window()->Activate();
898
899     // If last_browser is NULL and urls_to_open_ is non-empty,
900     // FinishedTabCreation will create a new TabbedBrowser and add the urls to
901     // it.
902     Browser* finished_browser = FinishedTabCreation(true, has_tabbed_browser);
903     if (finished_browser)
904       last_browser = finished_browser;
905
906     // sessionStorages needed for the session restore have now been recreated
907     // by RestoreTab. Now it's safe for the DOM storage system to start
908     // deleting leftover data.
909     content::BrowserContext::GetDefaultStoragePartition(profile_)->
910         GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
911     return last_browser;
912   }
913
914   // Record an app launch event (if appropriate) for a tab which is about to
915   // be restored. Callers should ensure that selected_index is within the
916   // bounds of tab.navigations before calling.
917   void RecordAppLaunchForTab(Browser* browser,
918                              const SessionTab& tab,
919                              int selected_index) {
920     DCHECK(selected_index >= 0 &&
921            selected_index < static_cast<int>(tab.navigations.size()));
922     GURL url = tab.navigations[selected_index].virtual_url();
923     const extensions::Extension* extension =
924         extensions::ExtensionRegistry::Get(profile())
925             ->enabled_extensions().GetAppByURL(url);
926     if (extension) {
927       CoreAppLauncherHandler::RecordAppLaunchType(
928           extension_misc::APP_LAUNCH_SESSION_RESTORE,
929           extension->GetType());
930     }
931   }
932
933   // Adds the tabs from |window| to |browser|. Normal tabs go after the existing
934   // tabs but pinned tabs will be pushed in front.
935   // If there are no existing tabs, the tab at |selected_tab_index| will be
936   // selected. Otherwise, the tab selection will remain untouched.
937   void RestoreTabsToBrowser(const SessionWindow& window,
938                            Browser* browser,
939                            int initial_tab_count,
940                            int selected_tab_index) {
941     VLOG(1) << "RestoreTabsToBrowser " << window.tabs.size();
942     DCHECK(!window.tabs.empty());
943     if (initial_tab_count == 0) {
944       for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
945         const SessionTab& tab = *(window.tabs[i]);
946
947         // Loads are scheduled for each restored tab unless the tab is going to
948         // be selected as ShowBrowser() will load the selected tab.
949         bool is_not_selected_tab = (i != selected_tab_index);
950         WebContents* restored_tab =
951             RestoreTab(tab, i, browser, is_not_selected_tab);
952
953         // RestoreTab can return NULL if |tab| doesn't have valid data.
954         if (!restored_tab)
955           continue;
956
957         // If this isn't the selected tab, there's nothing else to do.
958         if (is_not_selected_tab)
959           continue;
960
961         ShowBrowser(
962             browser,
963             browser->tab_strip_model()->GetIndexOfWebContents(restored_tab));
964         tab_loader_->TabIsLoading(&browser->tab_strip_model()
965                                        ->GetActiveWebContents()
966                                        ->GetController());
967       }
968     } else {
969       // If the browser already has tabs, we want to restore the new ones after
970       // the existing ones. E.g. this happens in Win8 Metro where we merge
971       // windows or when launching a hosted app from the app launcher.
972       int tab_index_offset = initial_tab_count;
973       for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
974         const SessionTab& tab = *(window.tabs[i]);
975         // Always schedule loads as we will not be calling ShowBrowser().
976         RestoreTab(tab, tab_index_offset + i, browser, true);
977       }
978     }
979   }
980
981   // |tab_index| is ignored for pinned tabs which will always be pushed behind
982   // the last existing pinned tab.
983   // |schedule_load| will let |tab_loader_| know that it should schedule this
984   // tab for loading.
985   WebContents* RestoreTab(const SessionTab& tab,
986                           const int tab_index,
987                           Browser* browser,
988                           bool schedule_load) {
989     // It's possible (particularly for foreign sessions) to receive a tab
990     // without valid navigations. In that case, just skip it.
991     // See crbug.com/154129.
992     if (tab.navigations.empty())
993       return NULL;
994     int selected_index = tab.current_navigation_index;
995     selected_index = std::max(
996         0,
997         std::min(selected_index,
998                  static_cast<int>(tab.navigations.size() - 1)));
999
1000     RecordAppLaunchForTab(browser, tab, selected_index);
1001
1002     // Associate sessionStorage (if any) to the restored tab.
1003     scoped_refptr<content::SessionStorageNamespace> session_storage_namespace;
1004     if (!tab.session_storage_persistent_id.empty()) {
1005       session_storage_namespace =
1006           content::BrowserContext::GetDefaultStoragePartition(profile_)->
1007               GetDOMStorageContext()->RecreateSessionStorage(
1008                   tab.session_storage_persistent_id);
1009     }
1010
1011     WebContents* web_contents =
1012         chrome::AddRestoredTab(browser,
1013                                tab.navigations,
1014                                tab_index,
1015                                selected_index,
1016                                tab.extension_app_id,
1017                                false,  // select
1018                                tab.pinned,
1019                                true,
1020                                session_storage_namespace.get(),
1021                                tab.user_agent_override);
1022     // Regression check: check that the tab didn't start loading right away. The
1023     // focused tab will be loaded by Browser, and TabLoader will load the rest.
1024     DCHECK(web_contents->GetController().NeedsReload());
1025
1026     // Set up the file access rights for the selected navigation entry.
1027     const int id = web_contents->GetRenderProcessHost()->GetID();
1028     const content::PageState& page_state =
1029         tab.navigations.at(selected_index).page_state();
1030     const std::vector<base::FilePath>& file_paths =
1031         page_state.GetReferencedFiles();
1032     for (std::vector<base::FilePath>::const_iterator file = file_paths.begin();
1033          file != file_paths.end(); ++file) {
1034       content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id,
1035                                                                         *file);
1036     }
1037
1038     if (schedule_load)
1039       tab_loader_->ScheduleLoad(&web_contents->GetController());
1040     return web_contents;
1041   }
1042
1043   Browser* CreateRestoredBrowser(Browser::Type type,
1044                                  gfx::Rect bounds,
1045                                  ui::WindowShowState show_state,
1046                                  const std::string& app_name) {
1047     Browser::CreateParams params(type, profile_, host_desktop_type_);
1048     if (!app_name.empty()) {
1049       const bool trusted_source = true;  // We only store trusted app windows.
1050       params = Browser::CreateParams::CreateForApp(app_name,
1051                                                    trusted_source,
1052                                                    bounds,
1053                                                    profile_,
1054                                                    host_desktop_type_);
1055     } else {
1056       params.initial_bounds = bounds;
1057     }
1058     params.initial_show_state = show_state;
1059     params.is_session_restore = true;
1060     return new Browser(params);
1061   }
1062
1063   void ShowBrowser(Browser* browser, int selected_tab_index) {
1064     DCHECK(browser);
1065     DCHECK(browser->tab_strip_model()->count());
1066     browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true);
1067
1068     if (browser_ == browser)
1069       return;
1070
1071     browser->window()->Show();
1072     browser->set_is_session_restore(false);
1073
1074     // TODO(jcampan): http://crbug.com/8123 we should not need to set the
1075     //                initial focus explicitly.
1076     browser->tab_strip_model()->GetActiveWebContents()->SetInitialFocus();
1077
1078     if (!browser_shown_) {
1079       browser_shown_ = true;
1080       base::TimeDelta time_to_first_show =
1081           base::TimeTicks::Now() - restore_started_;
1082       UMA_HISTOGRAM_CUSTOM_TIMES(
1083           "SessionRestore.TimeToFirstShow",
1084           time_to_first_show,
1085           base::TimeDelta::FromMilliseconds(10),
1086           base::TimeDelta::FromSeconds(1000),
1087           100);
1088     }
1089   }
1090
1091   // Appends the urls in |urls| to |browser|.
1092   void AppendURLsToBrowser(Browser* browser,
1093                            const std::vector<GURL>& urls) {
1094     for (size_t i = 0; i < urls.size(); ++i) {
1095       int add_types = TabStripModel::ADD_FORCE_INDEX;
1096       if (i == 0)
1097         add_types |= TabStripModel::ADD_ACTIVE;
1098       chrome::NavigateParams params(browser, urls[i],
1099                                     content::PAGE_TRANSITION_AUTO_TOPLEVEL);
1100       params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
1101       params.tabstrip_add_types = add_types;
1102       chrome::Navigate(&params);
1103     }
1104   }
1105
1106   // Invokes TabRestored on the SessionService for all tabs in browser after
1107   // initial_count.
1108   void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
1109     SessionService* session_service =
1110         SessionServiceFactory::GetForProfile(profile_);
1111     if (!session_service)
1112       return;
1113     TabStripModel* tab_strip = browser->tab_strip_model();
1114     for (int i = initial_count; i < tab_strip->count(); ++i)
1115       session_service->TabRestored(tab_strip->GetWebContentsAt(i),
1116                                    tab_strip->IsTabPinned(i));
1117   }
1118
1119   // The profile to create the sessions for.
1120   Profile* profile_;
1121
1122   // The first browser to restore to, may be null.
1123   Browser* browser_;
1124
1125   // The desktop on which all new browsers should be created (browser_, if it is
1126   // not NULL, must be of this desktop type as well).
1127   chrome::HostDesktopType host_desktop_type_;
1128
1129   // Whether or not restore is synchronous.
1130   const bool synchronous_;
1131
1132   // The quit-closure to terminate the nested message-loop started for
1133   // synchronous session-restore.
1134   base::Closure quit_closure_for_sync_restore_;
1135
1136   // See description of CLOBBER_CURRENT_TAB.
1137   const bool clobber_existing_tab_;
1138
1139   // If true and there is an error or there are no windows to restore, we
1140   // create a tabbed browser anyway. This is used on startup to make sure at
1141   // at least one window is created.
1142   const bool always_create_tabbed_browser_;
1143
1144   // Set of URLs to open in addition to those restored from the session.
1145   std::vector<GURL> urls_to_open_;
1146
1147   // Used to get the session.
1148   base::CancelableTaskTracker cancelable_task_tracker_;
1149
1150   // Responsible for loading the tabs.
1151   scoped_refptr<TabLoader> tab_loader_;
1152
1153   // When synchronous we run a nested message loop. To avoid creating windows
1154   // from the nested message loop (which can make exiting the nested message
1155   // loop take a while) we cache the SessionWindows here and create the actual
1156   // windows when the nested message loop exits.
1157   std::vector<SessionWindow*> windows_;
1158   SessionID::id_type active_window_id_;
1159
1160   content::NotificationRegistrar registrar_;
1161
1162   // The time we started the restore.
1163   base::TimeTicks restore_started_;
1164
1165   // Set to true after the first browser is shown.
1166   bool browser_shown_;
1167
1168   DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl);
1169 };
1170
1171 }  // namespace
1172
1173 // SessionRestore -------------------------------------------------------------
1174
1175 // static
1176 Browser* SessionRestore::RestoreSession(
1177     Profile* profile,
1178     Browser* browser,
1179     chrome::HostDesktopType host_desktop_type,
1180     uint32 behavior,
1181     const std::vector<GURL>& urls_to_open) {
1182 #if defined(OS_CHROMEOS)
1183   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1184       "SessionRestore-Start", false);
1185 #endif
1186   DCHECK(profile);
1187   // Always restore from the original profile (incognito profiles have no
1188   // session service).
1189   profile = profile->GetOriginalProfile();
1190   if (!SessionServiceFactory::GetForProfile(profile)) {
1191     NOTREACHED();
1192     return NULL;
1193   }
1194   profile->set_restored_last_session(true);
1195   // SessionRestoreImpl takes care of deleting itself when done.
1196   SessionRestoreImpl* restorer = new SessionRestoreImpl(
1197       profile, browser, host_desktop_type, (behavior & SYNCHRONOUS) != 0,
1198       (behavior & CLOBBER_CURRENT_TAB) != 0,
1199       (behavior & ALWAYS_CREATE_TABBED_BROWSER) != 0,
1200       urls_to_open);
1201   return restorer->Restore();
1202 }
1203
1204 // static
1205 void SessionRestore::RestoreSessionAfterCrash(Browser* browser) {
1206    uint32 behavior = 0;
1207   if (browser->tab_strip_model()->count() == 1) {
1208     const content::WebContents* active_tab =
1209         browser->tab_strip_model()->GetWebContentsAt(0);
1210     if (active_tab->GetURL() == GURL(chrome::kChromeUINewTabURL) ||
1211         chrome::IsInstantNTP(active_tab)) {
1212       // There is only one tab and its the new tab page, make session restore
1213       // clobber it.
1214       behavior = SessionRestore::CLOBBER_CURRENT_TAB;
1215     }
1216   }
1217   SessionRestore::RestoreSession(browser->profile(), browser,
1218                                  browser->host_desktop_type(), behavior,
1219                                  std::vector<GURL>());
1220 }
1221
1222 // static
1223 std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows(
1224     Profile* profile,
1225     chrome::HostDesktopType host_desktop_type,
1226     std::vector<const SessionWindow*>::const_iterator begin,
1227     std::vector<const SessionWindow*>::const_iterator end) {
1228   std::vector<GURL> gurls;
1229   SessionRestoreImpl restorer(profile,
1230       static_cast<Browser*>(NULL), host_desktop_type, true, false, true, gurls);
1231   return restorer.RestoreForeignSession(begin, end);
1232 }
1233
1234 // static
1235 WebContents* SessionRestore::RestoreForeignSessionTab(
1236     content::WebContents* source_web_contents,
1237     const SessionTab& tab,
1238     WindowOpenDisposition disposition) {
1239   Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents);
1240   Profile* profile = browser->profile();
1241   std::vector<GURL> gurls;
1242   SessionRestoreImpl restorer(profile, browser, browser->host_desktop_type(),
1243                               true, false, false, gurls);
1244   return restorer.RestoreForeignTab(tab, disposition);
1245 }
1246
1247 // static
1248 bool SessionRestore::IsRestoring(const Profile* profile) {
1249   if (active_session_restorers == NULL)
1250     return false;
1251   for (std::set<SessionRestoreImpl*>::const_iterator it =
1252            active_session_restorers->begin();
1253        it != active_session_restorers->end(); ++it) {
1254     if ((*it)->profile() == profile)
1255       return true;
1256   }
1257   return false;
1258 }
1259
1260 // static
1261 bool SessionRestore::IsRestoringSynchronously() {
1262   if (!active_session_restorers)
1263     return false;
1264   for (std::set<SessionRestoreImpl*>::const_iterator it =
1265            active_session_restorers->begin();
1266        it != active_session_restorers->end(); ++it) {
1267     if ((*it)->synchronous())
1268       return true;
1269   }
1270   return false;
1271 }