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/debug/alias.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h"
19 #include "base/metrics/histogram.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 // TODO(sky): remove. For debugging 368236.
157 void CheckNotObserving(NavigationController
* controller
);
159 content::NotificationRegistrar registrar_
;
161 // Current delay before a new tab is loaded. See class description for
163 int64 force_load_delay_
;
165 // Has Load been invoked?
168 // Have we recorded the times for a tab paint?
169 bool got_first_paint_
;
171 // The set of tabs we've initiated loading on. This does NOT include the
173 TabsLoading tabs_loading_
;
175 // The tabs we need to load.
176 TabsToLoad tabs_to_load_
;
178 // The renderers we have started loading into.
179 RenderWidgetHostSet render_widget_hosts_loading_
;
181 // The renderers we have loaded and are waiting on to paint.
182 RenderWidgetHostSet render_widget_hosts_to_paint_
;
184 // The number of tabs that have been restored.
187 base::OneShotTimer
<TabLoader
> force_load_timer_
;
189 // The time the restore process started.
190 base::TimeTicks restore_started_
;
192 // Max number of tabs that were loaded in parallel (for metrics).
193 size_t max_parallel_tab_loads_
;
195 // For keeping TabLoader alive while it's loading even if no
196 // SessionRestoreImpls reference it.
197 scoped_refptr
<TabLoader
> this_retainer_
;
199 DISALLOW_COPY_AND_ASSIGN(TabLoader
);
203 TabLoader
* TabLoader::GetTabLoader(base::TimeTicks restore_started
) {
204 if (!shared_tab_loader
)
205 shared_tab_loader
= new TabLoader(restore_started
);
206 return shared_tab_loader
;
209 void TabLoader::ScheduleLoad(NavigationController
* controller
) {
210 CheckNotObserving(controller
);
212 DCHECK(find(tabs_to_load_
.begin(), tabs_to_load_
.end(), controller
) ==
213 tabs_to_load_
.end());
214 tabs_to_load_
.push_back(controller
);
215 RegisterForNotifications(controller
);
218 void TabLoader::TabIsLoading(NavigationController
* controller
) {
219 CheckNotObserving(controller
);
221 DCHECK(find(tabs_loading_
.begin(), tabs_loading_
.end(), controller
) ==
222 tabs_loading_
.end());
223 tabs_loading_
.insert(controller
);
224 RenderWidgetHost
* render_widget_host
= GetRenderWidgetHost(controller
);
225 DCHECK(render_widget_host
);
226 render_widget_hosts_loading_
.insert(render_widget_host
);
227 RegisterForNotifications(controller
);
230 void TabLoader::StartLoading() {
231 // When multiple profiles are using the same TabLoader, another profile might
232 // already have started loading. In that case, the tabs scheduled for loading
233 // by this profile are already in the loading queue, and they will get loaded
239 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
,
240 content::NotificationService::AllSources());
241 this_retainer_
= this;
242 #if defined(OS_CHROMEOS)
243 if (!net::NetworkChangeNotifier::IsOffline()) {
247 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
255 TabLoader::TabLoader(base::TimeTicks restore_started
)
256 : force_load_delay_(kInitialDelayTimerMS
),
258 got_first_paint_(false),
260 restore_started_(restore_started
),
261 max_parallel_tab_loads_(0) {
264 TabLoader::~TabLoader() {
265 DCHECK((got_first_paint_
|| render_widget_hosts_to_paint_
.empty()) &&
266 tabs_loading_
.empty() && tabs_to_load_
.empty());
267 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
268 shared_tab_loader
= NULL
;
271 void TabLoader::LoadNextTab() {
272 if (!tabs_to_load_
.empty()) {
273 NavigationController
* tab
= tabs_to_load_
.front();
275 tabs_loading_
.insert(tab
);
276 if (tabs_loading_
.size() > max_parallel_tab_loads_
)
277 max_parallel_tab_loads_
= tabs_loading_
.size();
278 tabs_to_load_
.pop_front();
279 tab
->LoadIfNecessary();
280 content::WebContents
* contents
= tab
->GetWebContents();
282 Browser
* browser
= chrome::FindBrowserWithWebContents(contents
);
284 browser
->tab_strip_model()->GetActiveWebContents() != contents
) {
285 // By default tabs are marked as visible. As only the active tab is
286 // visible we need to explicitly tell non-active tabs they are hidden.
287 // Without this call non-active tabs are not marked as backgrounded.
289 // NOTE: We need to do this here rather than when the tab is added to
290 // the Browser as at that time not everything has been created, so that
291 // the call would do nothing.
292 contents
->WasHidden();
297 if (!tabs_to_load_
.empty()) {
298 force_load_timer_
.Stop();
299 // Each time we load a tab we also set a timer to force us to start loading
300 // the next tab if this one doesn't load quickly enough.
301 force_load_timer_
.Start(FROM_HERE
,
302 base::TimeDelta::FromMilliseconds(force_load_delay_
),
303 this, &TabLoader::ForceLoadTimerFired
);
306 // When the session restore is done synchronously, notification is sent from
307 // SessionRestoreImpl::Restore .
308 if (tabs_to_load_
.empty() && !SessionRestore::IsRestoringSynchronously()) {
309 content::NotificationService::current()->Notify(
310 chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
311 content::NotificationService::AllSources(),
312 content::NotificationService::NoDetails());
316 void TabLoader::Observe(int type
,
317 const content::NotificationSource
& source
,
318 const content::NotificationDetails
& details
) {
320 case content::NOTIFICATION_LOAD_START
: {
321 // Add this render_widget_host to the set of those we're waiting for
322 // paints on. We want to only record stats for paints that occur after
323 // a load has finished.
324 NavigationController
* tab
=
325 content::Source
<NavigationController
>(source
).ptr();
326 RenderWidgetHost
* render_widget_host
= GetRenderWidgetHost(tab
);
327 DCHECK(render_widget_host
);
328 render_widget_hosts_loading_
.insert(render_widget_host
);
331 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED
: {
332 WebContents
* web_contents
= content::Source
<WebContents
>(source
).ptr();
333 if (!got_first_paint_
) {
334 RenderWidgetHost
* render_widget_host
=
335 GetRenderWidgetHost(&web_contents
->GetController());
336 render_widget_hosts_loading_
.erase(render_widget_host
);
338 HandleTabClosedOrLoaded(&web_contents
->GetController());
341 case content::NOTIFICATION_LOAD_STOP
: {
342 NavigationController
* tab
=
343 content::Source
<NavigationController
>(source
).ptr();
344 render_widget_hosts_to_paint_
.insert(GetRenderWidgetHost(tab
));
345 HandleTabClosedOrLoaded(tab
);
348 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
: {
349 RenderWidgetHost
* render_widget_host
=
350 content::Source
<RenderWidgetHost
>(source
).ptr();
351 if (!got_first_paint_
&& render_widget_host
->GetView() &&
352 render_widget_host
->GetView()->IsShowing()) {
353 if (render_widget_hosts_to_paint_
.find(render_widget_host
) !=
354 render_widget_hosts_to_paint_
.end()) {
355 // Got a paint for one of our renderers, so record time.
356 got_first_paint_
= true;
357 base::TimeDelta time_to_paint
=
358 base::TimeTicks::Now() - restore_started_
;
359 UMA_HISTOGRAM_CUSTOM_TIMES(
360 "SessionRestore.FirstTabPainted",
362 base::TimeDelta::FromMilliseconds(10),
363 base::TimeDelta::FromSeconds(100),
365 // Record a time for the number of tabs, to help track down
367 std::string time_for_count
=
368 base::StringPrintf("SessionRestore.FirstTabPainted_%d",
370 base::HistogramBase
* counter_for_count
=
371 base::Histogram::FactoryTimeGet(
373 base::TimeDelta::FromMilliseconds(10),
374 base::TimeDelta::FromSeconds(100),
376 base::Histogram::kUmaTargetedHistogramFlag
);
377 counter_for_count
->AddTime(time_to_paint
);
378 } else if (render_widget_hosts_loading_
.find(render_widget_host
) ==
379 render_widget_hosts_loading_
.end()) {
380 // If this is a host for a tab we're not loading some other tab
381 // has rendered and there's no point tracking the time. This could
382 // happen because the user opened a different tab or restored tabs
383 // to an already existing browser and an existing tab painted.
384 got_first_paint_
= true;
390 NOTREACHED() << "Unknown notification received:" << type
;
392 // Delete ourselves when we're not waiting for any more notifications. If this
393 // was not the last reference, a SessionRestoreImpl holding a reference will
394 // eventually call StartLoading (which assigns this_retainer_), or drop the
395 // reference without initiating a load.
396 if ((got_first_paint_
|| render_widget_hosts_to_paint_
.empty()) &&
397 tabs_loading_
.empty() && tabs_to_load_
.empty())
398 this_retainer_
= NULL
;
401 void TabLoader::OnConnectionTypeChanged(
402 net::NetworkChangeNotifier::ConnectionType type
) {
403 if (type
!= net::NetworkChangeNotifier::CONNECTION_NONE
) {
413 void TabLoader::RemoveTab(NavigationController
* tab
) {
414 registrar_
.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
415 content::Source
<WebContents
>(tab
->GetWebContents()));
416 registrar_
.Remove(this, content::NOTIFICATION_LOAD_STOP
,
417 content::Source
<NavigationController
>(tab
));
418 registrar_
.Remove(this, content::NOTIFICATION_LOAD_START
,
419 content::Source
<NavigationController
>(tab
));
421 TabsLoading::iterator i
= tabs_loading_
.find(tab
);
422 if (i
!= tabs_loading_
.end())
423 tabs_loading_
.erase(i
);
425 TabsToLoad::iterator j
=
426 find(tabs_to_load_
.begin(), tabs_to_load_
.end(), tab
);
427 if (j
!= tabs_to_load_
.end())
428 tabs_to_load_
.erase(j
);
431 void TabLoader::ForceLoadTimerFired() {
432 force_load_delay_
*= 2;
436 RenderWidgetHost
* TabLoader::GetRenderWidgetHost(NavigationController
* tab
) {
437 WebContents
* web_contents
= tab
->GetWebContents();
439 content::RenderWidgetHostView
* render_widget_host_view
=
440 web_contents
->GetRenderWidgetHostView();
441 if (render_widget_host_view
)
442 return render_widget_host_view
->GetRenderWidgetHost();
447 void TabLoader::RegisterForNotifications(NavigationController
* controller
) {
448 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
449 content::Source
<WebContents
>(controller
->GetWebContents()));
450 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
,
451 content::Source
<NavigationController
>(controller
));
452 registrar_
.Add(this, content::NOTIFICATION_LOAD_START
,
453 content::Source
<NavigationController
>(controller
));
457 void TabLoader::HandleTabClosedOrLoaded(NavigationController
* tab
) {
461 if (tabs_loading_
.empty() && tabs_to_load_
.empty()) {
462 base::TimeDelta time_to_load
=
463 base::TimeTicks::Now() - restore_started_
;
464 performance_monitor::StartupTimer::SetElapsedSessionRestoreTime(
466 UMA_HISTOGRAM_CUSTOM_TIMES(
467 "SessionRestore.AllTabsLoaded",
469 base::TimeDelta::FromMilliseconds(10),
470 base::TimeDelta::FromSeconds(100),
472 // Record a time for the number of tabs, to help track down contention.
473 std::string time_for_count
=
474 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_
);
475 base::HistogramBase
* counter_for_count
=
476 base::Histogram::FactoryTimeGet(
478 base::TimeDelta::FromMilliseconds(10),
479 base::TimeDelta::FromSeconds(100),
481 base::Histogram::kUmaTargetedHistogramFlag
);
482 counter_for_count
->AddTime(time_to_load
);
484 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
485 max_parallel_tab_loads_
);
489 void TabLoader::CheckNotObserving(NavigationController
* controller
) {
490 const bool in_tabs_to_load
=
491 find(tabs_to_load_
.begin(), tabs_to_load_
.end(), controller
) !=
493 const bool in_tabs_loading
=
494 find(tabs_loading_
.begin(), tabs_loading_
.end(), controller
) !=
496 const bool observing
=
497 registrar_
.IsRegistered(
498 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
499 content::Source
<WebContents
>(controller
->GetWebContents())) ||
500 registrar_
.IsRegistered(
501 this, content::NOTIFICATION_LOAD_STOP
,
502 content::Source
<NavigationController
>(controller
)) ||
503 registrar_
.IsRegistered(
504 this, content::NOTIFICATION_LOAD_START
,
505 content::Source
<NavigationController
>(controller
));
506 base::debug::Alias(&in_tabs_to_load
);
507 base::debug::Alias(&in_tabs_loading
);
508 base::debug::Alias(&observing
);
509 CHECK(!in_tabs_to_load
&& !in_tabs_loading
&& !observing
);
512 // SessionRestoreImpl ---------------------------------------------------------
514 // SessionRestoreImpl is responsible for fetching the set of tabs to create
515 // from SessionService. SessionRestoreImpl deletes itself when done.
517 class SessionRestoreImpl
: public content::NotificationObserver
{
519 SessionRestoreImpl(Profile
* profile
,
521 chrome::HostDesktopType host_desktop_type
,
523 bool clobber_existing_tab
,
524 bool always_create_tabbed_browser
,
525 const std::vector
<GURL
>& urls_to_open
)
528 host_desktop_type_(host_desktop_type
),
529 synchronous_(synchronous
),
530 clobber_existing_tab_(clobber_existing_tab
),
531 always_create_tabbed_browser_(always_create_tabbed_browser
),
532 urls_to_open_(urls_to_open
),
533 active_window_id_(0),
534 restore_started_(base::TimeTicks::Now()),
535 browser_shown_(false) {
536 // For sanity's sake, if |browser| is non-null: force |host_desktop_type| to
537 // be the same as |browser|'s desktop type.
538 DCHECK(!browser
|| browser
->host_desktop_type() == host_desktop_type
);
540 if (active_session_restorers
== NULL
)
541 active_session_restorers
= new std::set
<SessionRestoreImpl
*>();
543 // Only one SessionRestoreImpl should be operating on the profile at the
545 std::set
<SessionRestoreImpl
*>::const_iterator it
;
546 for (it
= active_session_restorers
->begin();
547 it
!= active_session_restorers
->end(); ++it
) {
548 if ((*it
)->profile_
== profile
)
551 DCHECK(it
== active_session_restorers
->end());
553 active_session_restorers
->insert(this);
555 // When asynchronous its possible for there to be no windows. To make sure
556 // Chrome doesn't prematurely exit AddRef the process. We'll release in the
557 // destructor when restore is done.
558 g_browser_process
->AddRefModule();
561 bool synchronous() const { return synchronous_
; }
564 SessionService
* session_service
=
565 SessionServiceFactory::GetForProfile(profile_
);
566 DCHECK(session_service
);
567 session_service
->GetLastSession(
568 base::Bind(&SessionRestoreImpl::OnGotSession
, base::Unretained(this)),
569 &cancelable_task_tracker_
);
573 base::MessageLoop::ScopedNestableTaskAllower
allow(
574 base::MessageLoop::current());
576 quit_closure_for_sync_restore_
= loop
.QuitClosure();
578 quit_closure_for_sync_restore_
= base::Closure();
580 Browser
* browser
= ProcessSessionWindows(&windows_
, active_window_id_
);
582 content::NotificationService::current()->Notify(
583 chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
584 content::NotificationService::AllSources(),
585 content::NotificationService::NoDetails());
590 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED
,
591 content::Source
<Browser
>(browser_
));
597 // Restore window(s) from a foreign session. Returns newly created Browsers.
598 std::vector
<Browser
*> RestoreForeignSession(
599 std::vector
<const SessionWindow
*>::const_iterator begin
,
600 std::vector
<const SessionWindow
*>::const_iterator end
) {
602 std::vector
<Browser
*> browsers
;
603 // Create a browser instance to put the restored tabs in.
604 for (std::vector
<const SessionWindow
*>::const_iterator i
= begin
;
606 Browser
* browser
= CreateRestoredBrowser(
607 static_cast<Browser::Type
>((*i
)->type
),
611 browsers
.push_back(browser
);
613 // Restore and show the browser.
614 const int initial_tab_count
= 0;
615 int selected_tab_index
= std::max(
617 std::min((*i
)->selected_tab_index
,
618 static_cast<int>((*i
)->tabs
.size()) - 1));
619 RestoreTabsToBrowser(*(*i
), browser
, initial_tab_count
,
621 NotifySessionServiceOfRestoredTabs(browser
, initial_tab_count
);
624 // Always create in a new window
625 FinishedTabCreation(true, true);
629 // Restore a single tab from a foreign session.
630 // Opens in the tab in the last active browser, unless disposition is
631 // NEW_WINDOW, in which case the tab will be opened in a new browser. Returns
632 // the WebContents of the restored tab.
633 WebContents
* RestoreForeignTab(const SessionTab
& tab
,
634 WindowOpenDisposition disposition
) {
635 DCHECK(!tab
.navigations
.empty());
636 int selected_index
= tab
.current_navigation_index
;
637 selected_index
= std::max(
639 std::min(selected_index
,
640 static_cast<int>(tab
.navigations
.size() - 1)));
642 bool use_new_window
= disposition
== NEW_WINDOW
;
644 Browser
* browser
= use_new_window
?
645 new Browser(Browser::CreateParams(profile_
, host_desktop_type_
)) :
648 RecordAppLaunchForTab(browser
, tab
, selected_index
);
650 WebContents
* web_contents
;
651 if (disposition
== CURRENT_TAB
) {
652 DCHECK(!use_new_window
);
653 web_contents
= chrome::ReplaceRestoredTab(browser
,
657 tab
.extension_app_id
,
659 tab
.user_agent_override
);
662 use_new_window
? 0 : browser
->tab_strip_model()->active_index() + 1;
663 web_contents
= chrome::AddRestoredTab(
668 tab
.extension_app_id
,
669 disposition
== NEW_FOREGROUND_TAB
, // selected
673 tab
.user_agent_override
);
674 // Start loading the tab immediately.
675 web_contents
->GetController().LoadIfNecessary();
678 if (use_new_window
) {
679 browser
->tab_strip_model()->ActivateTabAt(0, true);
680 browser
->window()->Show();
682 NotifySessionServiceOfRestoredTabs(browser
,
683 browser
->tab_strip_model()->count());
685 // Since FinishedTabCreation() is not called here, |this| will leak if we
686 // are not in sychronous mode.
687 DCHECK(synchronous_
);
691 virtual ~SessionRestoreImpl() {
692 STLDeleteElements(&windows_
);
694 active_session_restorers
->erase(this);
695 if (active_session_restorers
->empty()) {
696 delete active_session_restorers
;
697 active_session_restorers
= NULL
;
700 g_browser_process
->ReleaseModule();
703 virtual void Observe(int type
,
704 const content::NotificationSource
& source
,
705 const content::NotificationDetails
& details
) OVERRIDE
{
707 case chrome::NOTIFICATION_BROWSER_CLOSED
:
717 Profile
* profile() { return profile_
; }
720 // Invoked when beginning to create new tabs. Resets the tab_loader_.
721 void StartTabCreation() {
722 tab_loader_
= TabLoader::GetTabLoader(restore_started_
);
725 // Invoked when done with creating all the tabs/browsers.
727 // |created_tabbed_browser| indicates whether a tabbed browser was created,
728 // or we used an existing tabbed browser.
730 // If successful, this begins loading tabs and deletes itself when all tabs
733 // Returns the Browser that was created, if any.
734 Browser
* FinishedTabCreation(bool succeeded
, bool created_tabbed_browser
) {
735 Browser
* browser
= NULL
;
736 if (!created_tabbed_browser
&& always_create_tabbed_browser_
) {
737 browser
= new Browser(Browser::CreateParams(profile_
,
738 host_desktop_type_
));
739 if (urls_to_open_
.empty()) {
740 // No tab browsers were created and no URLs were supplied on the command
741 // line. Open the new tab page.
742 urls_to_open_
.push_back(GURL(chrome::kChromeUINewTabURL
));
744 AppendURLsToBrowser(browser
, urls_to_open_
);
745 browser
->window()->Show();
749 DCHECK(tab_loader_
.get());
750 // TabLoader deletes itself when done loading.
751 tab_loader_
->StartLoading();
756 // If we're not synchronous we need to delete ourself.
757 // NOTE: we must use DeleteLater here as most likely we're in a callback
758 // from the history service which doesn't deal well with deleting the
759 // object it is notifying.
760 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
762 // The delete may take a while and at this point we no longer care about
763 // if the browser is deleted. Don't listen to anything. This avoid a
764 // possible double delete too (if browser is closed before DeleteSoon() is
766 registrar_
.RemoveAll();
769 #if defined(OS_CHROMEOS)
770 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
771 "SessionRestore-End", false);
776 void OnGotSession(ScopedVector
<SessionWindow
> windows
,
777 SessionID::id_type active_window_id
) {
778 base::TimeDelta time_to_got_sessions
=
779 base::TimeTicks::Now() - restore_started_
;
780 UMA_HISTOGRAM_CUSTOM_TIMES(
781 "SessionRestore.TimeToGotSessions",
782 time_to_got_sessions
,
783 base::TimeDelta::FromMilliseconds(10),
784 base::TimeDelta::FromSeconds(1000),
786 #if defined(OS_CHROMEOS)
787 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
788 "SessionRestore-GotSession", false);
791 // See comment above windows_ as to why we don't process immediately.
792 windows_
.swap(windows
.get());
793 active_window_id_
= active_window_id
;
794 CHECK(!quit_closure_for_sync_restore_
.is_null());
795 quit_closure_for_sync_restore_
.Run();
799 ProcessSessionWindows(&windows
.get(), active_window_id
);
802 Browser
* ProcessSessionWindows(std::vector
<SessionWindow
*>* windows
,
803 SessionID::id_type active_window_id
) {
804 VLOG(1) << "ProcessSessionWindows " << windows
->size();
805 base::TimeDelta time_to_process_sessions
=
806 base::TimeTicks::Now() - restore_started_
;
807 UMA_HISTOGRAM_CUSTOM_TIMES(
808 "SessionRestore.TimeToProcessSessions",
809 time_to_process_sessions
,
810 base::TimeDelta::FromMilliseconds(10),
811 base::TimeDelta::FromSeconds(1000),
814 if (windows
->empty()) {
815 // Restore was unsuccessful. The DOM storage system can also delete its
816 // data, since no session restore will happen at a later point in time.
817 content::BrowserContext::GetDefaultStoragePartition(profile_
)->
818 GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
819 return FinishedTabCreation(false, false);
822 #if defined(OS_CHROMEOS)
823 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
824 "SessionRestore-CreatingTabs-Start", false);
828 // After the for loop this contains the last TABBED_BROWSER. Is null if no
829 // tabbed browsers exist.
830 Browser
* last_browser
= NULL
;
831 bool has_tabbed_browser
= false;
833 // After the for loop, this contains the browser to activate, if one of the
834 // windows has the same id as specified in active_window_id.
835 Browser
* browser_to_activate
= NULL
;
837 int selected_tab_to_activate
= -1;
840 // Determine if there is a visible window.
841 bool has_visible_browser
= false;
842 for (std::vector
<SessionWindow
*>::iterator i
= windows
->begin();
843 i
!= windows
->end(); ++i
) {
844 if ((*i
)->show_state
!= ui::SHOW_STATE_MINIMIZED
)
845 has_visible_browser
= true;
848 for (std::vector
<SessionWindow
*>::iterator i
= windows
->begin();
849 i
!= windows
->end(); ++i
) {
850 Browser
* browser
= NULL
;
851 if (!has_tabbed_browser
&& (*i
)->type
== Browser::TYPE_TABBED
)
852 has_tabbed_browser
= true;
853 if (i
== windows
->begin() && (*i
)->type
== Browser::TYPE_TABBED
&&
854 browser_
&& browser_
->is_type_tabbed() &&
855 !browser_
->profile()->IsOffTheRecord()) {
856 // The first set of tabs is added to the existing browser.
859 #if defined(OS_CHROMEOS)
860 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
861 "SessionRestore-CreateRestoredBrowser-Start", false);
863 // Show the first window if none are visible.
864 ui::WindowShowState show_state
= (*i
)->show_state
;
865 if (!has_visible_browser
) {
866 show_state
= ui::SHOW_STATE_NORMAL
;
867 has_visible_browser
= true;
869 browser
= CreateRestoredBrowser(
870 static_cast<Browser::Type
>((*i
)->type
),
874 #if defined(OS_CHROMEOS)
875 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
876 "SessionRestore-CreateRestoredBrowser-End", false);
879 if ((*i
)->type
== Browser::TYPE_TABBED
)
880 last_browser
= browser
;
881 WebContents
* active_tab
=
882 browser
->tab_strip_model()->GetActiveWebContents();
883 int initial_tab_count
= browser
->tab_strip_model()->count();
884 bool close_active_tab
= clobber_existing_tab_
&&
885 i
== windows
->begin() &&
886 (*i
)->type
== Browser::TYPE_TABBED
&&
887 active_tab
&& browser
== browser_
&&
888 (*i
)->tabs
.size() > 0;
889 if (close_active_tab
)
891 int selected_tab_index
=
892 initial_tab_count
> 0 ? browser
->tab_strip_model()->active_index()
894 std::min((*i
)->selected_tab_index
,
895 static_cast<int>((*i
)->tabs
.size()) - 1));
896 if ((*i
)->window_id
.id() == active_window_id
) {
897 browser_to_activate
= browser
;
899 selected_tab_to_activate
= selected_tab_index
;
902 RestoreTabsToBrowser(*(*i
), browser
, initial_tab_count
,
904 NotifySessionServiceOfRestoredTabs(browser
, initial_tab_count
);
905 // This needs to be done after restore because closing the last tab will
906 // close the whole window.
907 if (close_active_tab
)
908 chrome::CloseWebContents(browser
, active_tab
, true);
910 selected_tab_to_activate
= -1;
914 if (browser_to_activate
&& browser_to_activate
->is_type_tabbed())
915 last_browser
= browser_to_activate
;
917 if (last_browser
&& !urls_to_open_
.empty())
918 AppendURLsToBrowser(last_browser
, urls_to_open_
);
919 #if defined(OS_CHROMEOS)
920 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
921 "SessionRestore-CreatingTabs-End", false);
923 if (browser_to_activate
)
924 browser_to_activate
->window()->Activate();
926 // If last_browser is NULL and urls_to_open_ is non-empty,
927 // FinishedTabCreation will create a new TabbedBrowser and add the urls to
929 Browser
* finished_browser
= FinishedTabCreation(true, has_tabbed_browser
);
930 if (finished_browser
)
931 last_browser
= finished_browser
;
933 // sessionStorages needed for the session restore have now been recreated
934 // by RestoreTab. Now it's safe for the DOM storage system to start
935 // deleting leftover data.
936 content::BrowserContext::GetDefaultStoragePartition(profile_
)->
937 GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
941 // Record an app launch event (if appropriate) for a tab which is about to
942 // be restored. Callers should ensure that selected_index is within the
943 // bounds of tab.navigations before calling.
944 void RecordAppLaunchForTab(Browser
* browser
,
945 const SessionTab
& tab
,
946 int selected_index
) {
947 DCHECK(selected_index
>= 0 &&
948 selected_index
< static_cast<int>(tab
.navigations
.size()));
949 GURL url
= tab
.navigations
[selected_index
].virtual_url();
950 const extensions::Extension
* extension
=
951 extensions::ExtensionRegistry::Get(profile())
952 ->enabled_extensions().GetAppByURL(url
);
954 CoreAppLauncherHandler::RecordAppLaunchType(
955 extension_misc::APP_LAUNCH_SESSION_RESTORE
,
956 extension
->GetType());
960 // Adds the tabs from |window| to |browser|. Normal tabs go after the existing
961 // tabs but pinned tabs will be pushed in front.
962 // If there are no existing tabs, the tab at |selected_tab_index| will be
963 // selected. Otherwise, the tab selection will remain untouched.
964 void RestoreTabsToBrowser(const SessionWindow
& window
,
966 int initial_tab_count
,
967 int selected_tab_index
) {
968 VLOG(1) << "RestoreTabsToBrowser " << window
.tabs
.size();
969 DCHECK(!window
.tabs
.empty());
970 if (initial_tab_count
== 0) {
971 for (int i
= 0; i
< static_cast<int>(window
.tabs
.size()); ++i
) {
972 const SessionTab
& tab
= *(window
.tabs
[i
]);
974 // Loads are scheduled for each restored tab unless the tab is going to
975 // be selected as ShowBrowser() will load the selected tab.
976 bool is_selected_tab
= (i
== selected_tab_index
);
977 WebContents
* restored_tab
=
978 RestoreTab(tab
, i
, browser
, is_selected_tab
);
980 // RestoreTab can return NULL if |tab| doesn't have valid data.
984 // If this isn't the selected tab, there's nothing else to do.
985 if (!is_selected_tab
)
990 browser
->tab_strip_model()->GetIndexOfWebContents(restored_tab
));
991 // TODO(sky): remove. For debugging 368236.
992 CHECK_EQ(browser
->tab_strip_model()->GetActiveWebContents(),
994 tab_loader_
->TabIsLoading(&browser
->tab_strip_model()
995 ->GetActiveWebContents()
999 // If the browser already has tabs, we want to restore the new ones after
1000 // the existing ones. E.g. this happens in Win8 Metro where we merge
1001 // windows or when launching a hosted app from the app launcher.
1002 int tab_index_offset
= initial_tab_count
;
1003 for (int i
= 0; i
< static_cast<int>(window
.tabs
.size()); ++i
) {
1004 const SessionTab
& tab
= *(window
.tabs
[i
]);
1005 // Always schedule loads as we will not be calling ShowBrowser().
1006 RestoreTab(tab
, tab_index_offset
+ i
, browser
, false);
1011 // |tab_index| is ignored for pinned tabs which will always be pushed behind
1012 // the last existing pinned tab.
1013 // |tab_loader_| will schedule this tab for loading if |is_selected_tab| is
1015 WebContents
* RestoreTab(const SessionTab
& tab
,
1016 const int tab_index
,
1018 bool is_selected_tab
) {
1019 // It's possible (particularly for foreign sessions) to receive a tab
1020 // without valid navigations. In that case, just skip it.
1021 // See crbug.com/154129.
1022 if (tab
.navigations
.empty())
1024 int selected_index
= tab
.current_navigation_index
;
1025 selected_index
= std::max(
1027 std::min(selected_index
,
1028 static_cast<int>(tab
.navigations
.size() - 1)));
1030 RecordAppLaunchForTab(browser
, tab
, selected_index
);
1032 // Associate sessionStorage (if any) to the restored tab.
1033 scoped_refptr
<content::SessionStorageNamespace
> session_storage_namespace
;
1034 if (!tab
.session_storage_persistent_id
.empty()) {
1035 session_storage_namespace
=
1036 content::BrowserContext::GetDefaultStoragePartition(profile_
)->
1037 GetDOMStorageContext()->RecreateSessionStorage(
1038 tab
.session_storage_persistent_id
);
1041 WebContents
* web_contents
=
1042 chrome::AddRestoredTab(browser
,
1046 tab
.extension_app_id
,
1050 session_storage_namespace
.get(),
1051 tab
.user_agent_override
);
1052 // Regression check: check that the tab didn't start loading right away. The
1053 // focused tab will be loaded by Browser, and TabLoader will load the rest.
1054 DCHECK(web_contents
->GetController().NeedsReload());
1056 // Set up the file access rights for the selected navigation entry.
1057 const int id
= web_contents
->GetRenderProcessHost()->GetID();
1058 const content::PageState
& page_state
=
1059 tab
.navigations
.at(selected_index
).page_state();
1060 const std::vector
<base::FilePath
>& file_paths
=
1061 page_state
.GetReferencedFiles();
1062 for (std::vector
<base::FilePath
>::const_iterator file
= file_paths
.begin();
1063 file
!= file_paths
.end(); ++file
) {
1064 content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id
,
1068 if (!is_selected_tab
)
1069 tab_loader_
->ScheduleLoad(&web_contents
->GetController());
1070 return web_contents
;
1073 Browser
* CreateRestoredBrowser(Browser::Type type
,
1075 ui::WindowShowState show_state
,
1076 const std::string
& app_name
) {
1077 Browser::CreateParams
params(type
, profile_
, host_desktop_type_
);
1078 if (!app_name
.empty()) {
1079 const bool trusted_source
= true; // We only store trusted app windows.
1080 params
= Browser::CreateParams::CreateForApp(app_name
,
1084 host_desktop_type_
);
1086 params
.initial_bounds
= bounds
;
1088 params
.initial_show_state
= show_state
;
1089 params
.is_session_restore
= true;
1090 return new Browser(params
);
1093 void ShowBrowser(Browser
* browser
, int selected_tab_index
) {
1095 DCHECK(browser
->tab_strip_model()->count());
1096 browser
->tab_strip_model()->ActivateTabAt(selected_tab_index
, true);
1098 if (browser_
== browser
)
1101 browser
->window()->Show();
1102 browser
->set_is_session_restore(false);
1104 // TODO(jcampan): http://crbug.com/8123 we should not need to set the
1105 // initial focus explicitly.
1106 browser
->tab_strip_model()->GetActiveWebContents()->SetInitialFocus();
1108 if (!browser_shown_
) {
1109 browser_shown_
= true;
1110 base::TimeDelta time_to_first_show
=
1111 base::TimeTicks::Now() - restore_started_
;
1112 UMA_HISTOGRAM_CUSTOM_TIMES(
1113 "SessionRestore.TimeToFirstShow",
1115 base::TimeDelta::FromMilliseconds(10),
1116 base::TimeDelta::FromSeconds(1000),
1121 // Appends the urls in |urls| to |browser|.
1122 void AppendURLsToBrowser(Browser
* browser
,
1123 const std::vector
<GURL
>& urls
) {
1124 for (size_t i
= 0; i
< urls
.size(); ++i
) {
1125 int add_types
= TabStripModel::ADD_FORCE_INDEX
;
1127 add_types
|= TabStripModel::ADD_ACTIVE
;
1128 chrome::NavigateParams
params(browser
, urls
[i
],
1129 content::PAGE_TRANSITION_AUTO_TOPLEVEL
);
1130 params
.disposition
= i
== 0 ? NEW_FOREGROUND_TAB
: NEW_BACKGROUND_TAB
;
1131 params
.tabstrip_add_types
= add_types
;
1132 chrome::Navigate(¶ms
);
1136 // Invokes TabRestored on the SessionService for all tabs in browser after
1138 void NotifySessionServiceOfRestoredTabs(Browser
* browser
, int initial_count
) {
1139 SessionService
* session_service
=
1140 SessionServiceFactory::GetForProfile(profile_
);
1141 if (!session_service
)
1143 TabStripModel
* tab_strip
= browser
->tab_strip_model();
1144 for (int i
= initial_count
; i
< tab_strip
->count(); ++i
)
1145 session_service
->TabRestored(tab_strip
->GetWebContentsAt(i
),
1146 tab_strip
->IsTabPinned(i
));
1149 // The profile to create the sessions for.
1152 // The first browser to restore to, may be null.
1155 // The desktop on which all new browsers should be created (browser_, if it is
1156 // not NULL, must be of this desktop type as well).
1157 chrome::HostDesktopType host_desktop_type_
;
1159 // Whether or not restore is synchronous.
1160 const bool synchronous_
;
1162 // The quit-closure to terminate the nested message-loop started for
1163 // synchronous session-restore.
1164 base::Closure quit_closure_for_sync_restore_
;
1166 // See description of CLOBBER_CURRENT_TAB.
1167 const bool clobber_existing_tab_
;
1169 // If true and there is an error or there are no windows to restore, we
1170 // create a tabbed browser anyway. This is used on startup to make sure at
1171 // at least one window is created.
1172 const bool always_create_tabbed_browser_
;
1174 // Set of URLs to open in addition to those restored from the session.
1175 std::vector
<GURL
> urls_to_open_
;
1177 // Used to get the session.
1178 base::CancelableTaskTracker cancelable_task_tracker_
;
1180 // Responsible for loading the tabs.
1181 scoped_refptr
<TabLoader
> tab_loader_
;
1183 // When synchronous we run a nested message loop. To avoid creating windows
1184 // from the nested message loop (which can make exiting the nested message
1185 // loop take a while) we cache the SessionWindows here and create the actual
1186 // windows when the nested message loop exits.
1187 std::vector
<SessionWindow
*> windows_
;
1188 SessionID::id_type active_window_id_
;
1190 content::NotificationRegistrar registrar_
;
1192 // The time we started the restore.
1193 base::TimeTicks restore_started_
;
1195 // Set to true after the first browser is shown.
1196 bool browser_shown_
;
1198 DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl
);
1203 // SessionRestore -------------------------------------------------------------
1206 Browser
* SessionRestore::RestoreSession(
1209 chrome::HostDesktopType host_desktop_type
,
1211 const std::vector
<GURL
>& urls_to_open
) {
1212 #if defined(OS_CHROMEOS)
1213 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1214 "SessionRestore-Start", false);
1217 // Always restore from the original profile (incognito profiles have no
1218 // session service).
1219 profile
= profile
->GetOriginalProfile();
1220 if (!SessionServiceFactory::GetForProfile(profile
)) {
1224 profile
->set_restored_last_session(true);
1225 // SessionRestoreImpl takes care of deleting itself when done.
1226 SessionRestoreImpl
* restorer
= new SessionRestoreImpl(
1227 profile
, browser
, host_desktop_type
, (behavior
& SYNCHRONOUS
) != 0,
1228 (behavior
& CLOBBER_CURRENT_TAB
) != 0,
1229 (behavior
& ALWAYS_CREATE_TABBED_BROWSER
) != 0,
1231 return restorer
->Restore();
1235 void SessionRestore::RestoreSessionAfterCrash(Browser
* browser
) {
1236 uint32 behavior
= 0;
1237 if (browser
->tab_strip_model()->count() == 1) {
1238 const content::WebContents
* active_tab
=
1239 browser
->tab_strip_model()->GetWebContentsAt(0);
1240 if (active_tab
->GetURL() == GURL(chrome::kChromeUINewTabURL
) ||
1241 chrome::IsInstantNTP(active_tab
)) {
1242 // There is only one tab and its the new tab page, make session restore
1244 behavior
= SessionRestore::CLOBBER_CURRENT_TAB
;
1247 SessionRestore::RestoreSession(browser
->profile(), browser
,
1248 browser
->host_desktop_type(), behavior
,
1249 std::vector
<GURL
>());
1253 std::vector
<Browser
*> SessionRestore::RestoreForeignSessionWindows(
1255 chrome::HostDesktopType host_desktop_type
,
1256 std::vector
<const SessionWindow
*>::const_iterator begin
,
1257 std::vector
<const SessionWindow
*>::const_iterator end
) {
1258 std::vector
<GURL
> gurls
;
1259 SessionRestoreImpl
restorer(profile
,
1260 static_cast<Browser
*>(NULL
), host_desktop_type
, true, false, true, gurls
);
1261 return restorer
.RestoreForeignSession(begin
, end
);
1265 WebContents
* SessionRestore::RestoreForeignSessionTab(
1266 content::WebContents
* source_web_contents
,
1267 const SessionTab
& tab
,
1268 WindowOpenDisposition disposition
) {
1269 Browser
* browser
= chrome::FindBrowserWithWebContents(source_web_contents
);
1270 Profile
* profile
= browser
->profile();
1271 std::vector
<GURL
> gurls
;
1272 SessionRestoreImpl
restorer(profile
, browser
, browser
->host_desktop_type(),
1273 true, false, false, gurls
);
1274 return restorer
.RestoreForeignTab(tab
, disposition
);
1278 bool SessionRestore::IsRestoring(const Profile
* profile
) {
1279 if (active_session_restorers
== NULL
)
1281 for (std::set
<SessionRestoreImpl
*>::const_iterator it
=
1282 active_session_restorers
->begin();
1283 it
!= active_session_restorers
->end(); ++it
) {
1284 if ((*it
)->profile() == profile
)
1291 bool SessionRestore::IsRestoringSynchronously() {
1292 if (!active_session_restorers
)
1294 for (std::set
<SessionRestoreImpl
*>::const_iterator it
=
1295 active_session_restorers
->begin();
1296 it
!= active_session_restorers
->end(); ++it
) {
1297 if ((*it
)->synchronous())