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.
5 #include "chrome/browser/sessions/session_restore.h"
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"
56 #if defined(OS_CHROMEOS)
57 #include "chrome/browser/chromeos/boot_times_loader.h"
60 using content::NavigationController;
61 using content::RenderWidgetHost;
62 using content::WebContents;
66 class SessionRestoreImpl;
69 TabLoader* shared_tab_loader = NULL;
71 // Pointers to SessionRestoreImpls which are currently restoring the session.
72 std::set<SessionRestoreImpl*>* active_session_restorers = NULL;
74 // TabLoader ------------------------------------------------------------------
76 // Initial delay (see class decription for details).
77 static const int kInitialDelayTimerMS = 100;
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
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.
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> {
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);
101 // Schedules a tab for loading.
102 void ScheduleLoad(NavigationController* controller);
104 // Notifies the loader that a tab has been scheduled for loading through
105 // some other mechanism.
106 void TabIsLoading(NavigationController* controller);
108 // Invokes |LoadNextTab| to load a tab.
110 // This must be invoked once to start loading.
114 friend class base::RefCounted<TabLoader>;
116 typedef std::set<NavigationController*> TabsLoading;
117 typedef std::list<NavigationController*> TabsToLoad;
118 typedef std::set<RenderWidgetHost*> RenderWidgetHostSet;
120 explicit TabLoader(base::TimeTicks restore_started);
121 virtual ~TabLoader();
123 // Loads the next tab. If there are no more tabs to load this deletes itself,
124 // otherwise |force_load_timer_| is restarted.
127 // NotificationObserver method. Removes the specified tab and loads the next
129 virtual void Observe(int type,
130 const content::NotificationSource& source,
131 const content::NotificationDetails& details) OVERRIDE;
133 // net::NetworkChangeNotifier::ConnectionTypeObserver overrides.
134 virtual void OnConnectionTypeChanged(
135 net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
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
140 void RemoveTab(NavigationController* tab);
142 // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes
143 // |LoadNextTab| to load the next tab
144 void ForceLoadTimerFired();
146 // Returns the RenderWidgetHost associated with a tab if there is one,
148 static RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab);
150 // Register for necessary notifications on a tab navigation controller.
151 void RegisterForNotifications(NavigationController* controller);
153 // Called when a tab goes away or a load completes.
154 void HandleTabClosedOrLoaded(NavigationController* controller);
156 content::NotificationRegistrar registrar_;
158 // Current delay before a new tab is loaded. See class description for
160 int64 force_load_delay_;
162 // Has Load been invoked?
165 // Have we recorded the times for a tab paint?
166 bool got_first_paint_;
168 // The set of tabs we've initiated loading on. This does NOT include the
170 TabsLoading tabs_loading_;
172 // The tabs we need to load.
173 TabsToLoad tabs_to_load_;
175 // The renderers we have started loading into.
176 RenderWidgetHostSet render_widget_hosts_loading_;
178 // The renderers we have loaded and are waiting on to paint.
179 RenderWidgetHostSet render_widget_hosts_to_paint_;
181 // The number of tabs that have been restored.
184 base::OneShotTimer<TabLoader> force_load_timer_;
186 // The time the restore process started.
187 base::TimeTicks restore_started_;
189 // Max number of tabs that were loaded in parallel (for metrics).
190 size_t max_parallel_tab_loads_;
192 // For keeping TabLoader alive while it's loading even if no
193 // SessionRestoreImpls reference it.
194 scoped_refptr<TabLoader> this_retainer_;
196 DISALLOW_COPY_AND_ASSIGN(TabLoader);
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;
206 void TabLoader::ScheduleLoad(NavigationController* 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);
214 void TabLoader::TabIsLoading(NavigationController* 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);
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
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()) {
242 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
250 TabLoader::TabLoader(base::TimeTicks restore_started)
251 : force_load_delay_(kInitialDelayTimerMS),
253 got_first_paint_(false),
255 restore_started_(restore_started),
256 max_parallel_tab_loads_(0) {
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;
266 void TabLoader::LoadNextTab() {
267 if (!tabs_to_load_.empty()) {
268 NavigationController* tab = tabs_to_load_.front();
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();
277 Browser* browser = chrome::FindBrowserWithWebContents(contents);
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.
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();
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);
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());
311 void TabLoader::Observe(int type,
312 const content::NotificationSource& source,
313 const content::NotificationDetails& details) {
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);
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);
333 HandleTabClosedOrLoaded(&web_contents->GetController());
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);
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",
357 base::TimeDelta::FromMilliseconds(10),
358 base::TimeDelta::FromSeconds(100),
360 // Record a time for the number of tabs, to help track down
362 std::string time_for_count =
363 base::StringPrintf("SessionRestore.FirstTabPainted_%d",
365 base::HistogramBase* counter_for_count =
366 base::Histogram::FactoryTimeGet(
368 base::TimeDelta::FromMilliseconds(10),
369 base::TimeDelta::FromSeconds(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;
385 NOTREACHED() << "Unknown notification received:" << type;
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;
396 void TabLoader::OnConnectionTypeChanged(
397 net::NetworkChangeNotifier::ConnectionType type) {
398 if (type != net::NetworkChangeNotifier::CONNECTION_NONE) {
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));
416 TabsLoading::iterator i = tabs_loading_.find(tab);
417 if (i != tabs_loading_.end())
418 tabs_loading_.erase(i);
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);
426 void TabLoader::ForceLoadTimerFired() {
427 force_load_delay_ *= 2;
431 RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
432 WebContents* web_contents = tab->GetWebContents();
434 content::RenderWidgetHostView* render_widget_host_view =
435 web_contents->GetRenderWidgetHostView();
436 if (render_widget_host_view)
437 return render_widget_host_view->GetRenderWidgetHost();
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));
452 void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
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(
461 UMA_HISTOGRAM_CUSTOM_TIMES(
462 "SessionRestore.AllTabsLoaded",
464 base::TimeDelta::FromMilliseconds(10),
465 base::TimeDelta::FromSeconds(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(
473 base::TimeDelta::FromMilliseconds(10),
474 base::TimeDelta::FromSeconds(100),
476 base::Histogram::kUmaTargetedHistogramFlag);
477 counter_for_count->AddTime(time_to_load);
479 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
480 max_parallel_tab_loads_);
484 // SessionRestoreImpl ---------------------------------------------------------
486 // SessionRestoreImpl is responsible for fetching the set of tabs to create
487 // from SessionService. SessionRestoreImpl deletes itself when done.
489 class SessionRestoreImpl : public content::NotificationObserver {
491 SessionRestoreImpl(Profile* profile,
493 chrome::HostDesktopType host_desktop_type,
495 bool clobber_existing_tab,
496 bool always_create_tabbed_browser,
497 const std::vector<GURL>& urls_to_open)
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);
512 if (active_session_restorers == NULL)
513 active_session_restorers = new std::set<SessionRestoreImpl*>();
515 // Only one SessionRestoreImpl should be operating on the profile at the
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)
523 DCHECK(it == active_session_restorers->end());
525 active_session_restorers->insert(this);
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();
533 bool synchronous() const { return synchronous_; }
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_);
545 base::MessageLoop::ScopedNestableTaskAllower allow(
546 base::MessageLoop::current());
548 quit_closure_for_sync_restore_ = loop.QuitClosure();
550 quit_closure_for_sync_restore_ = base::Closure();
552 Browser* browser = ProcessSessionWindows(&windows_, active_window_id_);
554 content::NotificationService::current()->Notify(
555 chrome::NOTIFICATION_SESSION_RESTORE_DONE,
556 content::NotificationService::AllSources(),
557 content::NotificationService::NoDetails());
562 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
563 content::Source<Browser>(browser_));
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) {
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;
578 Browser* browser = CreateRestoredBrowser(
579 static_cast<Browser::Type>((*i)->type),
583 browsers.push_back(browser);
585 // Restore and show the browser.
586 const int initial_tab_count = 0;
587 int selected_tab_index = std::max(
589 std::min((*i)->selected_tab_index,
590 static_cast<int>((*i)->tabs.size()) - 1));
591 RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
593 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
596 // Always create in a new window
597 FinishedTabCreation(true, true);
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(
611 std::min(selected_index,
612 static_cast<int>(tab.navigations.size() - 1)));
614 bool use_new_window = disposition == NEW_WINDOW;
616 Browser* browser = use_new_window ?
617 new Browser(Browser::CreateParams(profile_, host_desktop_type_)) :
620 RecordAppLaunchForTab(browser, tab, selected_index);
622 WebContents* web_contents;
623 if (disposition == CURRENT_TAB) {
624 DCHECK(!use_new_window);
625 web_contents = chrome::ReplaceRestoredTab(browser,
629 tab.extension_app_id,
631 tab.user_agent_override);
634 use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
635 web_contents = chrome::AddRestoredTab(
640 tab.extension_app_id,
641 disposition == NEW_FOREGROUND_TAB, // selected
645 tab.user_agent_override);
646 // Start loading the tab immediately.
647 web_contents->GetController().LoadIfNecessary();
650 if (use_new_window) {
651 browser->tab_strip_model()->ActivateTabAt(0, true);
652 browser->window()->Show();
654 NotifySessionServiceOfRestoredTabs(browser,
655 browser->tab_strip_model()->count());
657 // Since FinishedTabCreation() is not called here, |this| will leak if we
658 // are not in sychronous mode.
659 DCHECK(synchronous_);
663 virtual ~SessionRestoreImpl() {
664 STLDeleteElements(&windows_);
666 active_session_restorers->erase(this);
667 if (active_session_restorers->empty()) {
668 delete active_session_restorers;
669 active_session_restorers = NULL;
672 g_browser_process->ReleaseModule();
675 virtual void Observe(int type,
676 const content::NotificationSource& source,
677 const content::NotificationDetails& details) OVERRIDE {
679 case chrome::NOTIFICATION_BROWSER_CLOSED:
689 Profile* profile() { return profile_; }
692 // Invoked when beginning to create new tabs. Resets the tab_loader_.
693 void StartTabCreation() {
694 tab_loader_ = TabLoader::GetTabLoader(restore_started_);
697 // Invoked when done with creating all the tabs/browsers.
699 // |created_tabbed_browser| indicates whether a tabbed browser was created,
700 // or we used an existing tabbed browser.
702 // If successful, this begins loading tabs and deletes itself when all tabs
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
715 urls_to_open_.push_back(GURL());
717 AppendURLsToBrowser(browser, urls_to_open_);
718 browser->window()->Show();
722 DCHECK(tab_loader_.get());
723 // TabLoader deletes itself when done loading.
724 tab_loader_->StartLoading();
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);
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
739 registrar_.RemoveAll();
742 #if defined(OS_CHROMEOS)
743 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
744 "SessionRestore-End", false);
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),
759 #if defined(OS_CHROMEOS)
760 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
761 "SessionRestore-GotSession", false);
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();
772 ProcessSessionWindows(&windows.get(), active_window_id);
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),
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);
795 #if defined(OS_CHROMEOS)
796 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
797 "SessionRestore-CreatingTabs-Start", false);
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;
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;
810 int selected_tab_to_activate = -1;
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;
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.
832 #if defined(OS_CHROMEOS)
833 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
834 "SessionRestore-CreateRestoredBrowser-Start", false);
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;
842 browser = CreateRestoredBrowser(
843 static_cast<Browser::Type>((*i)->type),
847 #if defined(OS_CHROMEOS)
848 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
849 "SessionRestore-CreateRestoredBrowser-End", false);
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)
864 int selected_tab_index =
865 initial_tab_count > 0 ? browser->tab_strip_model()->active_index()
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;
872 selected_tab_to_activate = selected_tab_index;
875 RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
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);
883 selected_tab_to_activate = -1;
887 if (browser_to_activate && browser_to_activate->is_type_tabbed())
888 last_browser = browser_to_activate;
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);
896 if (browser_to_activate)
897 browser_to_activate->window()->Activate();
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
902 Browser* finished_browser = FinishedTabCreation(true, has_tabbed_browser);
903 if (finished_browser)
904 last_browser = finished_browser;
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();
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);
927 CoreAppLauncherHandler::RecordAppLaunchType(
928 extension_misc::APP_LAUNCH_SESSION_RESTORE,
929 extension->GetType());
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,
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]);
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);
953 // RestoreTab can return NULL if |tab| doesn't have valid data.
957 // If this isn't the selected tab, there's nothing else to do.
958 if (is_not_selected_tab)
963 browser->tab_strip_model()->GetIndexOfWebContents(restored_tab));
964 tab_loader_->TabIsLoading(&browser->tab_strip_model()
965 ->GetActiveWebContents()
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);
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
985 WebContents* RestoreTab(const SessionTab& tab,
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())
994 int selected_index = tab.current_navigation_index;
995 selected_index = std::max(
997 std::min(selected_index,
998 static_cast<int>(tab.navigations.size() - 1)));
1000 RecordAppLaunchForTab(browser, tab, selected_index);
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);
1011 WebContents* web_contents =
1012 chrome::AddRestoredTab(browser,
1016 tab.extension_app_id,
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());
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,
1039 tab_loader_->ScheduleLoad(&web_contents->GetController());
1040 return web_contents;
1043 Browser* CreateRestoredBrowser(Browser::Type type,
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,
1054 host_desktop_type_);
1056 params.initial_bounds = bounds;
1058 params.initial_show_state = show_state;
1059 params.is_session_restore = true;
1060 return new Browser(params);
1063 void ShowBrowser(Browser* browser, int selected_tab_index) {
1065 DCHECK(browser->tab_strip_model()->count());
1066 browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true);
1068 if (browser_ == browser)
1071 browser->window()->Show();
1072 browser->set_is_session_restore(false);
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();
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",
1085 base::TimeDelta::FromMilliseconds(10),
1086 base::TimeDelta::FromSeconds(1000),
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;
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(¶ms);
1106 // Invokes TabRestored on the SessionService for all tabs in browser after
1108 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
1109 SessionService* session_service =
1110 SessionServiceFactory::GetForProfile(profile_);
1111 if (!session_service)
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));
1119 // The profile to create the sessions for.
1122 // The first browser to restore to, may be null.
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_;
1129 // Whether or not restore is synchronous.
1130 const bool synchronous_;
1132 // The quit-closure to terminate the nested message-loop started for
1133 // synchronous session-restore.
1134 base::Closure quit_closure_for_sync_restore_;
1136 // See description of CLOBBER_CURRENT_TAB.
1137 const bool clobber_existing_tab_;
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_;
1144 // Set of URLs to open in addition to those restored from the session.
1145 std::vector<GURL> urls_to_open_;
1147 // Used to get the session.
1148 base::CancelableTaskTracker cancelable_task_tracker_;
1150 // Responsible for loading the tabs.
1151 scoped_refptr<TabLoader> tab_loader_;
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_;
1160 content::NotificationRegistrar registrar_;
1162 // The time we started the restore.
1163 base::TimeTicks restore_started_;
1165 // Set to true after the first browser is shown.
1166 bool browser_shown_;
1168 DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl);
1173 // SessionRestore -------------------------------------------------------------
1176 Browser* SessionRestore::RestoreSession(
1179 chrome::HostDesktopType host_desktop_type,
1181 const std::vector<GURL>& urls_to_open) {
1182 #if defined(OS_CHROMEOS)
1183 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1184 "SessionRestore-Start", false);
1187 // Always restore from the original profile (incognito profiles have no
1188 // session service).
1189 profile = profile->GetOriginalProfile();
1190 if (!SessionServiceFactory::GetForProfile(profile)) {
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,
1201 return restorer->Restore();
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
1214 behavior = SessionRestore::CLOBBER_CURRENT_TAB;
1217 SessionRestore::RestoreSession(browser->profile(), browser,
1218 browser->host_desktop_type(), behavior,
1219 std::vector<GURL>());
1223 std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows(
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);
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);
1248 bool SessionRestore::IsRestoring(const Profile* profile) {
1249 if (active_session_restorers == NULL)
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)
1261 bool SessionRestore::IsRestoringSynchronously() {
1262 if (!active_session_restorers)
1264 for (std::set<SessionRestoreImpl*>::const_iterator it =
1265 active_session_restorers->begin();
1266 it != active_session_restorers->end(); ++it) {
1267 if ((*it)->synchronous())