Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sessions / session_restore.cc
blobe6e4af4c1a899c35ef1c01cb8a65debcfc7e4d16
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"
7 #include <algorithm>
8 #include <list>
9 #include <set>
10 #include <string>
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"
55 #endif
57 #if defined(OS_WIN)
58 #include "win8/util/win8_util.h"
59 #endif
61 using content::NavigationController;
62 using content::RenderWidgetHost;
63 using content::WebContents;
65 namespace {
67 class SessionRestoreImpl;
68 class TabLoader;
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
84 // doubled.
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> {
96 public:
97 // Retrieves a pointer to the TabLoader instance shared between profiles, or
98 // creates a new TabLoader if it doesn't exist. If a TabLoader is created, its
99 // starting timestamp is set to |restore_started|.
100 static TabLoader* GetTabLoader(base::TimeTicks restore_started);
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.
112 void StartLoading();
114 private:
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.
126 void LoadNextTab();
128 // NotificationObserver method. Removes the specified tab and loads the next
129 // tab.
130 virtual void Observe(int type,
131 const content::NotificationSource& source,
132 const content::NotificationDetails& details) OVERRIDE;
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
140 // from.
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,
148 // NULL otherwise.
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
160 // details.
161 int64 force_load_delay_;
163 // Has Load been invoked?
164 bool loading_;
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
170 // selected tabs.
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.
183 int tab_count_;
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);
200 // static
201 TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) {
202 if (!shared_tab_loader)
203 shared_tab_loader = new TabLoader(restore_started);
204 return shared_tab_loader;
207 void TabLoader::ScheduleLoad(NavigationController* controller) {
208 DCHECK(controller);
209 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
210 tabs_to_load_.end());
211 tabs_to_load_.push_back(controller);
212 RegisterForNotifications(controller);
215 void TabLoader::TabIsLoading(NavigationController* controller) {
216 DCHECK(controller);
217 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
218 tabs_loading_.end());
219 tabs_loading_.insert(controller);
220 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
221 DCHECK(render_widget_host);
222 render_widget_hosts_loading_.insert(render_widget_host);
223 RegisterForNotifications(controller);
226 void TabLoader::StartLoading() {
227 // When multiple profiles are using the same TabLoader, another profile might
228 // already have started loading. In that case, the tabs scheduled for loading
229 // by this profile are already in the loading queue, and they will get loaded
230 // eventually.
231 if (loading_)
232 return;
233 registrar_.Add(
234 this,
235 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
236 content::NotificationService::AllSources());
237 this_retainer_ = this;
238 #if defined(OS_CHROMEOS)
239 if (!net::NetworkChangeNotifier::IsOffline()) {
240 loading_ = true;
241 LoadNextTab();
242 } else {
243 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
245 #else
246 loading_ = true;
247 LoadNextTab();
248 #endif
251 TabLoader::TabLoader(base::TimeTicks restore_started)
252 : force_load_delay_(kInitialDelayTimerMS),
253 loading_(false),
254 got_first_paint_(false),
255 tab_count_(0),
256 restore_started_(restore_started),
257 max_parallel_tab_loads_(0) {
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();
270 DCHECK(tab);
271 tabs_loading_.insert(tab);
272 if (tabs_loading_.size() > max_parallel_tab_loads_)
273 max_parallel_tab_loads_ = tabs_loading_.size();
274 tabs_to_load_.pop_front();
275 tab->LoadIfNecessary();
276 content::WebContents* contents = tab->GetWebContents();
277 if (contents) {
278 Browser* browser = chrome::FindBrowserWithWebContents(contents);
279 if (browser &&
280 browser->tab_strip_model()->GetActiveWebContents() != contents) {
281 // By default tabs are marked as visible. As only the active tab is
282 // visible we need to explicitly tell non-active tabs they are hidden.
283 // Without this call non-active tabs are not marked as backgrounded.
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) {
315 switch (type) {
316 case content::NOTIFICATION_LOAD_START: {
317 // Add this render_widget_host to the set of those we're waiting for
318 // paints on. We want to only record stats for paints that occur after
319 // a load has finished.
320 NavigationController* tab =
321 content::Source<NavigationController>(source).ptr();
322 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab);
323 DCHECK(render_widget_host);
324 render_widget_hosts_loading_.insert(render_widget_host);
325 break;
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());
335 break;
337 case content::NOTIFICATION_LOAD_STOP: {
338 NavigationController* tab =
339 content::Source<NavigationController>(source).ptr();
340 render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab));
341 HandleTabClosedOrLoaded(tab);
342 break;
344 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
345 RenderWidgetHost* render_widget_host =
346 content::Source<RenderWidgetHost>(source).ptr();
347 if (!got_first_paint_ && render_widget_host->GetView() &&
348 render_widget_host->GetView()->IsShowing()) {
349 if (render_widget_hosts_to_paint_.find(render_widget_host) !=
350 render_widget_hosts_to_paint_.end()) {
351 // Got a paint for one of our renderers, so record time.
352 got_first_paint_ = true;
353 base::TimeDelta time_to_paint =
354 base::TimeTicks::Now() - restore_started_;
355 UMA_HISTOGRAM_CUSTOM_TIMES(
356 "SessionRestore.FirstTabPainted",
357 time_to_paint,
358 base::TimeDelta::FromMilliseconds(10),
359 base::TimeDelta::FromSeconds(100),
360 100);
361 // Record a time for the number of tabs, to help track down
362 // contention.
363 std::string time_for_count =
364 base::StringPrintf("SessionRestore.FirstTabPainted_%d",
365 tab_count_);
366 base::HistogramBase* counter_for_count =
367 base::Histogram::FactoryTimeGet(
368 time_for_count,
369 base::TimeDelta::FromMilliseconds(10),
370 base::TimeDelta::FromSeconds(100),
371 100,
372 base::Histogram::kUmaTargetedHistogramFlag);
373 counter_for_count->AddTime(time_to_paint);
374 } else if (render_widget_hosts_loading_.find(render_widget_host) ==
375 render_widget_hosts_loading_.end()) {
376 // If this is a host for a tab we're not loading some other tab
377 // has rendered and there's no point tracking the time. This could
378 // happen because the user opened a different tab or restored tabs
379 // to an already existing browser and an existing tab painted.
380 got_first_paint_ = true;
383 break;
385 default:
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) {
400 if (!loading_) {
401 loading_ = true;
402 LoadNextTab();
404 } else {
405 loading_ = false;
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;
429 LoadNextTab();
432 RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
433 WebContents* web_contents = tab->GetWebContents();
434 if (web_contents) {
435 content::RenderWidgetHostView* render_widget_host_view =
436 web_contents->GetRenderWidgetHostView();
437 if (render_widget_host_view)
438 return render_widget_host_view->GetRenderWidgetHost();
440 return NULL;
443 void TabLoader::RegisterForNotifications(NavigationController* controller) {
444 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
445 content::Source<WebContents>(controller->GetWebContents()));
446 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
447 content::Source<NavigationController>(controller));
448 registrar_.Add(this, content::NOTIFICATION_LOAD_START,
449 content::Source<NavigationController>(controller));
450 ++tab_count_;
453 void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
454 RemoveTab(tab);
455 if (loading_)
456 LoadNextTab();
457 if (tabs_loading_.empty() && tabs_to_load_.empty()) {
458 base::TimeDelta time_to_load =
459 base::TimeTicks::Now() - restore_started_;
460 performance_monitor::StartupTimer::SetElapsedSessionRestoreTime(
461 time_to_load);
462 UMA_HISTOGRAM_CUSTOM_TIMES(
463 "SessionRestore.AllTabsLoaded",
464 time_to_load,
465 base::TimeDelta::FromMilliseconds(10),
466 base::TimeDelta::FromSeconds(100),
467 100);
468 // Record a time for the number of tabs, to help track down contention.
469 std::string time_for_count =
470 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_);
471 base::HistogramBase* counter_for_count =
472 base::Histogram::FactoryTimeGet(
473 time_for_count,
474 base::TimeDelta::FromMilliseconds(10),
475 base::TimeDelta::FromSeconds(100),
476 100,
477 base::Histogram::kUmaTargetedHistogramFlag);
478 counter_for_count->AddTime(time_to_load);
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 {
491 public:
492 SessionRestoreImpl(Profile* profile,
493 Browser* browser,
494 chrome::HostDesktopType host_desktop_type,
495 bool synchronous,
496 bool clobber_existing_tab,
497 bool always_create_tabbed_browser,
498 const std::vector<GURL>& urls_to_open)
499 : profile_(profile),
500 browser_(browser),
501 host_desktop_type_(host_desktop_type),
502 synchronous_(synchronous),
503 clobber_existing_tab_(clobber_existing_tab),
504 always_create_tabbed_browser_(always_create_tabbed_browser),
505 urls_to_open_(urls_to_open),
506 active_window_id_(0),
507 restore_started_(base::TimeTicks::Now()),
508 browser_shown_(false) {
509 // For sanity's sake, if |browser| is non-null: force |host_desktop_type| to
510 // be the same as |browser|'s desktop type.
511 DCHECK(!browser || browser->host_desktop_type() == host_desktop_type);
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
517 // same time.
518 std::set<SessionRestoreImpl*>::const_iterator it;
519 for (it = active_session_restorers->begin();
520 it != active_session_restorers->end(); ++it) {
521 if ((*it)->profile_ == profile)
522 break;
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_; }
536 Browser* Restore() {
537 SessionService* session_service =
538 SessionServiceFactory::GetForProfile(profile_);
539 DCHECK(session_service);
540 session_service->GetLastSession(
541 base::Bind(&SessionRestoreImpl::OnGotSession, base::Unretained(this)),
542 &cancelable_task_tracker_);
544 if (synchronous_) {
546 base::MessageLoop::ScopedNestableTaskAllower allow(
547 base::MessageLoop::current());
548 base::MessageLoop::current()->Run();
550 Browser* browser = ProcessSessionWindows(&windows_, active_window_id_);
551 delete this;
552 content::NotificationService::current()->Notify(
553 chrome::NOTIFICATION_SESSION_RESTORE_DONE,
554 content::NotificationService::AllSources(),
555 content::NotificationService::NoDetails());
556 return browser;
559 if (browser_) {
560 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
561 content::Source<Browser>(browser_));
564 return 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) {
571 StartTabCreation();
572 std::vector<Browser*> browsers;
573 // Create a browser instance to put the restored tabs in.
574 for (std::vector<const SessionWindow*>::const_iterator i = begin;
575 i != end; ++i) {
576 Browser* browser = CreateRestoredBrowser(
577 static_cast<Browser::Type>((*i)->type),
578 (*i)->bounds,
579 (*i)->show_state,
580 (*i)->app_name);
581 browsers.push_back(browser);
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,
590 selected_tab_index);
591 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
594 // Always create in a new window
595 FinishedTabCreation(true, true);
596 return browsers;
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_)) :
616 browser_;
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,
624 tab.navigations,
625 selected_index,
626 true,
627 tab.extension_app_id,
628 NULL,
629 tab.user_agent_override);
630 } else {
631 int tab_index =
632 use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
633 web_contents = chrome::AddRestoredTab(
634 browser,
635 tab.navigations,
636 tab_index,
637 selected_index,
638 tab.extension_app_id,
639 disposition == NEW_FOREGROUND_TAB, // selected
640 tab.pinned,
641 true,
642 NULL,
643 tab.user_agent_override);
644 // Start loading the tab immediately.
645 web_contents->GetController().LoadIfNecessary();
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_);
658 return web_contents;
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 {
676 switch (type) {
677 case chrome::NOTIFICATION_BROWSER_CLOSED:
678 delete this;
679 return;
681 default:
682 NOTREACHED();
683 break;
687 Profile* profile() { return profile_; }
689 private:
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
701 // have been loaded.
703 // Returns the Browser that was created, if any.
704 Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) {
705 Browser* browser = NULL;
706 if (!created_tabbed_browser && always_create_tabbed_browser_) {
707 browser = new Browser(Browser::CreateParams(profile_,
708 host_desktop_type_));
709 if (urls_to_open_.empty()) {
710 // No tab browsers were created and no URLs were supplied on the command
711 // line. Add an empty URL, which is treated as opening the users home
712 // page.
713 urls_to_open_.push_back(GURL());
715 AppendURLsToBrowser(browser, urls_to_open_);
716 browser->window()->Show();
719 if (succeeded) {
720 DCHECK(tab_loader_.get());
721 // TabLoader deletes itself when done loading.
722 tab_loader_->StartLoading();
723 tab_loader_ = NULL;
726 if (!synchronous_) {
727 // If we're not synchronous we need to delete ourself.
728 // NOTE: we must use DeleteLater here as most likely we're in a callback
729 // from the history service which doesn't deal well with deleting the
730 // object it is notifying.
731 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
733 // The delete may take a while and at this point we no longer care about
734 // if the browser is deleted. Don't listen to anything. This avoid a
735 // possible double delete too (if browser is closed before DeleteSoon() is
736 // processed).
737 registrar_.RemoveAll();
740 #if defined(OS_CHROMEOS)
741 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
742 "SessionRestore-End", false);
743 #endif
744 return browser;
747 void OnGotSession(ScopedVector<SessionWindow> windows,
748 SessionID::id_type active_window_id) {
749 base::TimeDelta time_to_got_sessions =
750 base::TimeTicks::Now() - restore_started_;
751 UMA_HISTOGRAM_CUSTOM_TIMES(
752 "SessionRestore.TimeToGotSessions",
753 time_to_got_sessions,
754 base::TimeDelta::FromMilliseconds(10),
755 base::TimeDelta::FromSeconds(1000),
756 100);
757 #if defined(OS_CHROMEOS)
758 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
759 "SessionRestore-GotSession", false);
760 #endif
761 if (synchronous_) {
762 // See comment above windows_ as to why we don't process immediately.
763 windows_.swap(windows.get());
764 active_window_id_ = active_window_id;
765 base::MessageLoop::current()->QuitNow();
766 return;
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),
782 100);
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);
795 #endif
796 StartTabCreation();
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;
806 #if defined(OS_WIN)
807 int selected_tab_to_activate = -1;
808 #endif
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.
827 browser = browser_;
828 } else {
829 #if defined(OS_CHROMEOS)
830 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
831 "SessionRestore-CreateRestoredBrowser-Start", false);
832 #endif
833 // Show the first window if none are visible.
834 ui::WindowShowState show_state = (*i)->show_state;
835 if (!has_visible_browser) {
836 show_state = ui::SHOW_STATE_NORMAL;
837 has_visible_browser = true;
839 browser = NULL;
840 #if defined(OS_WIN)
841 if (win8::IsSingleWindowMetroMode()) {
842 // We don't want to add tabs to the off the record browser.
843 if (browser_ && !browser_->profile()->IsOffTheRecord()) {
844 browser = browser_;
845 } else {
846 browser = last_browser;
847 // last_browser should never be off the record either.
848 // We don't set browser higher above when browser_ is offtherecord,
849 // and CreateRestoredBrowser below, is never created offtherecord.
850 DCHECK(!browser || !browser->profile()->IsOffTheRecord());
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);
858 #endif
859 if (!browser) {
860 browser = CreateRestoredBrowser(
861 static_cast<Browser::Type>((*i)->type),
862 (*i)->bounds,
863 show_state,
864 (*i)->app_name);
866 #if defined(OS_CHROMEOS)
867 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
868 "SessionRestore-CreateRestoredBrowser-End", false);
869 #endif
871 if ((*i)->type == Browser::TYPE_TABBED)
872 last_browser = browser;
873 WebContents* active_tab =
874 browser->tab_strip_model()->GetActiveWebContents();
875 int initial_tab_count = browser->tab_strip_model()->count();
876 bool close_active_tab = clobber_existing_tab_ &&
877 i == windows->begin() &&
878 (*i)->type == Browser::TYPE_TABBED &&
879 active_tab && browser == browser_ &&
880 (*i)->tabs.size() > 0;
881 if (close_active_tab)
882 --initial_tab_count;
883 int selected_tab_index =
884 initial_tab_count > 0 ? browser->tab_strip_model()->active_index()
885 : std::max(0,
886 std::min((*i)->selected_tab_index,
887 static_cast<int>((*i)->tabs.size()) - 1));
888 if ((*i)->window_id.id() == active_window_id) {
889 browser_to_activate = browser;
890 #if defined(OS_WIN)
891 selected_tab_to_activate = selected_tab_index;
892 #endif
894 RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
895 selected_tab_index);
896 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
897 // This needs to be done after restore because closing the last tab will
898 // close the whole window.
899 if (close_active_tab)
900 chrome::CloseWebContents(browser, active_tab, true);
901 #if defined(OS_WIN)
902 selected_tab_to_activate = -1;
903 #endif
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);
914 #endif
915 if (browser_to_activate) {
916 browser_to_activate->window()->Activate();
917 #if defined(OS_WIN)
918 // On Win8 Metro, we merge all browsers together, so if we need to
919 // activate one of the previously separated window, we need to activate
920 // the tab. Also, selected_tab_to_activate can be -1 if we clobbered the
921 // tab that would have been activated.
922 // In that case we'll leave activation to last tab.
923 // The only current usage of clobber is for crash recovery, so it's fine.
924 if (win8::IsSingleWindowMetroMode() && selected_tab_to_activate != -1)
925 ShowBrowser(browser_to_activate, selected_tab_to_activate);
926 #endif
929 // If last_browser is NULL and urls_to_open_ is non-empty,
930 // FinishedTabCreation will create a new TabbedBrowser and add the urls to
931 // it.
932 Browser* finished_browser = FinishedTabCreation(true, has_tabbed_browser);
933 if (finished_browser)
934 last_browser = finished_browser;
936 // sessionStorages needed for the session restore have now been recreated
937 // by RestoreTab. Now it's safe for the DOM storage system to start
938 // deleting leftover data.
939 content::BrowserContext::GetDefaultStoragePartition(profile_)->
940 GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
941 return last_browser;
944 // Record an app launch event (if appropriate) for a tab which is about to
945 // be restored. Callers should ensure that selected_index is within the
946 // bounds of tab.navigations before calling.
947 void RecordAppLaunchForTab(Browser* browser,
948 const SessionTab& tab,
949 int selected_index) {
950 DCHECK(selected_index >= 0 &&
951 selected_index < static_cast<int>(tab.navigations.size()));
952 GURL url = tab.navigations[selected_index].virtual_url();
953 if (browser->profile()->GetExtensionService()) {
954 const extensions::Extension* extension =
955 browser->profile()->GetExtensionService()->GetInstalledApp(url);
956 if (extension) {
957 CoreAppLauncherHandler::RecordAppLaunchType(
958 extension_misc::APP_LAUNCH_SESSION_RESTORE,
959 extension->GetType());
964 // Adds the tabs from |window| to |browser|. Normal tabs go after the existing
965 // tabs but pinned tabs will be pushed in front.
966 // If there are no existing tabs, the tab at |selected_tab_index| will be
967 // selected. Otherwise, the tab selection will remain untouched.
968 void RestoreTabsToBrowser(const SessionWindow& window,
969 Browser* browser,
970 int initial_tab_count,
971 int selected_tab_index) {
972 VLOG(1) << "RestoreTabsToBrowser " << window.tabs.size();
973 DCHECK(!window.tabs.empty());
974 if (initial_tab_count == 0) {
975 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
976 const SessionTab& tab = *(window.tabs[i]);
977 // Loads are scheduled for each restored tab unless the tab is going to
978 // be selected as ShowBrowser() will load the selected tab.
979 if (i == selected_tab_index) {
980 ShowBrowser(browser,
981 browser->tab_strip_model()->GetIndexOfWebContents(
982 RestoreTab(tab, i, browser, false)));
983 tab_loader_->TabIsLoading(
984 &browser->tab_strip_model()->GetActiveWebContents()->
985 GetController());
986 } else {
987 RestoreTab(tab, i, browser, true);
990 } else {
991 // If the browser already has tabs, we want to restore the new ones after
992 // the existing ones. E.g. this happens in Win8 Metro where we merge
993 // windows or when launching a hosted app from the app launcher.
994 int tab_index_offset = initial_tab_count;
995 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
996 const SessionTab& tab = *(window.tabs[i]);
997 // Always schedule loads as we will not be calling ShowBrowser().
998 RestoreTab(tab, tab_index_offset + i, browser, true);
1003 // |tab_index| is ignored for pinned tabs which will always be pushed behind
1004 // the last existing pinned tab.
1005 // |schedule_load| will let |tab_loader_| know that it should schedule this
1006 // tab for loading.
1007 WebContents* RestoreTab(const SessionTab& tab,
1008 const int tab_index,
1009 Browser* browser,
1010 bool schedule_load) {
1011 // It's possible (particularly for foreign sessions) to receive a tab
1012 // without valid navigations. In that case, just skip it.
1013 // See crbug.com/154129.
1014 if (tab.navigations.empty())
1015 return NULL;
1016 int selected_index = tab.current_navigation_index;
1017 selected_index = std::max(
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,
1035 tab.navigations,
1036 tab_index,
1037 selected_index,
1038 tab.extension_app_id,
1039 false, // select
1040 tab.pinned,
1041 true,
1042 session_storage_namespace.get(),
1043 tab.user_agent_override);
1044 // Regression check: check that the tab didn't start loading right away. The
1045 // focused tab will be loaded by Browser, and TabLoader will load the rest.
1046 DCHECK(web_contents->GetController().NeedsReload());
1048 // Set up the file access rights for the selected navigation entry.
1049 const int id = web_contents->GetRenderProcessHost()->GetID();
1050 const content::PageState& page_state =
1051 tab.navigations.at(selected_index).page_state();
1052 const std::vector<base::FilePath>& file_paths =
1053 page_state.GetReferencedFiles();
1054 for (std::vector<base::FilePath>::const_iterator file = file_paths.begin();
1055 file != file_paths.end(); ++file) {
1056 content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id,
1057 *file);
1060 if (schedule_load)
1061 tab_loader_->ScheduleLoad(&web_contents->GetController());
1062 return web_contents;
1065 Browser* CreateRestoredBrowser(Browser::Type type,
1066 gfx::Rect bounds,
1067 ui::WindowShowState show_state,
1068 const std::string& app_name) {
1069 Browser::CreateParams params(type, profile_, host_desktop_type_);
1070 params.app_name = app_name;
1071 params.initial_bounds = bounds;
1072 params.initial_show_state = show_state;
1073 params.is_session_restore = true;
1074 return new Browser(params);
1077 void ShowBrowser(Browser* browser, int selected_tab_index) {
1078 DCHECK(browser);
1079 DCHECK(browser->tab_strip_model()->count());
1080 browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true);
1082 if (browser_ == browser)
1083 return;
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",
1099 time_to_first_show,
1100 base::TimeDelta::FromMilliseconds(10),
1101 base::TimeDelta::FromSeconds(1000),
1102 100);
1106 // Appends the urls in |urls| to |browser|.
1107 void AppendURLsToBrowser(Browser* browser,
1108 const std::vector<GURL>& urls) {
1109 for (size_t i = 0; i < urls.size(); ++i) {
1110 int add_types = TabStripModel::ADD_FORCE_INDEX;
1111 if (i == 0)
1112 add_types |= TabStripModel::ADD_ACTIVE;
1113 chrome::NavigateParams params(browser, urls[i],
1114 content::PAGE_TRANSITION_AUTO_TOPLEVEL);
1115 params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
1116 params.tabstrip_add_types = add_types;
1117 chrome::Navigate(&params);
1121 // Invokes TabRestored on the SessionService for all tabs in browser after
1122 // initial_count.
1123 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
1124 SessionService* session_service =
1125 SessionServiceFactory::GetForProfile(profile_);
1126 if (!session_service)
1127 return;
1128 TabStripModel* tab_strip = browser->tab_strip_model();
1129 for (int i = initial_count; i < tab_strip->count(); ++i)
1130 session_service->TabRestored(tab_strip->GetWebContentsAt(i),
1131 tab_strip->IsTabPinned(i));
1134 // The profile to create the sessions for.
1135 Profile* profile_;
1137 // The first browser to restore to, may be null.
1138 Browser* browser_;
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);
1182 } // namespace
1184 // SessionRestore -------------------------------------------------------------
1186 // static
1187 Browser* SessionRestore::RestoreSession(
1188 Profile* profile,
1189 Browser* browser,
1190 chrome::HostDesktopType host_desktop_type,
1191 uint32 behavior,
1192 const std::vector<GURL>& urls_to_open) {
1193 #if defined(OS_CHROMEOS)
1194 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1195 "SessionRestore-Start", false);
1196 #endif
1197 DCHECK(profile);
1198 // Always restore from the original profile (incognito profiles have no
1199 // session service).
1200 profile = profile->GetOriginalProfile();
1201 if (!SessionServiceFactory::GetForProfile(profile)) {
1202 NOTREACHED();
1203 return NULL;
1205 profile->set_restored_last_session(true);
1206 // SessionRestoreImpl takes care of deleting itself when done.
1207 SessionRestoreImpl* restorer = new SessionRestoreImpl(
1208 profile, browser, host_desktop_type, (behavior & SYNCHRONOUS) != 0,
1209 (behavior & CLOBBER_CURRENT_TAB) != 0,
1210 (behavior & ALWAYS_CREATE_TABBED_BROWSER) != 0,
1211 urls_to_open);
1212 return restorer->Restore();
1215 // static
1216 std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows(
1217 Profile* profile,
1218 chrome::HostDesktopType host_desktop_type,
1219 std::vector<const SessionWindow*>::const_iterator begin,
1220 std::vector<const SessionWindow*>::const_iterator end) {
1221 std::vector<GURL> gurls;
1222 SessionRestoreImpl restorer(profile,
1223 static_cast<Browser*>(NULL), host_desktop_type, true, false, true, gurls);
1224 return restorer.RestoreForeignSession(begin, end);
1227 // static
1228 WebContents* SessionRestore::RestoreForeignSessionTab(
1229 content::WebContents* source_web_contents,
1230 const SessionTab& tab,
1231 WindowOpenDisposition disposition) {
1232 Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents);
1233 Profile* profile = browser->profile();
1234 std::vector<GURL> gurls;
1235 SessionRestoreImpl restorer(profile, browser, browser->host_desktop_type(),
1236 true, false, false, gurls);
1237 return restorer.RestoreForeignTab(tab, disposition);
1240 // static
1241 bool SessionRestore::IsRestoring(const Profile* profile) {
1242 if (active_session_restorers == NULL)
1243 return false;
1244 for (std::set<SessionRestoreImpl*>::const_iterator it =
1245 active_session_restorers->begin();
1246 it != active_session_restorers->end(); ++it) {
1247 if ((*it)->profile() == profile)
1248 return true;
1250 return false;
1253 // static
1254 bool SessionRestore::IsRestoringSynchronously() {
1255 if (!active_session_restorers)
1256 return false;
1257 for (std::set<SessionRestoreImpl*>::const_iterator it =
1258 active_session_restorers->begin();
1259 it != active_session_restorers->end(); ++it) {
1260 if ((*it)->synchronous())
1261 return true;
1263 return false;