Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / sessions / session_restore.cc
blobaca211c8d7bfe979dff23c9fc44f7a8ff4296d36
1 // Copyright 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/debug/alias.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h"
19 #include "base/metrics/field_trial.h"
20 #include "base/metrics/histogram.h"
21 #include "base/run_loop.h"
22 #include "base/stl_util.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/profiles/profile.h"
27 #include "chrome/browser/search/search.h"
28 #include "chrome/browser/sessions/session_restore_delegate.h"
29 #include "chrome/browser/sessions/session_service.h"
30 #include "chrome/browser/sessions/session_service_factory.h"
31 #include "chrome/browser/sessions/session_service_utils.h"
32 #include "chrome/browser/sessions/tab_loader.h"
33 #include "chrome/browser/ui/browser.h"
34 #include "chrome/browser/ui/browser_finder.h"
35 #include "chrome/browser/ui/browser_navigator.h"
36 #include "chrome/browser/ui/browser_tabrestore.h"
37 #include "chrome/browser/ui/browser_tabstrip.h"
38 #include "chrome/browser/ui/browser_window.h"
39 #include "chrome/browser/ui/tabs/tab_strip_model.h"
40 #include "chrome/common/extensions/extension_metrics.h"
41 #include "chrome/common/url_constants.h"
42 #include "components/sessions/session_types.h"
43 #include "content/public/browser/child_process_security_policy.h"
44 #include "content/public/browser/dom_storage_context.h"
45 #include "content/public/browser/navigation_controller.h"
46 #include "content/public/browser/notification_registrar.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/render_process_host.h"
49 #include "content/public/browser/render_widget_host.h"
50 #include "content/public/browser/render_widget_host_view.h"
51 #include "content/public/browser/session_storage_namespace.h"
52 #include "content/public/browser/storage_partition.h"
53 #include "content/public/browser/web_contents.h"
54 #include "content/public/common/page_state.h"
55 #include "extensions/browser/extension_registry.h"
56 #include "extensions/common/extension_set.h"
58 #if defined(OS_CHROMEOS)
59 #include "chrome/browser/chromeos/boot_times_recorder.h"
60 #endif
62 using content::NavigationController;
63 using content::RenderWidgetHost;
64 using content::WebContents;
65 using RestoredTab = SessionRestoreDelegate::RestoredTab;
67 namespace {
69 class SessionRestoreImpl;
71 // Pointers to SessionRestoreImpls which are currently restoring the session.
72 std::set<SessionRestoreImpl*>* active_session_restorers = nullptr;
74 // SessionRestoreImpl ---------------------------------------------------------
76 // SessionRestoreImpl is responsible for fetching the set of tabs to create
77 // from SessionService. SessionRestoreImpl deletes itself when done.
79 class SessionRestoreImpl : public content::NotificationObserver {
80 public:
81 SessionRestoreImpl(Profile* profile,
82 Browser* browser,
83 chrome::HostDesktopType host_desktop_type,
84 bool synchronous,
85 bool clobber_existing_tab,
86 bool always_create_tabbed_browser,
87 const std::vector<GURL>& urls_to_open,
88 SessionRestore::CallbackList* callbacks)
89 : profile_(profile),
90 browser_(browser),
91 host_desktop_type_(host_desktop_type),
92 synchronous_(synchronous),
93 clobber_existing_tab_(clobber_existing_tab),
94 always_create_tabbed_browser_(always_create_tabbed_browser),
95 urls_to_open_(urls_to_open),
96 active_window_id_(0),
97 restore_started_(base::TimeTicks::Now()),
98 on_session_restored_callbacks_(callbacks) {
99 // For sanity's sake, if |browser| is non-null: force |host_desktop_type| to
100 // be the same as |browser|'s desktop type.
101 DCHECK(!browser || browser->host_desktop_type() == host_desktop_type);
103 if (active_session_restorers == nullptr)
104 active_session_restorers = new std::set<SessionRestoreImpl*>();
106 // Only one SessionRestoreImpl should be operating on the profile at the
107 // same time.
108 std::set<SessionRestoreImpl*>::const_iterator it;
109 for (it = active_session_restorers->begin();
110 it != active_session_restorers->end(); ++it) {
111 if ((*it)->profile_ == profile)
112 break;
114 DCHECK(it == active_session_restorers->end());
116 active_session_restorers->insert(this);
118 // When asynchronous its possible for there to be no windows. To make sure
119 // Chrome doesn't prematurely exit AddRef the process. We'll release in the
120 // destructor when restore is done.
121 g_browser_process->AddRefModule();
124 bool synchronous() const { return synchronous_; }
126 Browser* Restore() {
127 SessionService* session_service =
128 SessionServiceFactory::GetForProfile(profile_);
129 DCHECK(session_service);
130 session_service->GetLastSession(
131 base::Bind(&SessionRestoreImpl::OnGotSession, base::Unretained(this)),
132 &cancelable_task_tracker_);
134 if (synchronous_) {
136 base::MessageLoop::ScopedNestableTaskAllower allow(
137 base::MessageLoop::current());
138 base::RunLoop loop;
139 quit_closure_for_sync_restore_ = loop.QuitClosure();
140 loop.Run();
141 quit_closure_for_sync_restore_ = base::Closure();
143 Browser* browser =
144 ProcessSessionWindowsAndNotify(&windows_, active_window_id_);
145 delete this;
146 return browser;
149 if (browser_) {
150 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
151 content::Source<Browser>(browser_));
154 return browser_;
157 // Restore window(s) from a foreign session. Returns newly created Browsers.
158 std::vector<Browser*> RestoreForeignSession(
159 std::vector<const sessions::SessionWindow*>::const_iterator begin,
160 std::vector<const sessions::SessionWindow*>::const_iterator end) {
161 std::vector<Browser*> browsers;
162 std::vector<RestoredTab> created_contents;
163 // Create a browser instance to put the restored tabs in.
164 for (std::vector<const sessions::SessionWindow*>::const_iterator i = begin;
165 i != end; ++i) {
166 Browser* browser =
167 CreateRestoredBrowser(BrowserTypeForWindowType((*i)->type),
168 (*i)->bounds, (*i)->show_state, (*i)->app_name);
169 browsers.push_back(browser);
171 // Restore and show the browser.
172 const int initial_tab_count = 0;
173 int selected_tab_index =
174 std::max(0, std::min((*i)->selected_tab_index,
175 static_cast<int>((*i)->tabs.size()) - 1));
176 RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
177 selected_tab_index, &created_contents);
178 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
181 // Always create in a new window.
182 FinishedTabCreation(true, true, &created_contents);
184 on_session_restored_callbacks_->Notify(
185 static_cast<int>(created_contents.size()));
187 return browsers;
190 // Restore a single tab from a foreign session.
191 // Opens in the tab in the last active browser, unless disposition is
192 // NEW_WINDOW, in which case the tab will be opened in a new browser. Returns
193 // the WebContents of the restored tab.
194 WebContents* RestoreForeignTab(const sessions::SessionTab& tab,
195 WindowOpenDisposition disposition) {
196 DCHECK(!tab.navigations.empty());
197 int selected_index = tab.current_navigation_index;
198 selected_index = std::max(
200 std::min(selected_index, static_cast<int>(tab.navigations.size() - 1)));
202 bool use_new_window = disposition == NEW_WINDOW;
204 Browser* browser =
205 use_new_window
206 ? new Browser(Browser::CreateParams(profile_, host_desktop_type_))
207 : browser_;
209 RecordAppLaunchForTab(browser, tab, selected_index);
211 WebContents* web_contents;
212 if (disposition == CURRENT_TAB) {
213 DCHECK(!use_new_window);
214 web_contents = chrome::ReplaceRestoredTab(
215 browser, tab.navigations, selected_index, true, tab.extension_app_id,
216 nullptr, tab.user_agent_override);
217 } else {
218 int tab_index =
219 use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
220 web_contents = chrome::AddRestoredTab(
221 browser, tab.navigations, tab_index, selected_index,
222 tab.extension_app_id,
223 disposition == NEW_FOREGROUND_TAB, // selected
224 tab.pinned, true, nullptr, tab.user_agent_override);
225 // Start loading the tab immediately.
226 web_contents->GetController().LoadIfNecessary();
229 if (use_new_window) {
230 browser->tab_strip_model()->ActivateTabAt(0, true);
231 browser->window()->Show();
233 NotifySessionServiceOfRestoredTabs(browser,
234 browser->tab_strip_model()->count());
236 // Since FinishedTabCreation() is not called here, |this| will leak if we
237 // are not in sychronous mode.
238 DCHECK(synchronous_);
240 on_session_restored_callbacks_->Notify(1);
242 return web_contents;
245 ~SessionRestoreImpl() override {
246 STLDeleteElements(&windows_);
248 active_session_restorers->erase(this);
249 if (active_session_restorers->empty()) {
250 delete active_session_restorers;
251 active_session_restorers = nullptr;
254 g_browser_process->ReleaseModule();
257 void Observe(int type,
258 const content::NotificationSource& source,
259 const content::NotificationDetails& details) override {
260 switch (type) {
261 case chrome::NOTIFICATION_BROWSER_CLOSED:
262 delete this;
263 return;
265 default:
266 NOTREACHED();
267 break;
271 Profile* profile() { return profile_; }
273 private:
274 // Invoked when done with creating all the tabs/browsers.
276 // |created_tabbed_browser| indicates whether a tabbed browser was created,
277 // or we used an existing tabbed browser.
279 // If successful, this begins loading tabs and deletes itself when all tabs
280 // have been loaded.
282 // Returns the Browser that was created, if any.
283 Browser* FinishedTabCreation(bool succeeded,
284 bool created_tabbed_browser,
285 std::vector<RestoredTab>* contents_created) {
286 Browser* browser = nullptr;
287 if (!created_tabbed_browser && always_create_tabbed_browser_) {
288 browser =
289 new Browser(Browser::CreateParams(profile_, host_desktop_type_));
290 if (urls_to_open_.empty()) {
291 // No tab browsers were created and no URLs were supplied on the command
292 // line. Open the new tab page.
293 urls_to_open_.push_back(GURL(chrome::kChromeUINewTabURL));
295 AppendURLsToBrowser(browser, urls_to_open_);
296 browser->window()->Show();
299 if (succeeded) {
300 if (SessionRestore::GetSmartRestoreMode() !=
301 SessionRestore::SMART_RESTORE_MODE_OFF) {
302 std::stable_sort(contents_created->begin(), contents_created->end());
304 // Start Loading tabs.
305 SessionRestoreDelegate::RestoreTabs(*contents_created, restore_started_);
308 if (!synchronous_) {
309 // If we're not synchronous we need to delete ourself.
310 // NOTE: we must use DeleteLater here as most likely we're in a callback
311 // from the history service which doesn't deal well with deleting the
312 // object it is notifying.
313 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
315 // The delete may take a while and at this point we no longer care about
316 // if the browser is deleted. Don't listen to anything. This avoid a
317 // possible double delete too (if browser is closed before DeleteSoon() is
318 // processed).
319 registrar_.RemoveAll();
322 #if defined(OS_CHROMEOS)
323 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker("SessionRestore-End",
324 false);
325 #endif
326 return browser;
329 void OnGotSession(ScopedVector<sessions::SessionWindow> windows,
330 SessionID::id_type active_window_id) {
331 #if defined(OS_CHROMEOS)
332 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
333 "SessionRestore-GotSession", false);
334 #endif
335 if (synchronous_) {
336 // See comment above windows_ as to why we don't process immediately.
337 windows_.swap(windows.get());
338 active_window_id_ = active_window_id;
339 CHECK(!quit_closure_for_sync_restore_.is_null());
340 quit_closure_for_sync_restore_.Run();
341 return;
344 ProcessSessionWindowsAndNotify(&windows.get(), active_window_id);
347 Browser* ProcessSessionWindowsAndNotify(
348 std::vector<sessions::SessionWindow*>* windows,
349 SessionID::id_type active_window_id) {
350 std::vector<RestoredTab> contents;
351 Browser* result =
352 ProcessSessionWindows(windows, active_window_id, &contents);
353 on_session_restored_callbacks_->Notify(static_cast<int>(contents.size()));
354 return result;
357 Browser* ProcessSessionWindows(std::vector<sessions::SessionWindow*>* windows,
358 SessionID::id_type active_window_id,
359 std::vector<RestoredTab>* created_contents) {
360 DVLOG(1) << "ProcessSessionWindows " << windows->size();
362 if (windows->empty()) {
363 // Restore was unsuccessful. The DOM storage system can also delete its
364 // data, since no session restore will happen at a later point in time.
365 content::BrowserContext::GetDefaultStoragePartition(profile_)
366 ->GetDOMStorageContext()
367 ->StartScavengingUnusedSessionStorage();
368 return FinishedTabCreation(false, false, created_contents);
371 #if defined(OS_CHROMEOS)
372 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
373 "SessionRestore-CreatingTabs-Start", false);
374 #endif
376 // After the for loop this contains the last TABBED_BROWSER. Is null if no
377 // tabbed browsers exist.
378 Browser* last_browser = nullptr;
379 bool has_tabbed_browser = false;
381 // After the for loop, this contains the browser to activate, if one of the
382 // windows has the same id as specified in active_window_id.
383 Browser* browser_to_activate = nullptr;
385 // Determine if there is a visible window.
386 bool has_visible_browser = false;
387 for (std::vector<sessions::SessionWindow*>::iterator i = windows->begin();
388 i != windows->end(); ++i) {
389 if ((*i)->show_state != ui::SHOW_STATE_MINIMIZED)
390 has_visible_browser = true;
393 for (std::vector<sessions::SessionWindow*>::iterator i = windows->begin();
394 i != windows->end(); ++i) {
395 Browser* browser = nullptr;
396 if (!has_tabbed_browser &&
397 (*i)->type == sessions::SessionWindow::TYPE_TABBED)
398 has_tabbed_browser = true;
399 if (i == windows->begin() &&
400 (*i)->type == sessions::SessionWindow::TYPE_TABBED && browser_ &&
401 browser_->is_type_tabbed() &&
402 !browser_->profile()->IsOffTheRecord()) {
403 // The first set of tabs is added to the existing browser.
404 browser = browser_;
405 } else {
406 #if defined(OS_CHROMEOS)
407 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
408 "SessionRestore-CreateRestoredBrowser-Start", false);
409 #endif
410 // Show the first window if none are visible.
411 ui::WindowShowState show_state = (*i)->show_state;
412 if (!has_visible_browser) {
413 show_state = ui::SHOW_STATE_NORMAL;
414 has_visible_browser = true;
416 browser =
417 CreateRestoredBrowser(BrowserTypeForWindowType((*i)->type),
418 (*i)->bounds, show_state, (*i)->app_name);
419 #if defined(OS_CHROMEOS)
420 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
421 "SessionRestore-CreateRestoredBrowser-End", false);
422 #endif
424 if ((*i)->type == sessions::SessionWindow::TYPE_TABBED)
425 last_browser = browser;
426 WebContents* active_tab =
427 browser->tab_strip_model()->GetActiveWebContents();
428 int initial_tab_count = browser->tab_strip_model()->count();
429 bool close_active_tab =
430 clobber_existing_tab_ && i == windows->begin() &&
431 (*i)->type == sessions::SessionWindow::TYPE_TABBED && active_tab &&
432 browser == browser_ && (*i)->tabs.size() > 0;
433 if (close_active_tab)
434 --initial_tab_count;
435 int selected_tab_index =
436 initial_tab_count > 0
437 ? browser->tab_strip_model()->active_index()
438 : std::max(0, std::min((*i)->selected_tab_index,
439 static_cast<int>((*i)->tabs.size()) - 1));
440 if ((*i)->window_id.id() == active_window_id)
441 browser_to_activate = browser;
443 RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
444 selected_tab_index, created_contents);
445 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
446 // This needs to be done after restore because closing the last tab will
447 // close the whole window.
448 if (close_active_tab)
449 chrome::CloseWebContents(browser, active_tab, true);
452 if (browser_to_activate && browser_to_activate->is_type_tabbed())
453 last_browser = browser_to_activate;
455 if (last_browser && !urls_to_open_.empty())
456 AppendURLsToBrowser(last_browser, urls_to_open_);
457 #if defined(OS_CHROMEOS)
458 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
459 "SessionRestore-CreatingTabs-End", false);
460 #endif
461 if (browser_to_activate)
462 browser_to_activate->window()->Activate();
464 // If last_browser is NULL and urls_to_open_ is non-empty,
465 // FinishedTabCreation will create a new TabbedBrowser and add the urls to
466 // it.
467 Browser* finished_browser =
468 FinishedTabCreation(true, has_tabbed_browser, created_contents);
469 if (finished_browser)
470 last_browser = finished_browser;
472 // sessionStorages needed for the session restore have now been recreated
473 // by RestoreTab. Now it's safe for the DOM storage system to start
474 // deleting leftover data.
475 content::BrowserContext::GetDefaultStoragePartition(profile_)
476 ->GetDOMStorageContext()
477 ->StartScavengingUnusedSessionStorage();
478 return last_browser;
481 // Record an app launch event (if appropriate) for a tab which is about to
482 // be restored. Callers should ensure that selected_index is within the
483 // bounds of tab.navigations before calling.
484 void RecordAppLaunchForTab(Browser* browser,
485 const sessions::SessionTab& tab,
486 int selected_index) {
487 DCHECK(selected_index >= 0 &&
488 selected_index < static_cast<int>(tab.navigations.size()));
489 GURL url = tab.navigations[selected_index].virtual_url();
490 const extensions::Extension* extension =
491 extensions::ExtensionRegistry::Get(profile())
492 ->enabled_extensions()
493 .GetAppByURL(url);
494 if (extension) {
495 extensions::RecordAppLaunchType(
496 extension_misc::APP_LAUNCH_SESSION_RESTORE, extension->GetType());
500 // Adds the tabs from |window| to |browser|. Normal tabs go after the existing
501 // tabs but pinned tabs will be pushed in front.
502 // If there are no existing tabs, the tab at |selected_tab_index| will be
503 // selected. Otherwise, the tab selection will remain untouched.
504 void RestoreTabsToBrowser(const sessions::SessionWindow& window,
505 Browser* browser,
506 int initial_tab_count,
507 int selected_tab_index,
508 std::vector<RestoredTab>* created_contents) {
509 DVLOG(1) << "RestoreTabsToBrowser " << window.tabs.size();
510 DCHECK(!window.tabs.empty());
511 base::TimeTicks now = base::TimeTicks::Now();
512 base::TimeTicks highest_time = base::TimeTicks::UnixEpoch();
513 if (initial_tab_count == 0) {
514 if (SessionRestore::GetSmartRestoreMode() ==
515 SessionRestore::SMART_RESTORE_MODE_MRU) {
516 // The last active time of a WebContents is initially set to the
517 // creation time of the tab, which is not necessarly the same as the
518 // loading time, so we have to restore the values. Also, since TimeTicks
519 // only make sense in their current session, these values have to be
520 // sanitized first. To do so, we need to first figure out the largest
521 // time. This will then be used to set the last active time of
522 // each tab where the most recent tab will have its time set to |now|
523 // and the rest of the tabs will have theirs set earlier by the same
524 // delta as they originally had.
525 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
526 const sessions::SessionTab& tab = *(window.tabs[i]);
527 if (tab.last_active_time > highest_time)
528 highest_time = tab.last_active_time;
531 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
532 const sessions::SessionTab& tab = *(window.tabs[i]);
534 // Loads are scheduled for each restored tab unless the tab is going to
535 // be selected as ShowBrowser() will load the selected tab.
536 bool is_selected_tab = (i == selected_tab_index);
537 WebContents* contents = RestoreTab(tab, i, browser, is_selected_tab);
539 // RestoreTab can return nullptr if |tab| doesn't have valid data.
540 if (!contents)
541 continue;
543 // Sanitize the last active time.
544 if (SessionRestore::GetSmartRestoreMode() ==
545 SessionRestore::SMART_RESTORE_MODE_MRU) {
546 base::TimeDelta delta = highest_time - tab.last_active_time;
547 contents->SetLastActiveTime(now - delta);
550 RestoredTab restored_tab(contents, is_selected_tab,
551 tab.extension_app_id.empty(), tab.pinned);
552 created_contents->push_back(restored_tab);
554 // If this isn't the selected tab, there's nothing else to do.
555 if (!is_selected_tab)
556 continue;
558 ShowBrowser(browser, browser->tab_strip_model()->GetIndexOfWebContents(
559 contents));
560 // TODO(sky): remove. For debugging 368236.
561 CHECK_EQ(browser->tab_strip_model()->GetActiveWebContents(), contents);
563 } else {
564 // If the browser already has tabs, we want to restore the new ones after
565 // the existing ones. E.g. this happens in Win8 Metro where we merge
566 // windows or when launching a hosted app from the app launcher.
567 int tab_index_offset = initial_tab_count;
568 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
569 const sessions::SessionTab& tab = *(window.tabs[i]);
570 // Always schedule loads as we will not be calling ShowBrowser().
571 WebContents* contents =
572 RestoreTab(tab, tab_index_offset + i, browser, false);
573 if (contents) {
574 // Sanitize the last active time.
575 if (SessionRestore::GetSmartRestoreMode() ==
576 SessionRestore::SMART_RESTORE_MODE_MRU) {
577 base::TimeDelta delta = highest_time - tab.last_active_time;
578 contents->SetLastActiveTime(now - delta);
580 RestoredTab restored_tab(contents, false,
581 tab.extension_app_id.empty(), tab.pinned);
582 created_contents->push_back(restored_tab);
588 // |tab_index| is ignored for pinned tabs which will always be pushed behind
589 // the last existing pinned tab.
590 // |tab_loader_| will schedule this tab for loading if |is_selected_tab| is
591 // false.
592 WebContents* RestoreTab(const sessions::SessionTab& tab,
593 const int tab_index,
594 Browser* browser,
595 bool is_selected_tab) {
596 // It's possible (particularly for foreign sessions) to receive a tab
597 // without valid navigations. In that case, just skip it.
598 // See crbug.com/154129.
599 if (tab.navigations.empty())
600 return nullptr;
601 int selected_index = tab.current_navigation_index;
602 selected_index = std::max(
604 std::min(selected_index, static_cast<int>(tab.navigations.size() - 1)));
606 RecordAppLaunchForTab(browser, tab, selected_index);
608 // Associate sessionStorage (if any) to the restored tab.
609 scoped_refptr<content::SessionStorageNamespace> session_storage_namespace;
610 if (!tab.session_storage_persistent_id.empty()) {
611 session_storage_namespace =
612 content::BrowserContext::GetDefaultStoragePartition(profile_)
613 ->GetDOMStorageContext()
614 ->RecreateSessionStorage(tab.session_storage_persistent_id);
617 WebContents* web_contents = chrome::AddRestoredTab(
618 browser, tab.navigations, tab_index, selected_index,
619 tab.extension_app_id,
620 false, // select
621 tab.pinned, true, session_storage_namespace.get(),
622 tab.user_agent_override);
623 // Regression check: check that the tab didn't start loading right away. The
624 // focused tab will be loaded by Browser, and TabLoader will load the rest.
625 DCHECK(web_contents->GetController().NeedsReload());
627 return web_contents;
630 Browser* CreateRestoredBrowser(Browser::Type type,
631 gfx::Rect bounds,
632 ui::WindowShowState show_state,
633 const std::string& app_name) {
634 Browser::CreateParams params(type, profile_, host_desktop_type_);
635 if (!app_name.empty()) {
636 const bool trusted_source = true; // We only store trusted app windows.
637 params = Browser::CreateParams::CreateForApp(
638 app_name, trusted_source, bounds, profile_, host_desktop_type_);
639 } else {
640 params.initial_bounds = bounds;
642 params.initial_show_state = show_state;
643 params.is_session_restore = true;
644 return new Browser(params);
647 void ShowBrowser(Browser* browser, int selected_tab_index) {
648 DCHECK(browser);
649 DCHECK(browser->tab_strip_model()->count());
650 browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true);
652 if (browser_ == browser)
653 return;
655 browser->window()->Show();
656 browser->set_is_session_restore(false);
658 // TODO(jcampan): http://crbug.com/8123 we should not need to set the
659 // initial focus explicitly.
660 browser->tab_strip_model()->GetActiveWebContents()->SetInitialFocus();
663 // Appends the urls in |urls| to |browser|.
664 void AppendURLsToBrowser(Browser* browser, const std::vector<GURL>& urls) {
665 for (size_t i = 0; i < urls.size(); ++i) {
666 int add_types = TabStripModel::ADD_FORCE_INDEX;
667 if (i == 0)
668 add_types |= TabStripModel::ADD_ACTIVE;
669 chrome::NavigateParams params(browser, urls[i],
670 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
671 params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
672 params.tabstrip_add_types = add_types;
673 chrome::Navigate(&params);
677 // Invokes TabRestored on the SessionService for all tabs in browser after
678 // initial_count.
679 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
680 SessionService* session_service =
681 SessionServiceFactory::GetForProfile(profile_);
682 if (!session_service)
683 return;
684 TabStripModel* tab_strip = browser->tab_strip_model();
685 for (int i = initial_count; i < tab_strip->count(); ++i)
686 session_service->TabRestored(tab_strip->GetWebContentsAt(i),
687 tab_strip->IsTabPinned(i));
690 // The profile to create the sessions for.
691 Profile* profile_;
693 // The first browser to restore to, may be null.
694 Browser* browser_;
696 // The desktop on which all new browsers should be created (browser_, if it is
697 // not NULL, must be of this desktop type as well).
698 chrome::HostDesktopType host_desktop_type_;
700 // Whether or not restore is synchronous.
701 const bool synchronous_;
703 // The quit-closure to terminate the nested message-loop started for
704 // synchronous session-restore.
705 base::Closure quit_closure_for_sync_restore_;
707 // See description of CLOBBER_CURRENT_TAB.
708 const bool clobber_existing_tab_;
710 // If true and there is an error or there are no windows to restore, we
711 // create a tabbed browser anyway. This is used on startup to make sure at
712 // at least one window is created.
713 const bool always_create_tabbed_browser_;
715 // Set of URLs to open in addition to those restored from the session.
716 std::vector<GURL> urls_to_open_;
718 // Used to get the session.
719 base::CancelableTaskTracker cancelable_task_tracker_;
721 // Responsible for loading the tabs.
722 scoped_refptr<TabLoader> tab_loader_;
724 // When synchronous we run a nested message loop. To avoid creating windows
725 // from the nested message loop (which can make exiting the nested message
726 // loop take a while) we cache the SessionWindows here and create the actual
727 // windows when the nested message loop exits.
728 std::vector<sessions::SessionWindow*> windows_;
729 SessionID::id_type active_window_id_;
731 content::NotificationRegistrar registrar_;
733 // The time we started the restore.
734 base::TimeTicks restore_started_;
736 // List of callbacks for session restore notification.
737 SessionRestore::CallbackList* on_session_restored_callbacks_;
739 DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl);
742 } // namespace
744 // SessionRestore -------------------------------------------------------------
746 // static
747 Browser* SessionRestore::RestoreSession(
748 Profile* profile,
749 Browser* browser,
750 chrome::HostDesktopType host_desktop_type,
751 uint32 behavior,
752 const std::vector<GURL>& urls_to_open) {
753 #if defined(OS_CHROMEOS)
754 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
755 "SessionRestore-Start", false);
756 #endif
757 DCHECK(profile);
758 // Always restore from the original profile (incognito profiles have no
759 // session service).
760 profile = profile->GetOriginalProfile();
761 if (!SessionServiceFactory::GetForProfile(profile)) {
762 NOTREACHED();
763 return nullptr;
765 profile->set_restored_last_session(true);
766 // SessionRestoreImpl takes care of deleting itself when done.
767 SessionRestoreImpl* restorer = new SessionRestoreImpl(
768 profile, browser, host_desktop_type, (behavior & SYNCHRONOUS) != 0,
769 (behavior & CLOBBER_CURRENT_TAB) != 0,
770 (behavior & ALWAYS_CREATE_TABBED_BROWSER) != 0,
771 urls_to_open,
772 SessionRestore::on_session_restored_callbacks());
773 return restorer->Restore();
776 // static
777 void SessionRestore::RestoreSessionAfterCrash(Browser* browser) {
778 uint32 behavior = 0;
779 if (browser->tab_strip_model()->count() == 1) {
780 const content::WebContents* active_tab =
781 browser->tab_strip_model()->GetWebContentsAt(0);
782 if (active_tab->GetURL() == GURL(chrome::kChromeUINewTabURL) ||
783 search::IsInstantNTP(active_tab)) {
784 // There is only one tab and its the new tab page, make session restore
785 // clobber it.
786 behavior = SessionRestore::CLOBBER_CURRENT_TAB;
789 SessionRestore::RestoreSession(browser->profile(), browser,
790 browser->host_desktop_type(), behavior,
791 std::vector<GURL>());
794 // static
795 std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows(
796 Profile* profile,
797 chrome::HostDesktopType host_desktop_type,
798 std::vector<const sessions::SessionWindow*>::const_iterator begin,
799 std::vector<const sessions::SessionWindow*>::const_iterator end) {
800 std::vector<GURL> gurls;
801 SessionRestoreImpl restorer(profile, static_cast<Browser*>(nullptr),
802 host_desktop_type, true, false, true, gurls,
803 on_session_restored_callbacks());
804 return restorer.RestoreForeignSession(begin, end);
807 // static
808 WebContents* SessionRestore::RestoreForeignSessionTab(
809 content::WebContents* source_web_contents,
810 const sessions::SessionTab& tab,
811 WindowOpenDisposition disposition) {
812 Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents);
813 Profile* profile = browser->profile();
814 std::vector<GURL> gurls;
815 SessionRestoreImpl restorer(profile, browser, browser->host_desktop_type(),
816 true, false, false, gurls,
817 on_session_restored_callbacks());
818 return restorer.RestoreForeignTab(tab, disposition);
821 // static
822 bool SessionRestore::IsRestoring(const Profile* profile) {
823 if (active_session_restorers == nullptr)
824 return false;
825 for (std::set<SessionRestoreImpl*>::const_iterator it =
826 active_session_restorers->begin();
827 it != active_session_restorers->end(); ++it) {
828 if ((*it)->profile() == profile)
829 return true;
831 return false;
834 // static
835 bool SessionRestore::IsRestoringSynchronously() {
836 if (!active_session_restorers)
837 return false;
838 for (std::set<SessionRestoreImpl*>::const_iterator it =
839 active_session_restorers->begin();
840 it != active_session_restorers->end(); ++it) {
841 if ((*it)->synchronous())
842 return true;
844 return false;
847 // static
848 SessionRestore::CallbackSubscription
849 SessionRestore::RegisterOnSessionRestoredCallback(
850 const base::Callback<void(int)>& callback) {
851 return on_session_restored_callbacks()->Add(callback);
854 // static
855 SessionRestore::SmartRestoreMode SessionRestore::GetSmartRestoreMode() {
856 std::string prioritize_tabs = variations::GetVariationParamValue(
857 "IntelligentSessionRestore", "PrioritizeTabs");
858 if (prioritize_tabs == "mru")
859 return SMART_RESTORE_MODE_MRU;
860 if (prioritize_tabs == "simple")
861 return SMART_RESTORE_MODE_SIMPLE;
862 return SMART_RESTORE_MODE_OFF;
865 // static
866 base::CallbackList<void(int)>*
867 SessionRestore::on_session_restored_callbacks_ = nullptr;