This source file includes following definitions.
- ScheduleLoad
- TabIsLoading
- StartLoading
- max_parallel_tab_loads_
- LoadNextTab
- Observe
- OnConnectionTypeChanged
- RemoveTab
- ForceLoadTimerFired
- GetRenderWidgetHost
- RegisterForNotifications
- HandleTabClosedOrLoaded
- browser_shown_
- synchronous
- Restore
- RestoreForeignSession
- RestoreForeignTab
- Observe
- profile
- StartTabCreation
- FinishedTabCreation
- OnGotSession
- ProcessSessionWindows
- RecordAppLaunchForTab
- RestoreTabsToBrowser
- RestoreTab
- CreateRestoredBrowser
- ShowBrowser
- AppendURLsToBrowser
- NotifySessionServiceOfRestoredTabs
- RestoreSession
- RestoreForeignSessionWindows
- RestoreForeignSessionTab
- IsRestoring
- IsRestoringSynchronously
#include "chrome/browser/sessions/session_restore.h"
#include <algorithm>
#include <list>
#include <set>
#include <string>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/metrics/histogram.h"
#include "base/platform_file.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/performance_monitor/startup_timer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_tabrestore.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "net/base/network_change_notifier.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/boot_times_loader.h"
#endif
#if defined(OS_WIN)
#include "win8/util/win8_util.h"
#endif
using content::NavigationController;
using content::RenderWidgetHost;
using content::WebContents;
namespace {
class SessionRestoreImpl;
class TabLoader;
TabLoader* shared_tab_loader = NULL;
std::set<SessionRestoreImpl*>* active_session_restorers = NULL;
static const int kInitialDelayTimerMS = 100;
class TabLoader : public content::NotificationObserver,
public net::NetworkChangeNotifier::ConnectionTypeObserver,
public base::RefCounted<TabLoader> {
public:
static TabLoader* GetTabLoader(base::TimeTicks restore_started);
void ScheduleLoad(NavigationController* controller);
void TabIsLoading(NavigationController* controller);
void StartLoading();
private:
friend class base::RefCounted<TabLoader>;
typedef std::set<NavigationController*> TabsLoading;
typedef std::list<NavigationController*> TabsToLoad;
typedef std::set<RenderWidgetHost*> RenderWidgetHostSet;
explicit TabLoader(base::TimeTicks restore_started);
virtual ~TabLoader();
void LoadNextTab();
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
virtual void OnConnectionTypeChanged(
net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
void RemoveTab(NavigationController* tab);
void ForceLoadTimerFired();
static RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab);
void RegisterForNotifications(NavigationController* controller);
void HandleTabClosedOrLoaded(NavigationController* controller);
content::NotificationRegistrar registrar_;
int64 force_load_delay_;
bool loading_;
bool got_first_paint_;
TabsLoading tabs_loading_;
TabsToLoad tabs_to_load_;
RenderWidgetHostSet render_widget_hosts_loading_;
RenderWidgetHostSet render_widget_hosts_to_paint_;
int tab_count_;
base::OneShotTimer<TabLoader> force_load_timer_;
base::TimeTicks restore_started_;
size_t max_parallel_tab_loads_;
scoped_refptr<TabLoader> this_retainer_;
DISALLOW_COPY_AND_ASSIGN(TabLoader);
};
TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) {
if (!shared_tab_loader)
shared_tab_loader = new TabLoader(restore_started);
return shared_tab_loader;
}
void TabLoader::ScheduleLoad(NavigationController* controller) {
DCHECK(controller);
DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) ==
tabs_to_load_.end());
tabs_to_load_.push_back(controller);
RegisterForNotifications(controller);
}
void TabLoader::TabIsLoading(NavigationController* controller) {
DCHECK(controller);
DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) ==
tabs_loading_.end());
tabs_loading_.insert(controller);
RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller);
DCHECK(render_widget_host);
render_widget_hosts_loading_.insert(render_widget_host);
RegisterForNotifications(controller);
}
void TabLoader::StartLoading() {
if (loading_)
return;
registrar_.Add(
this,
content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
content::NotificationService::AllSources());
this_retainer_ = this;
#if defined(OS_CHROMEOS)
if (!net::NetworkChangeNotifier::IsOffline()) {
loading_ = true;
LoadNextTab();
} else {
net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
}
#else
loading_ = true;
LoadNextTab();
#endif
}
TabLoader::TabLoader(base::TimeTicks restore_started)
: force_load_delay_(kInitialDelayTimerMS),
loading_(false),
got_first_paint_(false),
tab_count_(0),
restore_started_(restore_started),
max_parallel_tab_loads_(0) {
}
TabLoader::~TabLoader() {
DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
tabs_loading_.empty() && tabs_to_load_.empty());
net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
shared_tab_loader = NULL;
}
void TabLoader::LoadNextTab() {
if (!tabs_to_load_.empty()) {
NavigationController* tab = tabs_to_load_.front();
DCHECK(tab);
tabs_loading_.insert(tab);
if (tabs_loading_.size() > max_parallel_tab_loads_)
max_parallel_tab_loads_ = tabs_loading_.size();
tabs_to_load_.pop_front();
tab->LoadIfNecessary();
content::WebContents* contents = tab->GetWebContents();
if (contents) {
Browser* browser = chrome::FindBrowserWithWebContents(contents);
if (browser &&
browser->tab_strip_model()->GetActiveWebContents() != contents) {
contents->WasHidden();
}
}
}
if (!tabs_to_load_.empty()) {
force_load_timer_.Stop();
force_load_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(force_load_delay_),
this, &TabLoader::ForceLoadTimerFired);
}
if (tabs_to_load_.empty() && !SessionRestore::IsRestoringSynchronously()) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_SESSION_RESTORE_DONE,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
}
}
void TabLoader::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_LOAD_START: {
NavigationController* tab =
content::Source<NavigationController>(source).ptr();
RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab);
DCHECK(render_widget_host);
render_widget_hosts_loading_.insert(render_widget_host);
break;
}
case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
WebContents* web_contents = content::Source<WebContents>(source).ptr();
if (!got_first_paint_) {
RenderWidgetHost* render_widget_host =
GetRenderWidgetHost(&web_contents->GetController());
render_widget_hosts_loading_.erase(render_widget_host);
}
HandleTabClosedOrLoaded(&web_contents->GetController());
break;
}
case content::NOTIFICATION_LOAD_STOP: {
NavigationController* tab =
content::Source<NavigationController>(source).ptr();
render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab));
HandleTabClosedOrLoaded(tab);
break;
}
case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
RenderWidgetHost* render_widget_host =
content::Source<RenderWidgetHost>(source).ptr();
if (!got_first_paint_ && render_widget_host->GetView() &&
render_widget_host->GetView()->IsShowing()) {
if (render_widget_hosts_to_paint_.find(render_widget_host) !=
render_widget_hosts_to_paint_.end()) {
got_first_paint_ = true;
base::TimeDelta time_to_paint =
base::TimeTicks::Now() - restore_started_;
UMA_HISTOGRAM_CUSTOM_TIMES(
"SessionRestore.FirstTabPainted",
time_to_paint,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(100),
100);
std::string time_for_count =
base::StringPrintf("SessionRestore.FirstTabPainted_%d",
tab_count_);
base::HistogramBase* counter_for_count =
base::Histogram::FactoryTimeGet(
time_for_count,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(100),
100,
base::Histogram::kUmaTargetedHistogramFlag);
counter_for_count->AddTime(time_to_paint);
} else if (render_widget_hosts_loading_.find(render_widget_host) ==
render_widget_hosts_loading_.end()) {
got_first_paint_ = true;
}
}
break;
}
default:
NOTREACHED() << "Unknown notification received:" << type;
}
if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
tabs_loading_.empty() && tabs_to_load_.empty())
this_retainer_ = NULL;
}
void TabLoader::OnConnectionTypeChanged(
net::NetworkChangeNotifier::ConnectionType type) {
if (type != net::NetworkChangeNotifier::CONNECTION_NONE) {
if (!loading_) {
loading_ = true;
LoadNextTab();
}
} else {
loading_ = false;
}
}
void TabLoader::RemoveTab(NavigationController* tab) {
registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<WebContents>(tab->GetWebContents()));
registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(tab));
registrar_.Remove(this, content::NOTIFICATION_LOAD_START,
content::Source<NavigationController>(tab));
TabsLoading::iterator i = tabs_loading_.find(tab);
if (i != tabs_loading_.end())
tabs_loading_.erase(i);
TabsToLoad::iterator j =
find(tabs_to_load_.begin(), tabs_to_load_.end(), tab);
if (j != tabs_to_load_.end())
tabs_to_load_.erase(j);
}
void TabLoader::ForceLoadTimerFired() {
force_load_delay_ *= 2;
LoadNextTab();
}
RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) {
WebContents* web_contents = tab->GetWebContents();
if (web_contents) {
content::RenderWidgetHostView* render_widget_host_view =
web_contents->GetRenderWidgetHostView();
if (render_widget_host_view)
return render_widget_host_view->GetRenderWidgetHost();
}
return NULL;
}
void TabLoader::RegisterForNotifications(NavigationController* controller) {
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<WebContents>(controller->GetWebContents()));
registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(controller));
registrar_.Add(this, content::NOTIFICATION_LOAD_START,
content::Source<NavigationController>(controller));
++tab_count_;
}
void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) {
RemoveTab(tab);
if (loading_)
LoadNextTab();
if (tabs_loading_.empty() && tabs_to_load_.empty()) {
base::TimeDelta time_to_load =
base::TimeTicks::Now() - restore_started_;
performance_monitor::StartupTimer::SetElapsedSessionRestoreTime(
time_to_load);
UMA_HISTOGRAM_CUSTOM_TIMES(
"SessionRestore.AllTabsLoaded",
time_to_load,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(100),
100);
std::string time_for_count =
base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_);
base::HistogramBase* counter_for_count =
base::Histogram::FactoryTimeGet(
time_for_count,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(100),
100,
base::Histogram::kUmaTargetedHistogramFlag);
counter_for_count->AddTime(time_to_load);
UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
max_parallel_tab_loads_);
}
}
class SessionRestoreImpl : public content::NotificationObserver {
public:
SessionRestoreImpl(Profile* profile,
Browser* browser,
chrome::HostDesktopType host_desktop_type,
bool synchronous,
bool clobber_existing_tab,
bool always_create_tabbed_browser,
const std::vector<GURL>& urls_to_open)
: profile_(profile),
browser_(browser),
host_desktop_type_(host_desktop_type),
synchronous_(synchronous),
clobber_existing_tab_(clobber_existing_tab),
always_create_tabbed_browser_(always_create_tabbed_browser),
urls_to_open_(urls_to_open),
active_window_id_(0),
restore_started_(base::TimeTicks::Now()),
browser_shown_(false) {
DCHECK(!browser || browser->host_desktop_type() == host_desktop_type);
if (active_session_restorers == NULL)
active_session_restorers = new std::set<SessionRestoreImpl*>();
std::set<SessionRestoreImpl*>::const_iterator it;
for (it = active_session_restorers->begin();
it != active_session_restorers->end(); ++it) {
if ((*it)->profile_ == profile)
break;
}
DCHECK(it == active_session_restorers->end());
active_session_restorers->insert(this);
g_browser_process->AddRefModule();
}
bool synchronous() const { return synchronous_; }
Browser* Restore() {
SessionService* session_service =
SessionServiceFactory::GetForProfile(profile_);
DCHECK(session_service);
session_service->GetLastSession(
base::Bind(&SessionRestoreImpl::OnGotSession, base::Unretained(this)),
&cancelable_task_tracker_);
if (synchronous_) {
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
base::MessageLoop::current()->Run();
}
Browser* browser = ProcessSessionWindows(&windows_, active_window_id_);
delete this;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_SESSION_RESTORE_DONE,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
return browser;
}
if (browser_) {
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
content::Source<Browser>(browser_));
}
return browser_;
}
std::vector<Browser*> RestoreForeignSession(
std::vector<const SessionWindow*>::const_iterator begin,
std::vector<const SessionWindow*>::const_iterator end) {
StartTabCreation();
std::vector<Browser*> browsers;
for (std::vector<const SessionWindow*>::const_iterator i = begin;
i != end; ++i) {
Browser* browser = CreateRestoredBrowser(
static_cast<Browser::Type>((*i)->type),
(*i)->bounds,
(*i)->show_state,
(*i)->app_name);
browsers.push_back(browser);
const int initial_tab_count = 0;
int selected_tab_index = std::max(
0,
std::min((*i)->selected_tab_index,
static_cast<int>((*i)->tabs.size()) - 1));
RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
selected_tab_index);
NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
}
FinishedTabCreation(true, true);
return browsers;
}
WebContents* RestoreForeignTab(const SessionTab& tab,
WindowOpenDisposition disposition) {
DCHECK(!tab.navigations.empty());
int selected_index = tab.current_navigation_index;
selected_index = std::max(
0,
std::min(selected_index,
static_cast<int>(tab.navigations.size() - 1)));
bool use_new_window = disposition == NEW_WINDOW;
Browser* browser = use_new_window ?
new Browser(Browser::CreateParams(profile_, host_desktop_type_)) :
browser_;
RecordAppLaunchForTab(browser, tab, selected_index);
WebContents* web_contents;
if (disposition == CURRENT_TAB) {
DCHECK(!use_new_window);
web_contents = chrome::ReplaceRestoredTab(browser,
tab.navigations,
selected_index,
true,
tab.extension_app_id,
NULL,
tab.user_agent_override);
} else {
int tab_index =
use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
web_contents = chrome::AddRestoredTab(
browser,
tab.navigations,
tab_index,
selected_index,
tab.extension_app_id,
disposition == NEW_FOREGROUND_TAB,
tab.pinned,
true,
NULL,
tab.user_agent_override);
web_contents->GetController().LoadIfNecessary();
}
if (use_new_window) {
browser->tab_strip_model()->ActivateTabAt(0, true);
browser->window()->Show();
}
NotifySessionServiceOfRestoredTabs(browser,
browser->tab_strip_model()->count());
DCHECK(synchronous_);
return web_contents;
}
virtual ~SessionRestoreImpl() {
STLDeleteElements(&windows_);
active_session_restorers->erase(this);
if (active_session_restorers->empty()) {
delete active_session_restorers;
active_session_restorers = NULL;
}
g_browser_process->ReleaseModule();
}
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE {
switch (type) {
case chrome::NOTIFICATION_BROWSER_CLOSED:
delete this;
return;
default:
NOTREACHED();
break;
}
}
Profile* profile() { return profile_; }
private:
void StartTabCreation() {
tab_loader_ = TabLoader::GetTabLoader(restore_started_);
}
Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) {
Browser* browser = NULL;
if (!created_tabbed_browser && always_create_tabbed_browser_) {
browser = new Browser(Browser::CreateParams(profile_,
host_desktop_type_));
if (urls_to_open_.empty()) {
urls_to_open_.push_back(GURL());
}
AppendURLsToBrowser(browser, urls_to_open_);
browser->window()->Show();
}
if (succeeded) {
DCHECK(tab_loader_.get());
tab_loader_->StartLoading();
tab_loader_ = NULL;
}
if (!synchronous_) {
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
registrar_.RemoveAll();
}
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-End", false);
#endif
return browser;
}
void OnGotSession(ScopedVector<SessionWindow> windows,
SessionID::id_type active_window_id) {
base::TimeDelta time_to_got_sessions =
base::TimeTicks::Now() - restore_started_;
UMA_HISTOGRAM_CUSTOM_TIMES(
"SessionRestore.TimeToGotSessions",
time_to_got_sessions,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(1000),
100);
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-GotSession", false);
#endif
if (synchronous_) {
windows_.swap(windows.get());
active_window_id_ = active_window_id;
base::MessageLoop::current()->QuitNow();
return;
}
ProcessSessionWindows(&windows.get(), active_window_id);
}
Browser* ProcessSessionWindows(std::vector<SessionWindow*>* windows,
SessionID::id_type active_window_id) {
VLOG(1) << "ProcessSessionWindows " << windows->size();
base::TimeDelta time_to_process_sessions =
base::TimeTicks::Now() - restore_started_;
UMA_HISTOGRAM_CUSTOM_TIMES(
"SessionRestore.TimeToProcessSessions",
time_to_process_sessions,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(1000),
100);
if (windows->empty()) {
content::BrowserContext::GetDefaultStoragePartition(profile_)->
GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
return FinishedTabCreation(false, false);
}
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-CreatingTabs-Start", false);
#endif
StartTabCreation();
Browser* last_browser = NULL;
bool has_tabbed_browser = false;
Browser* browser_to_activate = NULL;
#if defined(OS_WIN)
int selected_tab_to_activate = -1;
#endif
bool has_visible_browser = false;
for (std::vector<SessionWindow*>::iterator i = windows->begin();
i != windows->end(); ++i) {
if ((*i)->show_state != ui::SHOW_STATE_MINIMIZED)
has_visible_browser = true;
}
for (std::vector<SessionWindow*>::iterator i = windows->begin();
i != windows->end(); ++i) {
Browser* browser = NULL;
if (!has_tabbed_browser && (*i)->type == Browser::TYPE_TABBED)
has_tabbed_browser = true;
if (i == windows->begin() && (*i)->type == Browser::TYPE_TABBED &&
browser_ && browser_->is_type_tabbed() &&
!browser_->profile()->IsOffTheRecord()) {
browser = browser_;
} else {
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-CreateRestoredBrowser-Start", false);
#endif
ui::WindowShowState show_state = (*i)->show_state;
if (!has_visible_browser) {
show_state = ui::SHOW_STATE_NORMAL;
has_visible_browser = true;
}
browser = NULL;
#if defined(OS_WIN)
if (win8::IsSingleWindowMetroMode()) {
if (browser_ && !browser_->profile()->IsOffTheRecord()) {
browser = browser_;
} else {
browser = last_browser;
DCHECK(!browser || !browser->profile()->IsOffTheRecord());
}
DCHECK(!browser || browser->is_type_tabbed());
DCHECK((*i)->type == Browser::TYPE_TABBED);
}
#endif
if (!browser) {
browser = CreateRestoredBrowser(
static_cast<Browser::Type>((*i)->type),
(*i)->bounds,
show_state,
(*i)->app_name);
}
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-CreateRestoredBrowser-End", false);
#endif
}
if ((*i)->type == Browser::TYPE_TABBED)
last_browser = browser;
WebContents* active_tab =
browser->tab_strip_model()->GetActiveWebContents();
int initial_tab_count = browser->tab_strip_model()->count();
bool close_active_tab = clobber_existing_tab_ &&
i == windows->begin() &&
(*i)->type == Browser::TYPE_TABBED &&
active_tab && browser == browser_ &&
(*i)->tabs.size() > 0;
if (close_active_tab)
--initial_tab_count;
int selected_tab_index =
initial_tab_count > 0 ? browser->tab_strip_model()->active_index()
: std::max(0,
std::min((*i)->selected_tab_index,
static_cast<int>((*i)->tabs.size()) - 1));
if ((*i)->window_id.id() == active_window_id) {
browser_to_activate = browser;
#if defined(OS_WIN)
selected_tab_to_activate = selected_tab_index;
#endif
}
RestoreTabsToBrowser(*(*i), browser, initial_tab_count,
selected_tab_index);
NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
if (close_active_tab)
chrome::CloseWebContents(browser, active_tab, true);
#if defined(OS_WIN)
selected_tab_to_activate = -1;
#endif
}
if (browser_to_activate && browser_to_activate->is_type_tabbed())
last_browser = browser_to_activate;
if (last_browser && !urls_to_open_.empty())
AppendURLsToBrowser(last_browser, urls_to_open_);
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-CreatingTabs-End", false);
#endif
if (browser_to_activate) {
browser_to_activate->window()->Activate();
#if defined(OS_WIN)
if (win8::IsSingleWindowMetroMode() && selected_tab_to_activate != -1)
ShowBrowser(browser_to_activate, selected_tab_to_activate);
#endif
}
Browser* finished_browser = FinishedTabCreation(true, has_tabbed_browser);
if (finished_browser)
last_browser = finished_browser;
content::BrowserContext::GetDefaultStoragePartition(profile_)->
GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
return last_browser;
}
void RecordAppLaunchForTab(Browser* browser,
const SessionTab& tab,
int selected_index) {
DCHECK(selected_index >= 0 &&
selected_index < static_cast<int>(tab.navigations.size()));
GURL url = tab.navigations[selected_index].virtual_url();
if (browser->profile()->GetExtensionService()) {
const extensions::Extension* extension =
browser->profile()->GetExtensionService()->GetInstalledApp(url);
if (extension) {
CoreAppLauncherHandler::RecordAppLaunchType(
extension_misc::APP_LAUNCH_SESSION_RESTORE,
extension->GetType());
}
}
}
void RestoreTabsToBrowser(const SessionWindow& window,
Browser* browser,
int initial_tab_count,
int selected_tab_index) {
VLOG(1) << "RestoreTabsToBrowser " << window.tabs.size();
DCHECK(!window.tabs.empty());
if (initial_tab_count == 0) {
for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
const SessionTab& tab = *(window.tabs[i]);
if (i == selected_tab_index) {
ShowBrowser(browser,
browser->tab_strip_model()->GetIndexOfWebContents(
RestoreTab(tab, i, browser, false)));
tab_loader_->TabIsLoading(
&browser->tab_strip_model()->GetActiveWebContents()->
GetController());
} else {
RestoreTab(tab, i, browser, true);
}
}
} else {
int tab_index_offset = initial_tab_count;
for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) {
const SessionTab& tab = *(window.tabs[i]);
RestoreTab(tab, tab_index_offset + i, browser, true);
}
}
}
WebContents* RestoreTab(const SessionTab& tab,
const int tab_index,
Browser* browser,
bool schedule_load) {
if (tab.navigations.empty())
return NULL;
int selected_index = tab.current_navigation_index;
selected_index = std::max(
0,
std::min(selected_index,
static_cast<int>(tab.navigations.size() - 1)));
RecordAppLaunchForTab(browser, tab, selected_index);
scoped_refptr<content::SessionStorageNamespace> session_storage_namespace;
if (!tab.session_storage_persistent_id.empty()) {
session_storage_namespace =
content::BrowserContext::GetDefaultStoragePartition(profile_)->
GetDOMStorageContext()->RecreateSessionStorage(
tab.session_storage_persistent_id);
}
WebContents* web_contents =
chrome::AddRestoredTab(browser,
tab.navigations,
tab_index,
selected_index,
tab.extension_app_id,
false,
tab.pinned,
true,
session_storage_namespace.get(),
tab.user_agent_override);
DCHECK(web_contents->GetController().NeedsReload());
const int id = web_contents->GetRenderProcessHost()->GetID();
const content::PageState& page_state =
tab.navigations.at(selected_index).page_state();
const std::vector<base::FilePath>& file_paths =
page_state.GetReferencedFiles();
for (std::vector<base::FilePath>::const_iterator file = file_paths.begin();
file != file_paths.end(); ++file) {
content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id,
*file);
}
if (schedule_load)
tab_loader_->ScheduleLoad(&web_contents->GetController());
return web_contents;
}
Browser* CreateRestoredBrowser(Browser::Type type,
gfx::Rect bounds,
ui::WindowShowState show_state,
const std::string& app_name) {
Browser::CreateParams params(type, profile_, host_desktop_type_);
params.app_name = app_name;
params.initial_bounds = bounds;
params.initial_show_state = show_state;
params.is_session_restore = true;
return new Browser(params);
}
void ShowBrowser(Browser* browser, int selected_tab_index) {
DCHECK(browser);
DCHECK(browser->tab_strip_model()->count());
browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true);
if (browser_ == browser)
return;
browser->window()->Show();
browser->set_is_session_restore(false);
browser->tab_strip_model()->GetActiveWebContents()->
GetView()->SetInitialFocus();
if (!browser_shown_) {
browser_shown_ = true;
base::TimeDelta time_to_first_show =
base::TimeTicks::Now() - restore_started_;
UMA_HISTOGRAM_CUSTOM_TIMES(
"SessionRestore.TimeToFirstShow",
time_to_first_show,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(1000),
100);
}
}
void AppendURLsToBrowser(Browser* browser,
const std::vector<GURL>& urls) {
for (size_t i = 0; i < urls.size(); ++i) {
int add_types = TabStripModel::ADD_FORCE_INDEX;
if (i == 0)
add_types |= TabStripModel::ADD_ACTIVE;
chrome::NavigateParams params(browser, urls[i],
content::PAGE_TRANSITION_AUTO_TOPLEVEL);
params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
params.tabstrip_add_types = add_types;
chrome::Navigate(¶ms);
}
}
void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) {
SessionService* session_service =
SessionServiceFactory::GetForProfile(profile_);
if (!session_service)
return;
TabStripModel* tab_strip = browser->tab_strip_model();
for (int i = initial_count; i < tab_strip->count(); ++i)
session_service->TabRestored(tab_strip->GetWebContentsAt(i),
tab_strip->IsTabPinned(i));
}
Profile* profile_;
Browser* browser_;
chrome::HostDesktopType host_desktop_type_;
const bool synchronous_;
const bool clobber_existing_tab_;
const bool always_create_tabbed_browser_;
std::vector<GURL> urls_to_open_;
base::CancelableTaskTracker cancelable_task_tracker_;
scoped_refptr<TabLoader> tab_loader_;
std::vector<SessionWindow*> windows_;
SessionID::id_type active_window_id_;
content::NotificationRegistrar registrar_;
base::TimeTicks restore_started_;
bool browser_shown_;
DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl);
};
}
Browser* SessionRestore::RestoreSession(
Profile* profile,
Browser* browser,
chrome::HostDesktopType host_desktop_type,
uint32 behavior,
const std::vector<GURL>& urls_to_open) {
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
"SessionRestore-Start", false);
#endif
DCHECK(profile);
profile = profile->GetOriginalProfile();
if (!SessionServiceFactory::GetForProfile(profile)) {
NOTREACHED();
return NULL;
}
profile->set_restored_last_session(true);
SessionRestoreImpl* restorer = new SessionRestoreImpl(
profile, browser, host_desktop_type, (behavior & SYNCHRONOUS) != 0,
(behavior & CLOBBER_CURRENT_TAB) != 0,
(behavior & ALWAYS_CREATE_TABBED_BROWSER) != 0,
urls_to_open);
return restorer->Restore();
}
std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows(
Profile* profile,
chrome::HostDesktopType host_desktop_type,
std::vector<const SessionWindow*>::const_iterator begin,
std::vector<const SessionWindow*>::const_iterator end) {
std::vector<GURL> gurls;
SessionRestoreImpl restorer(profile,
static_cast<Browser*>(NULL), host_desktop_type, true, false, true, gurls);
return restorer.RestoreForeignSession(begin, end);
}
WebContents* SessionRestore::RestoreForeignSessionTab(
content::WebContents* source_web_contents,
const SessionTab& tab,
WindowOpenDisposition disposition) {
Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents);
Profile* profile = browser->profile();
std::vector<GURL> gurls;
SessionRestoreImpl restorer(profile, browser, browser->host_desktop_type(),
true, false, false, gurls);
return restorer.RestoreForeignTab(tab, disposition);
}
bool SessionRestore::IsRestoring(const Profile* profile) {
if (active_session_restorers == NULL)
return false;
for (std::set<SessionRestoreImpl*>::const_iterator it =
active_session_restorers->begin();
it != active_session_restorers->end(); ++it) {
if ((*it)->profile() == profile)
return true;
}
return false;
}
bool SessionRestore::IsRestoringSynchronously() {
if (!active_session_restorers)
return false;
for (std::set<SessionRestoreImpl*>::const_iterator it =
active_session_restorers->begin();
it != active_session_restorers->end(); ++it) {
if ((*it)->synchronous())
return true;
}
return false;
}