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/run_loop.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/performance_monitor/startup_timer.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/search/search.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 "chrome/common/url_constants.h"
40 #include "content/public/browser/child_process_security_policy.h"
41 #include "content/public/browser/dom_storage_context.h"
42 #include "content/public/browser/navigation_controller.h"
43 #include "content/public/browser/notification_registrar.h"
44 #include "content/public/browser/notification_service.h"
45 #include "content/public/browser/render_process_host.h"
46 #include "content/public/browser/render_widget_host.h"
47 #include "content/public/browser/render_widget_host_view.h"
48 #include "content/public/browser/session_storage_namespace.h"
49 #include "content/public/browser/storage_partition.h"
50 #include "content/public/browser/web_contents.h"
51 #include "extensions/browser/extension_registry.h"
52 #include "extensions/common/extension_set.h"
53 #include "net/base/network_change_notifier.h"
55 #if defined(OS_CHROMEOS)
56 #include "chrome/browser/chromeos/boot_times_loader.h"
59 using content::NavigationController
;
60 using content::RenderWidgetHost
;
61 using content::WebContents
;
65 class SessionRestoreImpl
;
68 TabLoader
* shared_tab_loader
= NULL
;
70 // Pointers to SessionRestoreImpls which are currently restoring the session.
71 std::set
<SessionRestoreImpl
*>* active_session_restorers
= NULL
;
73 // TabLoader ------------------------------------------------------------------
75 // Initial delay (see class decription for details).
76 static const int kInitialDelayTimerMS
= 100;
78 // TabLoader is responsible for loading tabs after session restore creates
79 // tabs. New tabs are loaded after the current tab finishes loading, or a delay
80 // is reached (initially kInitialDelayTimerMS). If the delay is reached before
81 // a tab finishes loading a new tab is loaded and the time of the delay
84 // TabLoader keeps a reference to itself when it's loading. When it has finished
85 // loading, it drops the reference. If another profile is restored while the
86 // TabLoader is loading, it will schedule its tabs to get loaded by the same
87 // TabLoader. When doing the scheduling, it holds a reference to the TabLoader.
89 // This is not part of SessionRestoreImpl so that synchronous destruction
90 // of SessionRestoreImpl doesn't have timing problems.
91 class TabLoader
: public content::NotificationObserver
,
92 public net::NetworkChangeNotifier::ConnectionTypeObserver
,
93 public base::RefCounted
<TabLoader
> {
95 // Retrieves a pointer to the TabLoader instance shared between profiles, or
96 // creates a new TabLoader if it doesn't exist. If a TabLoader is created, its
97 // starting timestamp is set to |restore_started|.
98 static TabLoader
* GetTabLoader(base::TimeTicks restore_started
);
100 // Schedules a tab for loading.
101 void ScheduleLoad(NavigationController
* controller
);
103 // Notifies the loader that a tab has been scheduled for loading through
104 // some other mechanism.
105 void TabIsLoading(NavigationController
* controller
);
107 // Invokes |LoadNextTab| to load a tab.
109 // This must be invoked once to start loading.
113 friend class base::RefCounted
<TabLoader
>;
115 typedef std::set
<NavigationController
*> TabsLoading
;
116 typedef std::list
<NavigationController
*> TabsToLoad
;
117 typedef std::set
<RenderWidgetHost
*> RenderWidgetHostSet
;
119 explicit TabLoader(base::TimeTicks restore_started
);
120 virtual ~TabLoader();
122 // Loads the next tab. If there are no more tabs to load this deletes itself,
123 // otherwise |force_load_timer_| is restarted.
126 // NotificationObserver method. Removes the specified tab and loads the next
128 virtual void Observe(int type
,
129 const content::NotificationSource
& source
,
130 const content::NotificationDetails
& details
) OVERRIDE
;
132 // net::NetworkChangeNotifier::ConnectionTypeObserver overrides.
133 virtual void OnConnectionTypeChanged(
134 net::NetworkChangeNotifier::ConnectionType type
) OVERRIDE
;
136 // Removes the listeners from the specified tab and removes the tab from
137 // the set of tabs to load and list of tabs we're waiting to get a load
139 void RemoveTab(NavigationController
* tab
);
141 // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes
142 // |LoadNextTab| to load the next tab
143 void ForceLoadTimerFired();
145 // Returns the RenderWidgetHost associated with a tab if there is one,
147 static RenderWidgetHost
* GetRenderWidgetHost(NavigationController
* tab
);
149 // Register for necessary notifications on a tab navigation controller.
150 void RegisterForNotifications(NavigationController
* controller
);
152 // Called when a tab goes away or a load completes.
153 void HandleTabClosedOrLoaded(NavigationController
* controller
);
155 content::NotificationRegistrar registrar_
;
157 // Current delay before a new tab is loaded. See class description for
159 int64 force_load_delay_
;
161 // Has Load been invoked?
164 // Have we recorded the times for a tab paint?
165 bool got_first_paint_
;
167 // The set of tabs we've initiated loading on. This does NOT include the
169 TabsLoading tabs_loading_
;
171 // The tabs we need to load.
172 TabsToLoad tabs_to_load_
;
174 // The renderers we have started loading into.
175 RenderWidgetHostSet render_widget_hosts_loading_
;
177 // The renderers we have loaded and are waiting on to paint.
178 RenderWidgetHostSet render_widget_hosts_to_paint_
;
180 // The number of tabs that have been restored.
183 base::OneShotTimer
<TabLoader
> force_load_timer_
;
185 // The time the restore process started.
186 base::TimeTicks restore_started_
;
188 // Max number of tabs that were loaded in parallel (for metrics).
189 size_t max_parallel_tab_loads_
;
191 // For keeping TabLoader alive while it's loading even if no
192 // SessionRestoreImpls reference it.
193 scoped_refptr
<TabLoader
> this_retainer_
;
195 DISALLOW_COPY_AND_ASSIGN(TabLoader
);
199 TabLoader
* TabLoader::GetTabLoader(base::TimeTicks restore_started
) {
200 if (!shared_tab_loader
)
201 shared_tab_loader
= new TabLoader(restore_started
);
202 return shared_tab_loader
;
205 void TabLoader::ScheduleLoad(NavigationController
* controller
) {
207 DCHECK(find(tabs_to_load_
.begin(), tabs_to_load_
.end(), controller
) ==
208 tabs_to_load_
.end());
209 tabs_to_load_
.push_back(controller
);
210 RegisterForNotifications(controller
);
213 void TabLoader::TabIsLoading(NavigationController
* controller
) {
215 DCHECK(find(tabs_loading_
.begin(), tabs_loading_
.end(), controller
) ==
216 tabs_loading_
.end());
217 tabs_loading_
.insert(controller
);
218 RenderWidgetHost
* render_widget_host
= GetRenderWidgetHost(controller
);
219 DCHECK(render_widget_host
);
220 render_widget_hosts_loading_
.insert(render_widget_host
);
221 RegisterForNotifications(controller
);
224 void TabLoader::StartLoading() {
225 // When multiple profiles are using the same TabLoader, another profile might
226 // already have started loading. In that case, the tabs scheduled for loading
227 // by this profile are already in the loading queue, and they will get loaded
233 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
,
234 content::NotificationService::AllSources());
235 this_retainer_
= this;
236 #if defined(OS_CHROMEOS)
237 if (!net::NetworkChangeNotifier::IsOffline()) {
241 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
249 TabLoader::TabLoader(base::TimeTicks restore_started
)
250 : force_load_delay_(kInitialDelayTimerMS
),
252 got_first_paint_(false),
254 restore_started_(restore_started
),
255 max_parallel_tab_loads_(0) {
258 TabLoader::~TabLoader() {
259 DCHECK((got_first_paint_
|| render_widget_hosts_to_paint_
.empty()) &&
260 tabs_loading_
.empty() && tabs_to_load_
.empty());
261 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
262 shared_tab_loader
= NULL
;
265 void TabLoader::LoadNextTab() {
266 if (!tabs_to_load_
.empty()) {
267 NavigationController
* tab
= tabs_to_load_
.front();
269 tabs_loading_
.insert(tab
);
270 if (tabs_loading_
.size() > max_parallel_tab_loads_
)
271 max_parallel_tab_loads_
= tabs_loading_
.size();
272 tabs_to_load_
.pop_front();
273 tab
->LoadIfNecessary();
274 content::WebContents
* contents
= tab
->GetWebContents();
276 Browser
* browser
= chrome::FindBrowserWithWebContents(contents
);
278 browser
->tab_strip_model()->GetActiveWebContents() != contents
) {
279 // By default tabs are marked as visible. As only the active tab is
280 // visible we need to explicitly tell non-active tabs they are hidden.
281 // Without this call non-active tabs are not marked as backgrounded.
283 // NOTE: We need to do this here rather than when the tab is added to
284 // the Browser as at that time not everything has been created, so that
285 // the call would do nothing.
286 contents
->WasHidden();
291 if (!tabs_to_load_
.empty()) {
292 force_load_timer_
.Stop();
293 // Each time we load a tab we also set a timer to force us to start loading
294 // the next tab if this one doesn't load quickly enough.
295 force_load_timer_
.Start(FROM_HERE
,
296 base::TimeDelta::FromMilliseconds(force_load_delay_
),
297 this, &TabLoader::ForceLoadTimerFired
);
300 // When the session restore is done synchronously, notification is sent from
301 // SessionRestoreImpl::Restore .
302 if (tabs_to_load_
.empty() && !SessionRestore::IsRestoringSynchronously()) {
303 content::NotificationService::current()->Notify(
304 chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
305 content::NotificationService::AllSources(),
306 content::NotificationService::NoDetails());
310 void TabLoader::Observe(int type
,
311 const content::NotificationSource
& source
,
312 const content::NotificationDetails
& details
) {
314 case content::NOTIFICATION_LOAD_START
: {
315 // Add this render_widget_host to the set of those we're waiting for
316 // paints on. We want to only record stats for paints that occur after
317 // a load has finished.
318 NavigationController
* tab
=
319 content::Source
<NavigationController
>(source
).ptr();
320 RenderWidgetHost
* render_widget_host
= GetRenderWidgetHost(tab
);
321 DCHECK(render_widget_host
);
322 render_widget_hosts_loading_
.insert(render_widget_host
);
325 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED
: {
326 WebContents
* web_contents
= content::Source
<WebContents
>(source
).ptr();
327 if (!got_first_paint_
) {
328 RenderWidgetHost
* render_widget_host
=
329 GetRenderWidgetHost(&web_contents
->GetController());
330 render_widget_hosts_loading_
.erase(render_widget_host
);
332 HandleTabClosedOrLoaded(&web_contents
->GetController());
335 case content::NOTIFICATION_LOAD_STOP
: {
336 NavigationController
* tab
=
337 content::Source
<NavigationController
>(source
).ptr();
338 render_widget_hosts_to_paint_
.insert(GetRenderWidgetHost(tab
));
339 HandleTabClosedOrLoaded(tab
);
342 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
: {
343 RenderWidgetHost
* render_widget_host
=
344 content::Source
<RenderWidgetHost
>(source
).ptr();
345 if (!got_first_paint_
&& render_widget_host
->GetView() &&
346 render_widget_host
->GetView()->IsShowing()) {
347 if (render_widget_hosts_to_paint_
.find(render_widget_host
) !=
348 render_widget_hosts_to_paint_
.end()) {
349 // Got a paint for one of our renderers, so record time.
350 got_first_paint_
= true;
351 base::TimeDelta time_to_paint
=
352 base::TimeTicks::Now() - restore_started_
;
353 UMA_HISTOGRAM_CUSTOM_TIMES(
354 "SessionRestore.FirstTabPainted",
356 base::TimeDelta::FromMilliseconds(10),
357 base::TimeDelta::FromSeconds(100),
359 // Record a time for the number of tabs, to help track down
361 std::string time_for_count
=
362 base::StringPrintf("SessionRestore.FirstTabPainted_%d",
364 base::HistogramBase
* counter_for_count
=
365 base::Histogram::FactoryTimeGet(
367 base::TimeDelta::FromMilliseconds(10),
368 base::TimeDelta::FromSeconds(100),
370 base::Histogram::kUmaTargetedHistogramFlag
);
371 counter_for_count
->AddTime(time_to_paint
);
372 } else if (render_widget_hosts_loading_
.find(render_widget_host
) ==
373 render_widget_hosts_loading_
.end()) {
374 // If this is a host for a tab we're not loading some other tab
375 // has rendered and there's no point tracking the time. This could
376 // happen because the user opened a different tab or restored tabs
377 // to an already existing browser and an existing tab painted.
378 got_first_paint_
= true;
384 NOTREACHED() << "Unknown notification received:" << type
;
386 // Delete ourselves when we're not waiting for any more notifications. If this
387 // was not the last reference, a SessionRestoreImpl holding a reference will
388 // eventually call StartLoading (which assigns this_retainer_), or drop the
389 // reference without initiating a load.
390 if ((got_first_paint_
|| render_widget_hosts_to_paint_
.empty()) &&
391 tabs_loading_
.empty() && tabs_to_load_
.empty())
392 this_retainer_
= NULL
;
395 void TabLoader::OnConnectionTypeChanged(
396 net::NetworkChangeNotifier::ConnectionType type
) {
397 if (type
!= net::NetworkChangeNotifier::CONNECTION_NONE
) {
407 void TabLoader::RemoveTab(NavigationController
* tab
) {
408 registrar_
.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
409 content::Source
<WebContents
>(tab
->GetWebContents()));
410 registrar_
.Remove(this, content::NOTIFICATION_LOAD_STOP
,
411 content::Source
<NavigationController
>(tab
));
412 registrar_
.Remove(this, content::NOTIFICATION_LOAD_START
,
413 content::Source
<NavigationController
>(tab
));
415 TabsLoading::iterator i
= tabs_loading_
.find(tab
);
416 if (i
!= tabs_loading_
.end())
417 tabs_loading_
.erase(i
);
419 TabsToLoad::iterator j
=
420 find(tabs_to_load_
.begin(), tabs_to_load_
.end(), tab
);
421 if (j
!= tabs_to_load_
.end())
422 tabs_to_load_
.erase(j
);
425 void TabLoader::ForceLoadTimerFired() {
426 force_load_delay_
*= 2;
430 RenderWidgetHost
* TabLoader::GetRenderWidgetHost(NavigationController
* tab
) {
431 WebContents
* web_contents
= tab
->GetWebContents();
433 content::RenderWidgetHostView
* render_widget_host_view
=
434 web_contents
->GetRenderWidgetHostView();
435 if (render_widget_host_view
)
436 return render_widget_host_view
->GetRenderWidgetHost();
441 void TabLoader::RegisterForNotifications(NavigationController
* controller
) {
442 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
443 content::Source
<WebContents
>(controller
->GetWebContents()));
444 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
,
445 content::Source
<NavigationController
>(controller
));
446 registrar_
.Add(this, content::NOTIFICATION_LOAD_START
,
447 content::Source
<NavigationController
>(controller
));
451 void TabLoader::HandleTabClosedOrLoaded(NavigationController
* tab
) {
455 if (tabs_loading_
.empty() && tabs_to_load_
.empty()) {
456 base::TimeDelta time_to_load
=
457 base::TimeTicks::Now() - restore_started_
;
458 performance_monitor::StartupTimer::SetElapsedSessionRestoreTime(
460 UMA_HISTOGRAM_CUSTOM_TIMES(
461 "SessionRestore.AllTabsLoaded",
463 base::TimeDelta::FromMilliseconds(10),
464 base::TimeDelta::FromSeconds(100),
466 // Record a time for the number of tabs, to help track down contention.
467 std::string time_for_count
=
468 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_
);
469 base::HistogramBase
* counter_for_count
=
470 base::Histogram::FactoryTimeGet(
472 base::TimeDelta::FromMilliseconds(10),
473 base::TimeDelta::FromSeconds(100),
475 base::Histogram::kUmaTargetedHistogramFlag
);
476 counter_for_count
->AddTime(time_to_load
);
478 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
479 max_parallel_tab_loads_
);
483 // SessionRestoreImpl ---------------------------------------------------------
485 // SessionRestoreImpl is responsible for fetching the set of tabs to create
486 // from SessionService. SessionRestoreImpl deletes itself when done.
488 class SessionRestoreImpl
: public content::NotificationObserver
{
490 SessionRestoreImpl(Profile
* profile
,
492 chrome::HostDesktopType host_desktop_type
,
494 bool clobber_existing_tab
,
495 bool always_create_tabbed_browser
,
496 const std::vector
<GURL
>& urls_to_open
)
499 host_desktop_type_(host_desktop_type
),
500 synchronous_(synchronous
),
501 clobber_existing_tab_(clobber_existing_tab
),
502 always_create_tabbed_browser_(always_create_tabbed_browser
),
503 urls_to_open_(urls_to_open
),
504 active_window_id_(0),
505 restore_started_(base::TimeTicks::Now()),
506 browser_shown_(false) {
507 // For sanity's sake, if |browser| is non-null: force |host_desktop_type| to
508 // be the same as |browser|'s desktop type.
509 DCHECK(!browser
|| browser
->host_desktop_type() == host_desktop_type
);
511 if (active_session_restorers
== NULL
)
512 active_session_restorers
= new std::set
<SessionRestoreImpl
*>();
514 // Only one SessionRestoreImpl should be operating on the profile at the
516 std::set
<SessionRestoreImpl
*>::const_iterator it
;
517 for (it
= active_session_restorers
->begin();
518 it
!= active_session_restorers
->end(); ++it
) {
519 if ((*it
)->profile_
== profile
)
522 DCHECK(it
== active_session_restorers
->end());
524 active_session_restorers
->insert(this);
526 // When asynchronous its possible for there to be no windows. To make sure
527 // Chrome doesn't prematurely exit AddRef the process. We'll release in the
528 // destructor when restore is done.
529 g_browser_process
->AddRefModule();
532 bool synchronous() const { return synchronous_
; }
535 SessionService
* session_service
=
536 SessionServiceFactory::GetForProfile(profile_
);
537 DCHECK(session_service
);
538 session_service
->GetLastSession(
539 base::Bind(&SessionRestoreImpl::OnGotSession
, base::Unretained(this)),
540 &cancelable_task_tracker_
);
544 base::MessageLoop::ScopedNestableTaskAllower
allow(
545 base::MessageLoop::current());
547 quit_closure_for_sync_restore_
= loop
.QuitClosure();
549 quit_closure_for_sync_restore_
= base::Closure();
551 Browser
* browser
= ProcessSessionWindows(&windows_
, active_window_id_
);
553 content::NotificationService::current()->Notify(
554 chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
555 content::NotificationService::AllSources(),
556 content::NotificationService::NoDetails());
561 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED
,
562 content::Source
<Browser
>(browser_
));
568 // Restore window(s) from a foreign session. Returns newly created Browsers.
569 std::vector
<Browser
*> RestoreForeignSession(
570 std::vector
<const SessionWindow
*>::const_iterator begin
,
571 std::vector
<const SessionWindow
*>::const_iterator end
) {
573 std::vector
<Browser
*> browsers
;
574 // Create a browser instance to put the restored tabs in.
575 for (std::vector
<const SessionWindow
*>::const_iterator i
= begin
;
577 Browser
* browser
= CreateRestoredBrowser(
578 static_cast<Browser::Type
>((*i
)->type
),
582 browsers
.push_back(browser
);
584 // Restore and show the browser.
585 const int initial_tab_count
= 0;
586 int selected_tab_index
= std::max(
588 std::min((*i
)->selected_tab_index
,
589 static_cast<int>((*i
)->tabs
.size()) - 1));
590 RestoreTabsToBrowser(*(*i
), browser
, initial_tab_count
,
592 NotifySessionServiceOfRestoredTabs(browser
, initial_tab_count
);
595 // Always create in a new window
596 FinishedTabCreation(true, true);
600 // Restore a single tab from a foreign session.
601 // Opens in the tab in the last active browser, unless disposition is
602 // NEW_WINDOW, in which case the tab will be opened in a new browser. Returns
603 // the WebContents of the restored tab.
604 WebContents
* RestoreForeignTab(const SessionTab
& tab
,
605 WindowOpenDisposition disposition
) {
606 DCHECK(!tab
.navigations
.empty());
607 int selected_index
= tab
.current_navigation_index
;
608 selected_index
= std::max(
610 std::min(selected_index
,
611 static_cast<int>(tab
.navigations
.size() - 1)));
613 bool use_new_window
= disposition
== NEW_WINDOW
;
615 Browser
* browser
= use_new_window
?
616 new Browser(Browser::CreateParams(profile_
, host_desktop_type_
)) :
619 RecordAppLaunchForTab(browser
, tab
, selected_index
);
621 WebContents
* web_contents
;
622 if (disposition
== CURRENT_TAB
) {
623 DCHECK(!use_new_window
);
624 web_contents
= chrome::ReplaceRestoredTab(browser
,
628 tab
.extension_app_id
,
630 tab
.user_agent_override
);
633 use_new_window
? 0 : browser
->tab_strip_model()->active_index() + 1;
634 web_contents
= chrome::AddRestoredTab(
639 tab
.extension_app_id
,
640 disposition
== NEW_FOREGROUND_TAB
, // selected
644 tab
.user_agent_override
);
645 // Start loading the tab immediately.
646 web_contents
->GetController().LoadIfNecessary();
649 if (use_new_window
) {
650 browser
->tab_strip_model()->ActivateTabAt(0, true);
651 browser
->window()->Show();
653 NotifySessionServiceOfRestoredTabs(browser
,
654 browser
->tab_strip_model()->count());
656 // Since FinishedTabCreation() is not called here, |this| will leak if we
657 // are not in sychronous mode.
658 DCHECK(synchronous_
);
662 virtual ~SessionRestoreImpl() {
663 STLDeleteElements(&windows_
);
665 active_session_restorers
->erase(this);
666 if (active_session_restorers
->empty()) {
667 delete active_session_restorers
;
668 active_session_restorers
= NULL
;
671 g_browser_process
->ReleaseModule();
674 virtual void Observe(int type
,
675 const content::NotificationSource
& source
,
676 const content::NotificationDetails
& details
) OVERRIDE
{
678 case chrome::NOTIFICATION_BROWSER_CLOSED
:
688 Profile
* profile() { return profile_
; }
691 // Invoked when beginning to create new tabs. Resets the tab_loader_.
692 void StartTabCreation() {
693 tab_loader_
= TabLoader::GetTabLoader(restore_started_
);
696 // Invoked when done with creating all the tabs/browsers.
698 // |created_tabbed_browser| indicates whether a tabbed browser was created,
699 // or we used an existing tabbed browser.
701 // If successful, this begins loading tabs and deletes itself when all tabs
704 // Returns the Browser that was created, if any.
705 Browser
* FinishedTabCreation(bool succeeded
, bool created_tabbed_browser
) {
706 Browser
* browser
= NULL
;
707 if (!created_tabbed_browser
&& always_create_tabbed_browser_
) {
708 browser
= new Browser(Browser::CreateParams(profile_
,
709 host_desktop_type_
));
710 if (urls_to_open_
.empty()) {
711 // No tab browsers were created and no URLs were supplied on the command
712 // line. Add an empty URL, which is treated as opening the users home
714 urls_to_open_
.push_back(GURL());
716 AppendURLsToBrowser(browser
, urls_to_open_
);
717 browser
->window()->Show();
721 DCHECK(tab_loader_
.get());
722 // TabLoader deletes itself when done loading.
723 tab_loader_
->StartLoading();
728 // If we're not synchronous we need to delete ourself.
729 // NOTE: we must use DeleteLater here as most likely we're in a callback
730 // from the history service which doesn't deal well with deleting the
731 // object it is notifying.
732 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
734 // The delete may take a while and at this point we no longer care about
735 // if the browser is deleted. Don't listen to anything. This avoid a
736 // possible double delete too (if browser is closed before DeleteSoon() is
738 registrar_
.RemoveAll();
741 #if defined(OS_CHROMEOS)
742 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
743 "SessionRestore-End", false);
748 void OnGotSession(ScopedVector
<SessionWindow
> windows
,
749 SessionID::id_type active_window_id
) {
750 base::TimeDelta time_to_got_sessions
=
751 base::TimeTicks::Now() - restore_started_
;
752 UMA_HISTOGRAM_CUSTOM_TIMES(
753 "SessionRestore.TimeToGotSessions",
754 time_to_got_sessions
,
755 base::TimeDelta::FromMilliseconds(10),
756 base::TimeDelta::FromSeconds(1000),
758 #if defined(OS_CHROMEOS)
759 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
760 "SessionRestore-GotSession", false);
763 // See comment above windows_ as to why we don't process immediately.
764 windows_
.swap(windows
.get());
765 active_window_id_
= active_window_id
;
766 CHECK(!quit_closure_for_sync_restore_
.is_null());
767 quit_closure_for_sync_restore_
.Run();
771 ProcessSessionWindows(&windows
.get(), active_window_id
);
774 Browser
* ProcessSessionWindows(std::vector
<SessionWindow
*>* windows
,
775 SessionID::id_type active_window_id
) {
776 VLOG(1) << "ProcessSessionWindows " << windows
->size();
777 base::TimeDelta time_to_process_sessions
=
778 base::TimeTicks::Now() - restore_started_
;
779 UMA_HISTOGRAM_CUSTOM_TIMES(
780 "SessionRestore.TimeToProcessSessions",
781 time_to_process_sessions
,
782 base::TimeDelta::FromMilliseconds(10),
783 base::TimeDelta::FromSeconds(1000),
786 if (windows
->empty()) {
787 // Restore was unsuccessful. The DOM storage system can also delete its
788 // data, since no session restore will happen at a later point in time.
789 content::BrowserContext::GetDefaultStoragePartition(profile_
)->
790 GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
791 return FinishedTabCreation(false, false);
794 #if defined(OS_CHROMEOS)
795 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
796 "SessionRestore-CreatingTabs-Start", false);
800 // After the for loop this contains the last TABBED_BROWSER. Is null if no
801 // tabbed browsers exist.
802 Browser
* last_browser
= NULL
;
803 bool has_tabbed_browser
= false;
805 // After the for loop, this contains the browser to activate, if one of the
806 // windows has the same id as specified in active_window_id.
807 Browser
* browser_to_activate
= NULL
;
809 int selected_tab_to_activate
= -1;
812 // Determine if there is a visible window.
813 bool has_visible_browser
= false;
814 for (std::vector
<SessionWindow
*>::iterator i
= windows
->begin();
815 i
!= windows
->end(); ++i
) {
816 if ((*i
)->show_state
!= ui::SHOW_STATE_MINIMIZED
)
817 has_visible_browser
= true;
820 for (std::vector
<SessionWindow
*>::iterator i
= windows
->begin();
821 i
!= windows
->end(); ++i
) {
822 Browser
* browser
= NULL
;
823 if (!has_tabbed_browser
&& (*i
)->type
== Browser::TYPE_TABBED
)
824 has_tabbed_browser
= true;
825 if (i
== windows
->begin() && (*i
)->type
== Browser::TYPE_TABBED
&&
826 browser_
&& browser_
->is_type_tabbed() &&
827 !browser_
->profile()->IsOffTheRecord()) {
828 // The first set of tabs is added to the existing browser.
831 #if defined(OS_CHROMEOS)
832 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
833 "SessionRestore-CreateRestoredBrowser-Start", false);
835 // Show the first window if none are visible.
836 ui::WindowShowState show_state
= (*i
)->show_state
;
837 if (!has_visible_browser
) {
838 show_state
= ui::SHOW_STATE_NORMAL
;
839 has_visible_browser
= true;
841 browser
= CreateRestoredBrowser(
842 static_cast<Browser::Type
>((*i
)->type
),
846 #if defined(OS_CHROMEOS)
847 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
848 "SessionRestore-CreateRestoredBrowser-End", false);
851 if ((*i
)->type
== Browser::TYPE_TABBED
)
852 last_browser
= browser
;
853 WebContents
* active_tab
=
854 browser
->tab_strip_model()->GetActiveWebContents();
855 int initial_tab_count
= browser
->tab_strip_model()->count();
856 bool close_active_tab
= clobber_existing_tab_
&&
857 i
== windows
->begin() &&
858 (*i
)->type
== Browser::TYPE_TABBED
&&
859 active_tab
&& browser
== browser_
&&
860 (*i
)->tabs
.size() > 0;
861 if (close_active_tab
)
863 int selected_tab_index
=
864 initial_tab_count
> 0 ? browser
->tab_strip_model()->active_index()
866 std::min((*i
)->selected_tab_index
,
867 static_cast<int>((*i
)->tabs
.size()) - 1));
868 if ((*i
)->window_id
.id() == active_window_id
) {
869 browser_to_activate
= browser
;
871 selected_tab_to_activate
= selected_tab_index
;
874 RestoreTabsToBrowser(*(*i
), browser
, initial_tab_count
,
876 NotifySessionServiceOfRestoredTabs(browser
, initial_tab_count
);
877 // This needs to be done after restore because closing the last tab will
878 // close the whole window.
879 if (close_active_tab
)
880 chrome::CloseWebContents(browser
, active_tab
, true);
882 selected_tab_to_activate
= -1;
886 if (browser_to_activate
&& browser_to_activate
->is_type_tabbed())
887 last_browser
= browser_to_activate
;
889 if (last_browser
&& !urls_to_open_
.empty())
890 AppendURLsToBrowser(last_browser
, urls_to_open_
);
891 #if defined(OS_CHROMEOS)
892 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
893 "SessionRestore-CreatingTabs-End", false);
895 if (browser_to_activate
)
896 browser_to_activate
->window()->Activate();
898 // If last_browser is NULL and urls_to_open_ is non-empty,
899 // FinishedTabCreation will create a new TabbedBrowser and add the urls to
901 Browser
* finished_browser
= FinishedTabCreation(true, has_tabbed_browser
);
902 if (finished_browser
)
903 last_browser
= finished_browser
;
905 // sessionStorages needed for the session restore have now been recreated
906 // by RestoreTab. Now it's safe for the DOM storage system to start
907 // deleting leftover data.
908 content::BrowserContext::GetDefaultStoragePartition(profile_
)->
909 GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
913 // Record an app launch event (if appropriate) for a tab which is about to
914 // be restored. Callers should ensure that selected_index is within the
915 // bounds of tab.navigations before calling.
916 void RecordAppLaunchForTab(Browser
* browser
,
917 const SessionTab
& tab
,
918 int selected_index
) {
919 DCHECK(selected_index
>= 0 &&
920 selected_index
< static_cast<int>(tab
.navigations
.size()));
921 GURL url
= tab
.navigations
[selected_index
].virtual_url();
922 const extensions::Extension
* extension
=
923 extensions::ExtensionRegistry::Get(profile())
924 ->enabled_extensions().GetAppByURL(url
);
926 CoreAppLauncherHandler::RecordAppLaunchType(
927 extension_misc::APP_LAUNCH_SESSION_RESTORE
,
928 extension
->GetType());
932 // Adds the tabs from |window| to |browser|. Normal tabs go after the existing
933 // tabs but pinned tabs will be pushed in front.
934 // If there are no existing tabs, the tab at |selected_tab_index| will be
935 // selected. Otherwise, the tab selection will remain untouched.
936 void RestoreTabsToBrowser(const SessionWindow
& window
,
938 int initial_tab_count
,
939 int selected_tab_index
) {
940 VLOG(1) << "RestoreTabsToBrowser " << window
.tabs
.size();
941 DCHECK(!window
.tabs
.empty());
942 if (initial_tab_count
== 0) {
943 for (int i
= 0; i
< static_cast<int>(window
.tabs
.size()); ++i
) {
944 const SessionTab
& tab
= *(window
.tabs
[i
]);
946 // Loads are scheduled for each restored tab unless the tab is going to
947 // be selected as ShowBrowser() will load the selected tab.
948 bool is_not_selected_tab
= (i
!= selected_tab_index
);
949 WebContents
* restored_tab
=
950 RestoreTab(tab
, i
, browser
, is_not_selected_tab
);
952 // RestoreTab can return NULL if |tab| doesn't have valid data.
956 // If this isn't the selected tab, there's nothing else to do.
957 if (is_not_selected_tab
)
962 browser
->tab_strip_model()->GetIndexOfWebContents(restored_tab
));
963 tab_loader_
->TabIsLoading(&browser
->tab_strip_model()
964 ->GetActiveWebContents()
968 // If the browser already has tabs, we want to restore the new ones after
969 // the existing ones. E.g. this happens in Win8 Metro where we merge
970 // windows or when launching a hosted app from the app launcher.
971 int tab_index_offset
= initial_tab_count
;
972 for (int i
= 0; i
< static_cast<int>(window
.tabs
.size()); ++i
) {
973 const SessionTab
& tab
= *(window
.tabs
[i
]);
974 // Always schedule loads as we will not be calling ShowBrowser().
975 RestoreTab(tab
, tab_index_offset
+ i
, browser
, true);
980 // |tab_index| is ignored for pinned tabs which will always be pushed behind
981 // the last existing pinned tab.
982 // |schedule_load| will let |tab_loader_| know that it should schedule this
984 WebContents
* RestoreTab(const SessionTab
& tab
,
987 bool schedule_load
) {
988 // It's possible (particularly for foreign sessions) to receive a tab
989 // without valid navigations. In that case, just skip it.
990 // See crbug.com/154129.
991 if (tab
.navigations
.empty())
993 int selected_index
= tab
.current_navigation_index
;
994 selected_index
= std::max(
996 std::min(selected_index
,
997 static_cast<int>(tab
.navigations
.size() - 1)));
999 RecordAppLaunchForTab(browser
, tab
, selected_index
);
1001 // Associate sessionStorage (if any) to the restored tab.
1002 scoped_refptr
<content::SessionStorageNamespace
> session_storage_namespace
;
1003 if (!tab
.session_storage_persistent_id
.empty()) {
1004 session_storage_namespace
=
1005 content::BrowserContext::GetDefaultStoragePartition(profile_
)->
1006 GetDOMStorageContext()->RecreateSessionStorage(
1007 tab
.session_storage_persistent_id
);
1010 WebContents
* web_contents
=
1011 chrome::AddRestoredTab(browser
,
1015 tab
.extension_app_id
,
1019 session_storage_namespace
.get(),
1020 tab
.user_agent_override
);
1021 // Regression check: check that the tab didn't start loading right away. The
1022 // focused tab will be loaded by Browser, and TabLoader will load the rest.
1023 DCHECK(web_contents
->GetController().NeedsReload());
1025 // Set up the file access rights for the selected navigation entry.
1026 const int id
= web_contents
->GetRenderProcessHost()->GetID();
1027 const content::PageState
& page_state
=
1028 tab
.navigations
.at(selected_index
).page_state();
1029 const std::vector
<base::FilePath
>& file_paths
=
1030 page_state
.GetReferencedFiles();
1031 for (std::vector
<base::FilePath
>::const_iterator file
= file_paths
.begin();
1032 file
!= file_paths
.end(); ++file
) {
1033 content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id
,
1038 tab_loader_
->ScheduleLoad(&web_contents
->GetController());
1039 return web_contents
;
1042 Browser
* CreateRestoredBrowser(Browser::Type type
,
1044 ui::WindowShowState show_state
,
1045 const std::string
& app_name
) {
1046 Browser::CreateParams
params(type
, profile_
, host_desktop_type_
);
1047 if (!app_name
.empty()) {
1048 const bool trusted_source
= true; // We only store trusted app windows.
1049 params
= Browser::CreateParams::CreateForApp(app_name
,
1053 host_desktop_type_
);
1055 params
.initial_bounds
= bounds
;
1057 params
.initial_show_state
= show_state
;
1058 params
.is_session_restore
= true;
1059 return new Browser(params
);
1062 void ShowBrowser(Browser
* browser
, int selected_tab_index
) {
1064 DCHECK(browser
->tab_strip_model()->count());
1065 browser
->tab_strip_model()->ActivateTabAt(selected_tab_index
, true);
1067 if (browser_
== browser
)
1070 browser
->window()->Show();
1071 browser
->set_is_session_restore(false);
1073 // TODO(jcampan): http://crbug.com/8123 we should not need to set the
1074 // initial focus explicitly.
1075 browser
->tab_strip_model()->GetActiveWebContents()->SetInitialFocus();
1077 if (!browser_shown_
) {
1078 browser_shown_
= true;
1079 base::TimeDelta time_to_first_show
=
1080 base::TimeTicks::Now() - restore_started_
;
1081 UMA_HISTOGRAM_CUSTOM_TIMES(
1082 "SessionRestore.TimeToFirstShow",
1084 base::TimeDelta::FromMilliseconds(10),
1085 base::TimeDelta::FromSeconds(1000),
1090 // Appends the urls in |urls| to |browser|.
1091 void AppendURLsToBrowser(Browser
* browser
,
1092 const std::vector
<GURL
>& urls
) {
1093 for (size_t i
= 0; i
< urls
.size(); ++i
) {
1094 int add_types
= TabStripModel::ADD_FORCE_INDEX
;
1096 add_types
|= TabStripModel::ADD_ACTIVE
;
1097 chrome::NavigateParams
params(browser
, urls
[i
],
1098 content::PAGE_TRANSITION_AUTO_TOPLEVEL
);
1099 params
.disposition
= i
== 0 ? NEW_FOREGROUND_TAB
: NEW_BACKGROUND_TAB
;
1100 params
.tabstrip_add_types
= add_types
;
1101 chrome::Navigate(¶ms
);
1105 // Invokes TabRestored on the SessionService for all tabs in browser after
1107 void NotifySessionServiceOfRestoredTabs(Browser
* browser
, int initial_count
) {
1108 SessionService
* session_service
=
1109 SessionServiceFactory::GetForProfile(profile_
);
1110 if (!session_service
)
1112 TabStripModel
* tab_strip
= browser
->tab_strip_model();
1113 for (int i
= initial_count
; i
< tab_strip
->count(); ++i
)
1114 session_service
->TabRestored(tab_strip
->GetWebContentsAt(i
),
1115 tab_strip
->IsTabPinned(i
));
1118 // The profile to create the sessions for.
1121 // The first browser to restore to, may be null.
1124 // The desktop on which all new browsers should be created (browser_, if it is
1125 // not NULL, must be of this desktop type as well).
1126 chrome::HostDesktopType host_desktop_type_
;
1128 // Whether or not restore is synchronous.
1129 const bool synchronous_
;
1131 // The quit-closure to terminate the nested message-loop started for
1132 // synchronous session-restore.
1133 base::Closure quit_closure_for_sync_restore_
;
1135 // See description of CLOBBER_CURRENT_TAB.
1136 const bool clobber_existing_tab_
;
1138 // If true and there is an error or there are no windows to restore, we
1139 // create a tabbed browser anyway. This is used on startup to make sure at
1140 // at least one window is created.
1141 const bool always_create_tabbed_browser_
;
1143 // Set of URLs to open in addition to those restored from the session.
1144 std::vector
<GURL
> urls_to_open_
;
1146 // Used to get the session.
1147 base::CancelableTaskTracker cancelable_task_tracker_
;
1149 // Responsible for loading the tabs.
1150 scoped_refptr
<TabLoader
> tab_loader_
;
1152 // When synchronous we run a nested message loop. To avoid creating windows
1153 // from the nested message loop (which can make exiting the nested message
1154 // loop take a while) we cache the SessionWindows here and create the actual
1155 // windows when the nested message loop exits.
1156 std::vector
<SessionWindow
*> windows_
;
1157 SessionID::id_type active_window_id_
;
1159 content::NotificationRegistrar registrar_
;
1161 // The time we started the restore.
1162 base::TimeTicks restore_started_
;
1164 // Set to true after the first browser is shown.
1165 bool browser_shown_
;
1167 DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl
);
1172 // SessionRestore -------------------------------------------------------------
1175 Browser
* SessionRestore::RestoreSession(
1178 chrome::HostDesktopType host_desktop_type
,
1180 const std::vector
<GURL
>& urls_to_open
) {
1181 #if defined(OS_CHROMEOS)
1182 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1183 "SessionRestore-Start", false);
1186 // Always restore from the original profile (incognito profiles have no
1187 // session service).
1188 profile
= profile
->GetOriginalProfile();
1189 if (!SessionServiceFactory::GetForProfile(profile
)) {
1193 profile
->set_restored_last_session(true);
1194 // SessionRestoreImpl takes care of deleting itself when done.
1195 SessionRestoreImpl
* restorer
= new SessionRestoreImpl(
1196 profile
, browser
, host_desktop_type
, (behavior
& SYNCHRONOUS
) != 0,
1197 (behavior
& CLOBBER_CURRENT_TAB
) != 0,
1198 (behavior
& ALWAYS_CREATE_TABBED_BROWSER
) != 0,
1200 return restorer
->Restore();
1204 void SessionRestore::RestoreSessionAfterCrash(Browser
* browser
) {
1205 uint32 behavior
= 0;
1206 if (browser
->tab_strip_model()->count() == 1) {
1207 const content::WebContents
* active_tab
=
1208 browser
->tab_strip_model()->GetWebContentsAt(0);
1209 if (active_tab
->GetURL() == GURL(chrome::kChromeUINewTabURL
) ||
1210 chrome::IsInstantNTP(active_tab
)) {
1211 // There is only one tab and its the new tab page, make session restore
1213 behavior
= SessionRestore::CLOBBER_CURRENT_TAB
;
1216 SessionRestore::RestoreSession(browser
->profile(), browser
,
1217 browser
->host_desktop_type(), behavior
,
1218 std::vector
<GURL
>());
1222 std::vector
<Browser
*> SessionRestore::RestoreForeignSessionWindows(
1224 chrome::HostDesktopType host_desktop_type
,
1225 std::vector
<const SessionWindow
*>::const_iterator begin
,
1226 std::vector
<const SessionWindow
*>::const_iterator end
) {
1227 std::vector
<GURL
> gurls
;
1228 SessionRestoreImpl
restorer(profile
,
1229 static_cast<Browser
*>(NULL
), host_desktop_type
, true, false, true, gurls
);
1230 return restorer
.RestoreForeignSession(begin
, end
);
1234 WebContents
* SessionRestore::RestoreForeignSessionTab(
1235 content::WebContents
* source_web_contents
,
1236 const SessionTab
& tab
,
1237 WindowOpenDisposition disposition
) {
1238 Browser
* browser
= chrome::FindBrowserWithWebContents(source_web_contents
);
1239 Profile
* profile
= browser
->profile();
1240 std::vector
<GURL
> gurls
;
1241 SessionRestoreImpl
restorer(profile
, browser
, browser
->host_desktop_type(),
1242 true, false, false, gurls
);
1243 return restorer
.RestoreForeignTab(tab
, disposition
);
1247 bool SessionRestore::IsRestoring(const Profile
* profile
) {
1248 if (active_session_restorers
== NULL
)
1250 for (std::set
<SessionRestoreImpl
*>::const_iterator it
=
1251 active_session_restorers
->begin();
1252 it
!= active_session_restorers
->end(); ++it
) {
1253 if ((*it
)->profile() == profile
)
1260 bool SessionRestore::IsRestoringSynchronously() {
1261 if (!active_session_restorers
)
1263 for (std::set
<SessionRestoreImpl
*>::const_iterator it
=
1264 active_session_restorers
->begin();
1265 it
!= active_session_restorers
->end(); ++it
) {
1266 if ((*it
)->synchronous())