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/stl_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/extensions/extension_service.h"
25 #include "chrome/browser/performance_monitor/startup_timer.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/sessions/session_service.h"
28 #include "chrome/browser/sessions/session_service_factory.h"
29 #include "chrome/browser/sessions/session_types.h"
30 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_finder.h"
32 #include "chrome/browser/ui/browser_navigator.h"
33 #include "chrome/browser/ui/browser_tabrestore.h"
34 #include "chrome/browser/ui/browser_tabstrip.h"
35 #include "chrome/browser/ui/browser_window.h"
36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
37 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
38 #include "chrome/common/cancelable_task_tracker.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"
53 #if defined(OS_CHROMEOS)
54 #include "chrome/browser/chromeos/boot_times_loader.h"
58 #include "win8/util/win8_util.h"
61 using content::NavigationController
;
62 using content::RenderWidgetHost
;
63 using content::WebContents
;
67 class SessionRestoreImpl
;
70 TabLoader
* shared_tab_loader
= NULL
;
72 // Pointers to SessionRestoreImpls which are currently restoring the session.
73 std::set
<SessionRestoreImpl
*>* active_session_restorers
= NULL
;
75 // TabLoader ------------------------------------------------------------------
77 // Initial delay (see class decription for details).
78 static const int kInitialDelayTimerMS
= 100;
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
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.
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
> {
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
);
102 // Schedules a tab for loading.
103 void ScheduleLoad(NavigationController
* controller
);
105 // Notifies the loader that a tab has been scheduled for loading through
106 // some other mechanism.
107 void TabIsLoading(NavigationController
* controller
);
109 // Invokes |LoadNextTab| to load a tab.
111 // This must be invoked once to start loading.
115 friend class base::RefCounted
<TabLoader
>;
117 typedef std::set
<NavigationController
*> TabsLoading
;
118 typedef std::list
<NavigationController
*> TabsToLoad
;
119 typedef std::set
<RenderWidgetHost
*> RenderWidgetHostSet
;
121 explicit TabLoader(base::TimeTicks restore_started
);
122 virtual ~TabLoader();
124 // Loads the next tab. If there are no more tabs to load this deletes itself,
125 // otherwise |force_load_timer_| is restarted.
128 // NotificationObserver method. Removes the specified tab and loads the next
130 virtual void Observe(int type
,
131 const content::NotificationSource
& source
,
132 const content::NotificationDetails
& details
) OVERRIDE
;
134 // net::NetworkChangeNotifier::ConnectionTypeObserver overrides.
135 virtual void OnConnectionTypeChanged(
136 net::NetworkChangeNotifier::ConnectionType type
) OVERRIDE
;
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
141 void RemoveTab(NavigationController
* tab
);
143 // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes
144 // |LoadNextTab| to load the next tab
145 void ForceLoadTimerFired();
147 // Returns the RenderWidgetHost associated with a tab if there is one,
149 static RenderWidgetHost
* GetRenderWidgetHost(NavigationController
* tab
);
151 // Register for necessary notifications on a tab navigation controller.
152 void RegisterForNotifications(NavigationController
* controller
);
154 // Called when a tab goes away or a load completes.
155 void HandleTabClosedOrLoaded(NavigationController
* controller
);
157 content::NotificationRegistrar registrar_
;
159 // Current delay before a new tab is loaded. See class description for
161 int64 force_load_delay_
;
163 // Has Load been invoked?
166 // Have we recorded the times for a tab paint?
167 bool got_first_paint_
;
169 // The set of tabs we've initiated loading on. This does NOT include the
171 TabsLoading tabs_loading_
;
173 // The tabs we need to load.
174 TabsToLoad tabs_to_load_
;
176 // The renderers we have started loading into.
177 RenderWidgetHostSet render_widget_hosts_loading_
;
179 // The renderers we have loaded and are waiting on to paint.
180 RenderWidgetHostSet render_widget_hosts_to_paint_
;
182 // The number of tabs that have been restored.
185 base::OneShotTimer
<TabLoader
> force_load_timer_
;
187 // The time the restore process started.
188 base::TimeTicks restore_started_
;
190 // Max number of tabs that were loaded in parallel (for metrics).
191 size_t max_parallel_tab_loads_
;
193 // For keeping TabLoader alive while it's loading even if no
194 // SessionRestoreImpls reference it.
195 scoped_refptr
<TabLoader
> this_retainer_
;
197 DISALLOW_COPY_AND_ASSIGN(TabLoader
);
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
;
207 void TabLoader::ScheduleLoad(NavigationController
* 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
);
215 void TabLoader::TabIsLoading(NavigationController
* 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
);
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
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()) {
243 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
251 TabLoader::TabLoader(base::TimeTicks restore_started
)
252 : force_load_delay_(kInitialDelayTimerMS
),
254 got_first_paint_(false),
256 restore_started_(restore_started
),
257 max_parallel_tab_loads_(0) {
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
;
267 void TabLoader::LoadNextTab() {
268 if (!tabs_to_load_
.empty()) {
269 NavigationController
* tab
= tabs_to_load_
.front();
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();
278 Browser
* browser
= chrome::FindBrowserWithWebContents(contents
);
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.
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();
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
);
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());
312 void TabLoader::Observe(int type
,
313 const content::NotificationSource
& source
,
314 const content::NotificationDetails
& details
) {
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
);
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
);
334 HandleTabClosedOrLoaded(&web_contents
->GetController());
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
);
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",
358 base::TimeDelta::FromMilliseconds(10),
359 base::TimeDelta::FromSeconds(100),
361 // Record a time for the number of tabs, to help track down
363 std::string time_for_count
=
364 base::StringPrintf("SessionRestore.FirstTabPainted_%d",
366 base::HistogramBase
* counter_for_count
=
367 base::Histogram::FactoryTimeGet(
369 base::TimeDelta::FromMilliseconds(10),
370 base::TimeDelta::FromSeconds(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;
386 NOTREACHED() << "Unknown notification received:" << type
;
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
;
397 void TabLoader::OnConnectionTypeChanged(
398 net::NetworkChangeNotifier::ConnectionType type
) {
399 if (type
!= net::NetworkChangeNotifier::CONNECTION_NONE
) {
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
));
417 TabsLoading::iterator i
= tabs_loading_
.find(tab
);
418 if (i
!= tabs_loading_
.end())
419 tabs_loading_
.erase(i
);
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
);
427 void TabLoader::ForceLoadTimerFired() {
428 force_load_delay_
*= 2;
432 RenderWidgetHost
* TabLoader::GetRenderWidgetHost(NavigationController
* tab
) {
433 WebContents
* web_contents
= tab
->GetWebContents();
435 content::RenderWidgetHostView
* render_widget_host_view
=
436 web_contents
->GetRenderWidgetHostView();
437 if (render_widget_host_view
)
438 return render_widget_host_view
->GetRenderWidgetHost();
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
));
453 void TabLoader::HandleTabClosedOrLoaded(NavigationController
* tab
) {
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(
462 UMA_HISTOGRAM_CUSTOM_TIMES(
463 "SessionRestore.AllTabsLoaded",
465 base::TimeDelta::FromMilliseconds(10),
466 base::TimeDelta::FromSeconds(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(
474 base::TimeDelta::FromMilliseconds(10),
475 base::TimeDelta::FromSeconds(100),
477 base::Histogram::kUmaTargetedHistogramFlag
);
478 counter_for_count
->AddTime(time_to_load
);
480 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
481 max_parallel_tab_loads_
);
485 // SessionRestoreImpl ---------------------------------------------------------
487 // SessionRestoreImpl is responsible for fetching the set of tabs to create
488 // from SessionService. SessionRestoreImpl deletes itself when done.
490 class SessionRestoreImpl
: public content::NotificationObserver
{
492 SessionRestoreImpl(Profile
* profile
,
494 chrome::HostDesktopType host_desktop_type
,
496 bool clobber_existing_tab
,
497 bool always_create_tabbed_browser
,
498 const std::vector
<GURL
>& urls_to_open
)
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
);
513 if (active_session_restorers
== NULL
)
514 active_session_restorers
= new std::set
<SessionRestoreImpl
*>();
516 // Only one SessionRestoreImpl should be operating on the profile at the
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
)
524 DCHECK(it
== active_session_restorers
->end());
526 active_session_restorers
->insert(this);
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();
534 bool synchronous() const { return synchronous_
; }
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_
);
546 base::MessageLoop::ScopedNestableTaskAllower
allow(
547 base::MessageLoop::current());
548 base::MessageLoop::current()->Run();
550 Browser
* browser
= ProcessSessionWindows(&windows_
, active_window_id_
);
552 content::NotificationService::current()->Notify(
553 chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
554 content::NotificationService::AllSources(),
555 content::NotificationService::NoDetails());
560 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED
,
561 content::Source
<Browser
>(browser_
));
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
) {
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
;
576 Browser
* browser
= CreateRestoredBrowser(
577 static_cast<Browser::Type
>((*i
)->type
),
581 browsers
.push_back(browser
);
583 // Restore and show the browser.
584 const int initial_tab_count
= 0;
585 int selected_tab_index
= std::max(
587 std::min((*i
)->selected_tab_index
,
588 static_cast<int>((*i
)->tabs
.size()) - 1));
589 RestoreTabsToBrowser(*(*i
), browser
, initial_tab_count
,
591 NotifySessionServiceOfRestoredTabs(browser
, initial_tab_count
);
594 // Always create in a new window
595 FinishedTabCreation(true, true);
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(
609 std::min(selected_index
,
610 static_cast<int>(tab
.navigations
.size() - 1)));
612 bool use_new_window
= disposition
== NEW_WINDOW
;
614 Browser
* browser
= use_new_window
?
615 new Browser(Browser::CreateParams(profile_
, host_desktop_type_
)) :
618 RecordAppLaunchForTab(browser
, tab
, selected_index
);
620 WebContents
* web_contents
;
621 if (disposition
== CURRENT_TAB
) {
622 DCHECK(!use_new_window
);
623 web_contents
= chrome::ReplaceRestoredTab(browser
,
627 tab
.extension_app_id
,
629 tab
.user_agent_override
);
632 use_new_window
? 0 : browser
->tab_strip_model()->active_index() + 1;
633 web_contents
= chrome::AddRestoredTab(
638 tab
.extension_app_id
,
639 disposition
== NEW_FOREGROUND_TAB
, // selected
643 tab
.user_agent_override
);
644 // Start loading the tab immediately.
645 web_contents
->GetController().LoadIfNecessary();
648 if (use_new_window
) {
649 browser
->tab_strip_model()->ActivateTabAt(0, true);
650 browser
->window()->Show();
652 NotifySessionServiceOfRestoredTabs(browser
,
653 browser
->tab_strip_model()->count());
655 // Since FinishedTabCreation() is not called here, |this| will leak if we
656 // are not in sychronous mode.
657 DCHECK(synchronous_
);
661 virtual ~SessionRestoreImpl() {
662 STLDeleteElements(&windows_
);
664 active_session_restorers
->erase(this);
665 if (active_session_restorers
->empty()) {
666 delete active_session_restorers
;
667 active_session_restorers
= NULL
;
670 g_browser_process
->ReleaseModule();
673 virtual void Observe(int type
,
674 const content::NotificationSource
& source
,
675 const content::NotificationDetails
& details
) OVERRIDE
{
677 case chrome::NOTIFICATION_BROWSER_CLOSED
:
687 Profile
* profile() { return profile_
; }
690 // Invoked when beginning to create new tabs. Resets the tab_loader_.
691 void StartTabCreation() {
692 tab_loader_
= TabLoader::GetTabLoader(restore_started_
);
695 // Invoked when done with creating all the tabs/browsers.
697 // |created_tabbed_browser| indicates whether a tabbed browser was created,
698 // or we used an existing tabbed browser.
700 // If successful, this begins loading tabs and deletes itself when all tabs
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
713 urls_to_open_
.push_back(GURL());
715 AppendURLsToBrowser(browser
, urls_to_open_
);
716 browser
->window()->Show();
720 DCHECK(tab_loader_
.get());
721 // TabLoader deletes itself when done loading.
722 tab_loader_
->StartLoading();
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);
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
737 registrar_
.RemoveAll();
740 #if defined(OS_CHROMEOS)
741 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
742 "SessionRestore-End", false);
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),
757 #if defined(OS_CHROMEOS)
758 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
759 "SessionRestore-GotSession", false);
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();
769 ProcessSessionWindows(&windows
.get(), active_window_id
);
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),
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);
792 #if defined(OS_CHROMEOS)
793 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
794 "SessionRestore-CreatingTabs-Start", false);
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;
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
;
807 int selected_tab_to_activate
= -1;
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;
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.
829 #if defined(OS_CHROMEOS)
830 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
831 "SessionRestore-CreateRestoredBrowser-Start", false);
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;
841 if (win8::IsSingleWindowMetroMode()) {
842 // We don't want to add tabs to the off the record browser.
843 if (browser_
&& !browser_
->profile()->IsOffTheRecord()) {
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());
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
);
860 browser
= CreateRestoredBrowser(
861 static_cast<Browser::Type
>((*i
)->type
),
866 #if defined(OS_CHROMEOS)
867 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
868 "SessionRestore-CreateRestoredBrowser-End", false);
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
)
883 int selected_tab_index
=
884 initial_tab_count
> 0 ? browser
->tab_strip_model()->active_index()
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
;
891 selected_tab_to_activate
= selected_tab_index
;
894 RestoreTabsToBrowser(*(*i
), browser
, initial_tab_count
,
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);
902 selected_tab_to_activate
= -1;
906 if (browser_to_activate
&& browser_to_activate
->is_type_tabbed())
907 last_browser
= browser_to_activate
;
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);
915 if (browser_to_activate
) {
916 browser_to_activate
->window()->Activate();
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
);
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
932 Browser
* finished_browser
= FinishedTabCreation(true, has_tabbed_browser
);
933 if (finished_browser
)
934 last_browser
= finished_browser
;
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();
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
);
957 CoreAppLauncherHandler::RecordAppLaunchType(
958 extension_misc::APP_LAUNCH_SESSION_RESTORE
,
959 extension
->GetType());
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
,
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
) {
981 browser
->tab_strip_model()->GetIndexOfWebContents(
982 RestoreTab(tab
, i
, browser
, false)));
983 tab_loader_
->TabIsLoading(
984 &browser
->tab_strip_model()->GetActiveWebContents()->
987 RestoreTab(tab
, i
, browser
, true);
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);
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
1007 WebContents
* RestoreTab(const SessionTab
& tab
,
1008 const int tab_index
,
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())
1016 int selected_index
= tab
.current_navigation_index
;
1017 selected_index
= std::max(
1019 std::min(selected_index
,
1020 static_cast<int>(tab
.navigations
.size() - 1)));
1022 RecordAppLaunchForTab(browser
, tab
, selected_index
);
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
);
1033 WebContents
* web_contents
=
1034 chrome::AddRestoredTab(browser
,
1038 tab
.extension_app_id
,
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());
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
,
1061 tab_loader_
->ScheduleLoad(&web_contents
->GetController());
1062 return web_contents
;
1065 Browser
* CreateRestoredBrowser(Browser::Type type
,
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
);
1077 void ShowBrowser(Browser
* browser
, int selected_tab_index
) {
1079 DCHECK(browser
->tab_strip_model()->count());
1080 browser
->tab_strip_model()->ActivateTabAt(selected_tab_index
, true);
1082 if (browser_
== browser
)
1085 browser
->window()->Show();
1086 browser
->set_is_session_restore(false);
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();
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",
1100 base::TimeDelta::FromMilliseconds(10),
1101 base::TimeDelta::FromSeconds(1000),
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
;
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(¶ms
);
1121 // Invokes TabRestored on the SessionService for all tabs in browser after
1123 void NotifySessionServiceOfRestoredTabs(Browser
* browser
, int initial_count
) {
1124 SessionService
* session_service
=
1125 SessionServiceFactory::GetForProfile(profile_
);
1126 if (!session_service
)
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
));
1134 // The profile to create the sessions for.
1137 // The first browser to restore to, may be null.
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_
;
1144 // Whether or not restore is synchronous.
1145 const bool synchronous_
;
1147 // See description of CLOBBER_CURRENT_TAB.
1148 const bool clobber_existing_tab_
;
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_
;
1155 // Set of URLs to open in addition to those restored from the session.
1156 std::vector
<GURL
> urls_to_open_
;
1158 // Used to get the session.
1159 CancelableTaskTracker cancelable_task_tracker_
;
1161 // Responsible for loading the tabs.
1162 scoped_refptr
<TabLoader
> tab_loader_
;
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_
;
1171 content::NotificationRegistrar registrar_
;
1173 // The time we started the restore.
1174 base::TimeTicks restore_started_
;
1176 // Set to true after the first browser is shown.
1177 bool browser_shown_
;
1179 DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl
);
1184 // SessionRestore -------------------------------------------------------------
1187 Browser
* SessionRestore::RestoreSession(
1190 chrome::HostDesktopType host_desktop_type
,
1192 const std::vector
<GURL
>& urls_to_open
) {
1193 #if defined(OS_CHROMEOS)
1194 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1195 "SessionRestore-Start", false);
1198 // Always restore from the original profile (incognito profiles have no
1199 // session service).
1200 profile
= profile
->GetOriginalProfile();
1201 if (!SessionServiceFactory::GetForProfile(profile
)) {
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,
1212 return restorer
->Restore();
1216 std::vector
<Browser
*> SessionRestore::RestoreForeignSessionWindows(
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
);
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
);
1241 bool SessionRestore::IsRestoring(const Profile
* profile
) {
1242 if (active_session_restorers
== NULL
)
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
)
1254 bool SessionRestore::IsRestoringSynchronously() {
1255 if (!active_session_restorers
)
1257 for (std::set
<SessionRestoreImpl
*>::const_iterator it
=
1258 active_session_restorers
->begin();
1259 it
!= active_session_restorers
->end(); ++it
) {
1260 if ((*it
)->synchronous())