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