[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / sessions / session_restore.cc
blob7cca291c9b3881de619289ab8c46ae5f6096b0a1
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/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"
57 #endif
59 using content::NavigationController;
60 using content::RenderWidgetHost;
61 using content::WebContents;
63 namespace {
65 class SessionRestoreImpl;
66 class TabLoader;
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
82 // doubled.
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> {
94 public:
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.
110 void StartLoading();
112 private:
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.
124 void LoadNextTab();
126 // NotificationObserver method. Removes the specified tab and loads the next
127 // tab.
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
138 // from.
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,
146 // NULL otherwise.
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
158 // details.
159 int64 force_load_delay_;
161 // Has Load been invoked?
162 bool loading_;
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
168 // selected tabs.
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.
181 int tab_count_;
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);
198 // static
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) {
206 DCHECK(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) {
214 DCHECK(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
228 // eventually.
229 if (loading_)
230 return;
231 registrar_.Add(
232 this,
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()) {
238 loading_ = true;
239 LoadNextTab();
240 } else {
241 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
243 #else
244 loading_ = true;
245 LoadNextTab();
246 #endif
249 TabLoader::TabLoader(base::TimeTicks restore_started)
250 : force_load_delay_(kInitialDelayTimerMS),
251 loading_(false),
252 got_first_paint_(false),
253 tab_count_(0),
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();
268 DCHECK(tab);
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();
275 if (contents) {
276 Browser* browser = chrome::FindBrowserWithWebContents(contents);
277 if (browser &&
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) {
313 switch (type) {
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);
323 break;
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());
333 break;
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);
340 break;
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",
355 time_to_paint,
356 base::TimeDelta::FromMilliseconds(10),
357 base::TimeDelta::FromSeconds(100),
358 100);
359 // Record a time for the number of tabs, to help track down
360 // contention.
361 std::string time_for_count =
362 base::StringPrintf("SessionRestore.FirstTabPainted_%d",
363 tab_count_);
364 base::HistogramBase* counter_for_count =
365 base::Histogram::FactoryTimeGet(
366 time_for_count,
367 base::TimeDelta::FromMilliseconds(10),
368 base::TimeDelta::FromSeconds(100),
369 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;
381 break;
383 default:
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) {
398 if (!loading_) {
399 loading_ = true;
400 LoadNextTab();
402 } else {
403 loading_ = false;
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;
427 LoadNextTab();
430 RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
431 WebContents* web_contents = tab->GetWebContents();
432 if (web_contents) {
433 content::RenderWidgetHostView* render_widget_host_view =
434 web_contents->GetRenderWidgetHostView();
435 if (render_widget_host_view)
436 return render_widget_host_view->GetRenderWidgetHost();
438 return NULL;
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));
448 ++tab_count_;
451 void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
452 RemoveTab(tab);
453 if (loading_)
454 LoadNextTab();
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(
459 time_to_load);
460 UMA_HISTOGRAM_CUSTOM_TIMES(
461 "SessionRestore.AllTabsLoaded",
462 time_to_load,
463 base::TimeDelta::FromMilliseconds(10),
464 base::TimeDelta::FromSeconds(100),
465 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(
471 time_for_count,
472 base::TimeDelta::FromMilliseconds(10),
473 base::TimeDelta::FromSeconds(100),
474 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 {
489 public:
490 SessionRestoreImpl(Profile* profile,
491 Browser* browser,
492 chrome::HostDesktopType host_desktop_type,
493 bool synchronous,
494 bool clobber_existing_tab,
495 bool always_create_tabbed_browser,
496 const std::vector<GURL>& urls_to_open)
497 : profile_(profile),
498 browser_(browser),
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
515 // same time.
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)
520 break;
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_; }
534 Browser* Restore() {
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_);
542 if (synchronous_) {
544 base::MessageLoop::ScopedNestableTaskAllower allow(
545 base::MessageLoop::current());
546 base::RunLoop loop;
547 quit_closure_for_sync_restore_ = loop.QuitClosure();
548 loop.Run();
549 quit_closure_for_sync_restore_ = base::Closure();
551 Browser* browser = ProcessSessionWindows(&windows_, active_window_id_);
552 delete this;
553 content::NotificationService::current()->Notify(
554 chrome::NOTIFICATION_SESSION_RESTORE_DONE,
555 content::NotificationService::AllSources(),
556 content::NotificationService::NoDetails());
557 return browser;
560 if (browser_) {
561 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
562 content::Source<Browser>(browser_));
565 return 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) {
572 StartTabCreation();
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;
576 i != end; ++i) {
577 Browser* browser = CreateRestoredBrowser(
578 static_cast<Browser::Type>((*i)->type),
579 (*i)->bounds,
580 (*i)->show_state,
581 (*i)->app_name);
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,
591 selected_tab_index);
592 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
595 // Always create in a new window
596 FinishedTabCreation(true, true);
597 return browsers;
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_)) :
617 browser_;
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,
625 tab.navigations,
626 selected_index,
627 true,
628 tab.extension_app_id,
629 NULL,
630 tab.user_agent_override);
631 } else {
632 int tab_index =
633 use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
634 web_contents = chrome::AddRestoredTab(
635 browser,
636 tab.navigations,
637 tab_index,
638 selected_index,
639 tab.extension_app_id,
640 disposition == NEW_FOREGROUND_TAB, // selected
641 tab.pinned,
642 true,
643 NULL,
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_);
659 return web_contents;
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 {
677 switch (type) {
678 case chrome::NOTIFICATION_BROWSER_CLOSED:
679 delete this;
680 return;
682 default:
683 NOTREACHED();
684 break;
688 Profile* profile() { return profile_; }
690 private:
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
702 // have been loaded.
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
713 // page.
714 urls_to_open_.push_back(GURL());
716 AppendURLsToBrowser(browser, urls_to_open_);
717 browser->window()->Show();
720 if (succeeded) {
721 DCHECK(tab_loader_.get());
722 // TabLoader deletes itself when done loading.
723 tab_loader_->StartLoading();
724 tab_loader_ = NULL;
727 if (!synchronous_) {
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
737 // processed).
738 registrar_.RemoveAll();
741 #if defined(OS_CHROMEOS)
742 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
743 "SessionRestore-End", false);
744 #endif
745 return browser;
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),
757 100);
758 #if defined(OS_CHROMEOS)
759 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
760 "SessionRestore-GotSession", false);
761 #endif
762 if (synchronous_) {
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();
768 return;
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),
784 100);
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);
797 #endif
798 StartTabCreation();
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;
808 #if defined(OS_WIN)
809 int selected_tab_to_activate = -1;
810 #endif
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.
829 browser = browser_;
830 } else {
831 #if defined(OS_CHROMEOS)
832 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
833 "SessionRestore-CreateRestoredBrowser-Start", false);
834 #endif
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),
843 (*i)->bounds,
844 show_state,
845 (*i)->app_name);
846 #if defined(OS_CHROMEOS)
847 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
848 "SessionRestore-CreateRestoredBrowser-End", false);
849 #endif
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)
862 --initial_tab_count;
863 int selected_tab_index =
864 initial_tab_count > 0 ? browser->tab_strip_model()->active_index()
865 : std::max(0,
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;
870 #if defined(OS_WIN)
871 selected_tab_to_activate = selected_tab_index;
872 #endif
874 RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
875 selected_tab_index);
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);
881 #if defined(OS_WIN)
882 selected_tab_to_activate = -1;
883 #endif
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);
894 #endif
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
900 // it.
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();
910 return last_browser;
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);
925 if (extension) {
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,
937 Browser* browser,
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.
953 if (!restored_tab)
954 continue;
956 // If this isn't the selected tab, there's nothing else to do.
957 if (is_not_selected_tab)
958 continue;
960 ShowBrowser(
961 browser,
962 browser->tab_strip_model()->GetIndexOfWebContents(restored_tab));
963 tab_loader_->TabIsLoading(&browser->tab_strip_model()
964 ->GetActiveWebContents()
965 ->GetController());
967 } else {
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
983 // tab for loading.
984 WebContents* RestoreTab(const SessionTab& tab,
985 const int tab_index,
986 Browser* browser,
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())
992 return NULL;
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,
1012 tab.navigations,
1013 tab_index,
1014 selected_index,
1015 tab.extension_app_id,
1016 false, // select
1017 tab.pinned,
1018 true,
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,
1034 *file);
1037 if (schedule_load)
1038 tab_loader_->ScheduleLoad(&web_contents->GetController());
1039 return web_contents;
1042 Browser* CreateRestoredBrowser(Browser::Type type,
1043 gfx::Rect bounds,
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,
1050 trusted_source,
1051 bounds,
1052 profile_,
1053 host_desktop_type_);
1054 } else {
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) {
1063 DCHECK(browser);
1064 DCHECK(browser->tab_strip_model()->count());
1065 browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true);
1067 if (browser_ == browser)
1068 return;
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",
1083 time_to_first_show,
1084 base::TimeDelta::FromMilliseconds(10),
1085 base::TimeDelta::FromSeconds(1000),
1086 100);
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;
1095 if (i == 0)
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(&params);
1105 // Invokes TabRestored on the SessionService for all tabs in browser after
1106 // initial_count.
1107 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
1108 SessionService* session_service =
1109 SessionServiceFactory::GetForProfile(profile_);
1110 if (!session_service)
1111 return;
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.
1119 Profile* profile_;
1121 // The first browser to restore to, may be null.
1122 Browser* browser_;
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);
1170 } // namespace
1172 // SessionRestore -------------------------------------------------------------
1174 // static
1175 Browser* SessionRestore::RestoreSession(
1176 Profile* profile,
1177 Browser* browser,
1178 chrome::HostDesktopType host_desktop_type,
1179 uint32 behavior,
1180 const std::vector<GURL>& urls_to_open) {
1181 #if defined(OS_CHROMEOS)
1182 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
1183 "SessionRestore-Start", false);
1184 #endif
1185 DCHECK(profile);
1186 // Always restore from the original profile (incognito profiles have no
1187 // session service).
1188 profile = profile->GetOriginalProfile();
1189 if (!SessionServiceFactory::GetForProfile(profile)) {
1190 NOTREACHED();
1191 return NULL;
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,
1199 urls_to_open);
1200 return restorer->Restore();
1203 // static
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
1212 // clobber it.
1213 behavior = SessionRestore::CLOBBER_CURRENT_TAB;
1216 SessionRestore::RestoreSession(browser->profile(), browser,
1217 browser->host_desktop_type(), behavior,
1218 std::vector<GURL>());
1221 // static
1222 std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows(
1223 Profile* profile,
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);
1233 // static
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);
1246 // static
1247 bool SessionRestore::IsRestoring(const Profile* profile) {
1248 if (active_session_restorers == NULL)
1249 return false;
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)
1254 return true;
1256 return false;
1259 // static
1260 bool SessionRestore::IsRestoringSynchronously() {
1261 if (!active_session_restorers)
1262 return false;
1263 for (std::set<SessionRestoreImpl*>::const_iterator it =
1264 active_session_restorers->begin();
1265 it != active_session_restorers->end(); ++it) {
1266 if ((*it)->synchronous())
1267 return true;
1269 return false;