#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sessions/session_backend.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/sessions/base_session_service_delegate_impl.h"
#include "chrome/browser/sessions/session_command.h"
#include "chrome/browser/sessions/session_data_deleter.h"
#include "chrome/browser/sessions/session_restore.h"
+#include "chrome/browser/sessions/session_service_utils.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/ui/browser_iterator.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/extension.h"
+#include "components/sessions/content/content_serialized_navigation_builder.h"
#include "components/startup_metric_utils/startup_metric_utils.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/web_contents.h"
+#include "extensions/common/extension.h"
#if defined(OS_MACOSX)
#include "chrome/browser/app_controller_mac.h"
using base::Time;
using content::NavigationEntry;
using content::WebContents;
+using sessions::ContentSerializedNavigationBuilder;
using sessions::SerializedNavigationEntry;
-// Identifier for commands written to file.
-static const SessionCommand::id_type kCommandSetTabWindow = 0;
-// OBSOLETE Superseded by kCommandSetWindowBounds3.
-// static const SessionCommand::id_type kCommandSetWindowBounds = 1;
-static const SessionCommand::id_type kCommandSetTabIndexInWindow = 2;
-// Original kCommandTabClosed/kCommandWindowClosed. See comment in
-// MigrateClosedPayload for details on why they were replaced.
-static const SessionCommand::id_type kCommandTabClosedObsolete = 3;
-static const SessionCommand::id_type kCommandWindowClosedObsolete = 4;
-static const SessionCommand::id_type
- kCommandTabNavigationPathPrunedFromBack = 5;
-static const SessionCommand::id_type kCommandUpdateTabNavigation = 6;
-static const SessionCommand::id_type kCommandSetSelectedNavigationIndex = 7;
-static const SessionCommand::id_type kCommandSetSelectedTabInIndex = 8;
-static const SessionCommand::id_type kCommandSetWindowType = 9;
-// OBSOLETE Superseded by kCommandSetWindowBounds3. Except for data migration.
-// static const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
-static const SessionCommand::id_type
- kCommandTabNavigationPathPrunedFromFront = 11;
-static const SessionCommand::id_type kCommandSetPinnedState = 12;
-static const SessionCommand::id_type kCommandSetExtensionAppID = 13;
-static const SessionCommand::id_type kCommandSetWindowBounds3 = 14;
-static const SessionCommand::id_type kCommandSetWindowAppName = 15;
-static const SessionCommand::id_type kCommandTabClosed = 16;
-static const SessionCommand::id_type kCommandWindowClosed = 17;
-static const SessionCommand::id_type kCommandSetTabUserAgentOverride = 18;
-static const SessionCommand::id_type kCommandSessionStorageAssociated = 19;
-static const SessionCommand::id_type kCommandSetActiveWindow = 20;
-
// Every kWritesPerReset commands triggers recreating the file.
static const int kWritesPerReset = 250;
-namespace {
-
-// Various payload structures.
-struct ClosedPayload {
- SessionID::id_type id;
- int64 close_time;
-};
-
-struct WindowBoundsPayload2 {
- SessionID::id_type window_id;
- int32 x;
- int32 y;
- int32 w;
- int32 h;
- bool is_maximized;
-};
-
-struct WindowBoundsPayload3 {
- SessionID::id_type window_id;
- int32 x;
- int32 y;
- int32 w;
- int32 h;
- int32 show_state;
-};
-
-typedef SessionID::id_type ActiveWindowPayload;
-
-struct IDAndIndexPayload {
- SessionID::id_type id;
- int32 index;
-};
-
-typedef IDAndIndexPayload TabIndexInWindowPayload;
-
-typedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload;
-
-typedef IDAndIndexPayload SelectedNavigationIndexPayload;
-
-typedef IDAndIndexPayload SelectedTabInIndexPayload;
-
-typedef IDAndIndexPayload WindowTypePayload;
-
-typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload;
-
-struct PinnedStatePayload {
- SessionID::id_type tab_id;
- bool pinned_state;
-};
-
-// Returns the show state to store to disk based |state|.
-ui::WindowShowState AdjustShowState(ui::WindowShowState state) {
- switch (state) {
- case ui::SHOW_STATE_NORMAL:
- case ui::SHOW_STATE_MINIMIZED:
- case ui::SHOW_STATE_MAXIMIZED:
- case ui::SHOW_STATE_FULLSCREEN:
- case ui::SHOW_STATE_DETACHED:
- return state;
-
- case ui::SHOW_STATE_DEFAULT:
- case ui::SHOW_STATE_INACTIVE:
- case ui::SHOW_STATE_END:
- return ui::SHOW_STATE_NORMAL;
- }
- return ui::SHOW_STATE_NORMAL;
-}
-
-// Migrates a |ClosedPayload|, returning true on success (migration was
-// necessary and happened), or false (migration was not necessary or was not
-// successful).
-bool MigrateClosedPayload(const SessionCommand& command,
- ClosedPayload* payload) {
-#if defined(OS_CHROMEOS)
- // Pre M17 versions of chromeos were 32bit. Post M17 is 64 bit. Apparently the
- // 32 bit versions of chrome on pre M17 resulted in a sizeof 12 for the
- // ClosedPayload, where as post M17 64-bit gives a sizeof 16 (presumably the
- // struct is padded).
- if ((command.id() == kCommandWindowClosedObsolete ||
- command.id() == kCommandTabClosedObsolete) &&
- command.size() == 12 && sizeof(payload->id) == 4 &&
- sizeof(payload->close_time) == 8) {
- memcpy(&payload->id, command.contents(), 4);
- memcpy(&payload->close_time, command.contents() + 4, 8);
- return true;
- } else {
- return false;
- }
-#else
- return false;
-#endif
-}
-
-} // namespace
-
// SessionService -------------------------------------------------------------
SessionService::SessionService(Profile* profile)
- : BaseSessionService(SESSION_RESTORE, profile, base::FilePath()),
+ : BaseSessionServiceDelegateImpl(true),
+ profile_(profile),
+ base_session_service_(
+ new BaseSessionService(BaseSessionService::SESSION_RESTORE,
+ profile->GetPath(),
+ this)),
has_open_trackable_browsers_(false),
move_on_new_browser_(false),
save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
- force_browser_not_alive_with_no_windows_(false) {
+ force_browser_not_alive_with_no_windows_(false),
+ weak_factory_(this) {
+ // We should never be created when incognito.
+ DCHECK(!profile->IsOffTheRecord());
Init();
}
SessionService::SessionService(const base::FilePath& save_path)
- : BaseSessionService(SESSION_RESTORE, NULL, save_path),
+ : BaseSessionServiceDelegateImpl(false),
+ profile_(NULL),
+ base_session_service_(
+ new BaseSessionService(BaseSessionService::SESSION_RESTORE,
+ save_path,
+ this)),
has_open_trackable_browsers_(false),
move_on_new_browser_(false),
save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
- force_browser_not_alive_with_no_windows_(false) {
+ force_browser_not_alive_with_no_windows_(false),
+ weak_factory_(this) {
Init();
}
SessionService::~SessionService() {
// The BrowserList should outlive the SessionService since it's static and
- // the SessionService is a BrowserContextKeyedService.
+ // the SessionService is a KeyedService.
BrowserList::RemoveObserver(this);
- Save();
+ base_session_service_->Save();
+}
+
+bool SessionService::ShouldNewWindowStartSession() {
+ // ChromeOS and OSX have different ideas of application lifetime than
+ // the other platforms.
+ // On ChromeOS opening a new window should never start a new session.
+#if defined(OS_CHROMEOS)
+ if (!force_browser_not_alive_with_no_windows_)
+ return false;
+#endif
+ if (!has_open_trackable_browsers_ &&
+ !StartupBrowserCreator::InSynchronousProfileLaunch() &&
+ !SessionRestore::IsRestoring(profile())
+#if defined(OS_MACOSX)
+ // On OSX, a new window should not start a new session if it was opened
+ // from the dock or the menubar.
+ && !app_controller_mac::IsOpeningNewWindow()
+#endif // OS_MACOSX
+ ) {
+ return true;
+ }
+ return false;
}
bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) {
}
void SessionService::ResetFromCurrentBrowsers() {
- ScheduleReset();
+ ScheduleResetCommands();
}
void SessionService::MoveCurrentSessionToLastSession() {
window_closing_ids_.clear();
pending_window_close_ids_.clear();
- Save();
+ base_session_service_->MoveCurrentSessionToLastSession();
+}
- RunTaskOnBackendThread(
- FROM_HERE, base::Bind(&SessionBackend::MoveCurrentSessionToLastSession,
- backend()));
+void SessionService::DeleteLastSession() {
+ base_session_service_->DeleteLastSession();
}
void SessionService::SetTabWindow(const SessionID& window_id,
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreateSetTabWindowCommand(window_id, tab_id));
+ ScheduleCommand(CreateSetTabWindowCommand(window_id, tab_id).Pass());
}
void SessionService::SetWindowBounds(const SessionID& window_id,
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreateSetWindowBoundsCommand(window_id, bounds, show_state));
+ ScheduleCommand(
+ CreateSetWindowBoundsCommand(window_id, bounds, show_state).Pass());
}
void SessionService::SetTabIndexInWindow(const SessionID& window_id,
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreateSetTabIndexInWindowCommand(tab_id, new_index));
+ ScheduleCommand(CreateSetTabIndexInWindowCommand(tab_id, new_index).Pass());
}
void SessionService::SetPinnedState(const SessionID& window_id,
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreatePinnedStateCommand(tab_id, is_pinned));
+ ScheduleCommand(CreatePinnedStateCommand(tab_id, is_pinned).Pass());
}
void SessionService::TabClosed(const SessionID& window_id,
// . closing a tab and there are other windows/tabs open.
// . closed by a user gesture.
// In all cases we need to mark the tab as explicitly closed.
- ScheduleCommand(CreateTabClosedCommand(tab_id.id()));
+ ScheduleCommand(CreateTabClosedCommand(tab_id.id()).Pass());
} else {
// User closed the last tab in the last tabbed browser. Don't mark the
// tab closed.
}
}
+void SessionService::WindowOpened(Browser* browser) {
+ if (!ShouldTrackBrowser(browser))
+ return;
+
+ RestoreIfNecessary(std::vector<GURL>(), browser);
+ SetWindowType(browser->session_id(),
+ browser->type(),
+ browser->is_app() ? TYPE_APP : TYPE_NORMAL);
+ SetWindowAppName(browser->session_id(), browser->app_name());
+}
+
void SessionService::WindowClosing(const SessionID& window_id) {
if (!ShouldTrackChangesToWindow(window_id))
return;
// false to true, so only update it if already true.
has_open_trackable_browsers_ = HasOpenTrackableBrowsers(window_id);
}
- if (should_record_close_as_pending())
+ bool use_pending_close = !has_open_trackable_browsers_;
+ if (!use_pending_close) {
+ // Somewhat outside of "normal behavior" is profile locking. In this case
+ // (when IsSiginRequired has already been set True), we're closing all
+ // browser windows in turn but want them all to be restored when the user
+ // unlocks. To accomplish this, we do a "pending close" on all windows
+ // instead of just the last one (which has no open_trackable_browsers).
+ // http://crbug.com/356818
+ //
+ // Some editions (like iOS) don't have a profile_manager and some tests
+ // don't supply one so be lenient.
+ if (g_browser_process) {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ if (profile_manager) {
+ ProfileInfoCache& profile_info =
+ profile_manager->GetProfileInfoCache();
+ size_t profile_index = profile_info.GetIndexOfProfileWithPath(
+ profile()->GetPath());
+ use_pending_close = profile_index != std::string::npos &&
+ profile_info.ProfileIsSigninRequiredAtIndex(profile_index);
+ }
+ }
+ }
+ if (use_pending_close)
pending_window_close_ids_.insert(window_id.id());
else
window_closing_ids_.insert(window_id.id());
}
void SessionService::WindowClosed(const SessionID& window_id) {
- if (!ShouldTrackChangesToWindow(window_id))
+ if (!ShouldTrackChangesToWindow(window_id)) {
+ // The last window may be one that is not tracked.
+ MaybeDeleteSessionOnlyData();
return;
+ }
windows_tracking_.erase(window_id.id());
if (window_closing_ids_.find(window_id.id()) != window_closing_ids_.end()) {
window_closing_ids_.erase(window_id.id());
- ScheduleCommand(CreateWindowClosedCommand(window_id.id()));
+ ScheduleCommand(CreateWindowClosedCommand(window_id.id()).Pass());
} else if (pending_window_close_ids_.find(window_id.id()) ==
pending_window_close_ids_.end()) {
// We'll hit this if user closed the last tab in a window.
has_open_trackable_browsers_ = HasOpenTrackableBrowsers(window_id);
- if (should_record_close_as_pending())
+ if (!has_open_trackable_browsers_)
pending_window_close_ids_.insert(window_id.id());
else
- ScheduleCommand(CreateWindowClosedCommand(window_id.id()));
+ ScheduleCommand(CreateWindowClosedCommand(window_id.id()).Pass());
}
- // Clear session data if the last window for a profile has been closed and
- // closing the last window would normally close Chrome, unless background mode
- // is active.
- if (!has_open_trackable_browsers_ &&
- !browser_defaults::kBrowserAliveWithNoWindows &&
- !g_browser_process->background_mode_manager()->IsBackgroundModeActive()) {
- DeleteSessionOnlyData(profile());
+ MaybeDeleteSessionOnlyData();
+}
+
+void SessionService::TabInserted(WebContents* contents) {
+ SessionTabHelper* session_tab_helper =
+ SessionTabHelper::FromWebContents(contents);
+ if (!ShouldTrackChangesToWindow(session_tab_helper->window_id()))
+ return;
+ SetTabWindow(session_tab_helper->window_id(),
+ session_tab_helper->session_id());
+ extensions::TabHelper* extensions_tab_helper =
+ extensions::TabHelper::FromWebContents(contents);
+ if (extensions_tab_helper &&
+ extensions_tab_helper->extension_app()) {
+ SetTabExtensionAppID(
+ session_tab_helper->window_id(),
+ session_tab_helper->session_id(),
+ extensions_tab_helper->extension_app()->id());
}
+
+ // Record the association between the SessionStorageNamespace and the
+ // tab.
+ //
+ // TODO(ajwong): This should be processing the whole map rather than
+ // just the default. This in particular will not work for tabs with only
+ // isolated apps which won't have a default partition.
+ content::SessionStorageNamespace* session_storage_namespace =
+ contents->GetController().GetDefaultSessionStorageNamespace();
+ ScheduleCommand(CreateSessionStorageAssociatedCommand(
+ session_tab_helper->session_id(),
+ session_storage_namespace->persistent_id()).Pass());
+ session_storage_namespace->SetShouldPersist(true);
+}
+
+void SessionService::TabClosing(WebContents* contents) {
+ // Allow the associated sessionStorage to get deleted; it won't be needed
+ // in the session restore.
+ content::SessionStorageNamespace* session_storage_namespace =
+ contents->GetController().GetDefaultSessionStorageNamespace();
+ session_storage_namespace->SetShouldPersist(false);
+ SessionTabHelper* session_tab_helper =
+ SessionTabHelper::FromWebContents(contents);
+ TabClosed(session_tab_helper->window_id(),
+ session_tab_helper->session_id(),
+ contents->GetClosedByUserGesture());
+ RecordSessionUpdateHistogramData(content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ &last_updated_tab_closed_time_);
}
void SessionService::SetWindowType(const SessionID& window_id,
Browser::Type type,
AppType app_type) {
- if (!should_track_changes_for_browser_type(type, app_type))
+ SessionWindow::WindowType window_type = WindowTypeForBrowserType(type);
+ if (!ShouldRestoreWindowOfType(window_type, app_type))
return;
windows_tracking_.insert(window_id.id());
has_open_trackable_browsers_ = true;
move_on_new_browser_ = true;
- ScheduleCommand(
- CreateSetWindowTypeCommand(window_id, WindowTypeForBrowserType(type)));
+ ScheduleCommand(CreateSetWindowTypeCommand(window_id, window_type).Pass());
}
void SessionService::SetWindowAppName(
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreateSetTabExtensionAppIDCommand(
- kCommandSetWindowAppName,
- window_id.id(),
- app_name));
+ ScheduleCommand(CreateSetWindowAppNameCommand(window_id, app_name).Pass());
}
void SessionService::TabNavigationPathPrunedFromBack(const SessionID& window_id,
if (!ShouldTrackChangesToWindow(window_id))
return;
- TabNavigationPathPrunedFromBackPayload payload = { 0 };
- payload.id = tab_id.id();
- payload.index = count;
- SessionCommand* command =
- new SessionCommand(kCommandTabNavigationPathPrunedFromBack,
- sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- ScheduleCommand(command);
+ ScheduleCommand(
+ CreateTabNavigationPathPrunedFromBackCommand(tab_id, count).Pass());
}
void SessionService::TabNavigationPathPrunedFromFront(
range.second = std::max(0, range.second - count);
}
- TabNavigationPathPrunedFromFrontPayload payload = { 0 };
- payload.id = tab_id.id();
- payload.index = count;
- SessionCommand* command =
- new SessionCommand(kCommandTabNavigationPathPrunedFromFront,
- sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- ScheduleCommand(command);
+ ScheduleCommand(
+ CreateTabNavigationPathPrunedFromFrontCommand(tab_id, count).Pass());
}
void SessionService::UpdateTabNavigation(
range.first = std::min(navigation.index(), range.first);
range.second = std::max(navigation.index(), range.second);
}
- ScheduleCommand(CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation,
- tab_id.id(), navigation));
+ ScheduleCommand(CreateUpdateTabNavigationCommand(tab_id, navigation).Pass());
}
void SessionService::TabRestored(WebContents* tab, bool pinned) {
if (!ShouldTrackChangesToWindow(session_tab_helper->window_id()))
return;
- BuildCommandsForTab(session_tab_helper->window_id(), tab, -1,
- pinned, &pending_commands(), NULL);
- StartSaveTimer();
+ BuildCommandsForTab(session_tab_helper->window_id(), tab, -1, pinned, NULL);
+ base_session_service_->StartSaveTimer();
}
void SessionService::SetSelectedNavigationIndex(const SessionID& window_id,
return;
}
}
- ScheduleCommand(CreateSetSelectedNavigationIndexCommand(tab_id, index));
+ ScheduleCommand(
+ CreateSetSelectedNavigationIndexCommand(tab_id, index).Pass());
}
void SessionService::SetSelectedTabInWindow(const SessionID& window_id,
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreateSetSelectedTabInWindow(window_id, index));
+ ScheduleCommand(CreateSetSelectedTabInWindowCommand(window_id, index).Pass());
}
void SessionService::SetTabUserAgentOverride(
if (!ShouldTrackChangesToWindow(window_id))
return;
- ScheduleCommand(CreateSetTabUserAgentOverrideCommand(
- kCommandSetTabUserAgentOverride, tab_id.id(), user_agent_override));
+ ScheduleCommand(
+ CreateSetTabUserAgentOverrideCommand(tab_id, user_agent_override).Pass());
+}
+
+void SessionService::SetTabExtensionAppID(
+ const SessionID& window_id,
+ const SessionID& tab_id,
+ const std::string& extension_app_id) {
+ if (!ShouldTrackChangesToWindow(window_id))
+ return;
+
+ ScheduleCommand(
+ CreateSetTabExtensionAppIDCommand(tab_id, extension_app_id).Pass());
}
-CancelableTaskTracker::TaskId SessionService::GetLastSession(
+base::CancelableTaskTracker::TaskId SessionService::GetLastSession(
const SessionCallback& callback,
- CancelableTaskTracker* tracker) {
+ base::CancelableTaskTracker* tracker) {
// OnGotSessionCommands maps the SessionCommands to browser state, then run
// the callback.
- return ScheduleGetLastSessionCommands(
+ return base_session_service_->ScheduleGetLastSessionCommands(
base::Bind(&SessionService::OnGotSessionCommands,
- base::Unretained(this), callback),
+ weak_factory_.GetWeakPtr(),
+ callback),
tracker);
}
-void SessionService::Save() {
- bool had_commands = !pending_commands().empty();
- BaseSessionService::Save();
- if (had_commands) {
- RecordSessionUpdateHistogramData(chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
- &last_updated_save_time_);
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
- content::Source<Profile>(profile()),
- content::NotificationService::NoDetails());
- }
+void SessionService::OnSavedCommands() {
+ RecordSessionUpdateHistogramData(chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
+ &last_updated_save_time_);
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
+ content::Source<Profile>(profile()),
+ content::NotificationService::NoDetails());
}
void SessionService::Init() {
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
content::NotificationService::AllSources());
- // Wait for NOTIFICATION_BROWSER_WINDOW_READY so that is_app() is set.
- registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
- content::NotificationService::AllBrowserContextsAndSources());
registrar_.Add(
this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
content::NotificationService::AllSources());
BrowserList::AddObserver(this);
}
-bool SessionService::processed_any_commands() {
- return backend()->inited() || !pending_commands().empty();
-}
-
-bool SessionService::ShouldNewWindowStartSession() {
- // ChromeOS and OSX have different ideas of application lifetime than
- // the other platforms.
- // On ChromeOS opening a new window should never start a new session.
+bool SessionService::ShouldRestoreWindowOfType(
+ SessionWindow::WindowType window_type,
+ AppType app_type) const {
#if defined(OS_CHROMEOS)
- if (!force_browser_not_alive_with_no_windows_)
- return false;
-#endif
- if (!has_open_trackable_browsers_ &&
- !StartupBrowserCreator::InSynchronousProfileLaunch() &&
- !SessionRestore::IsRestoring(profile())
-#if defined(OS_MACOSX)
- // On OSX, a new window should not start a new session if it was opened
- // from the dock or the menubar.
- && !app_controller_mac::IsOpeningNewWindow()
-#endif // OS_MACOSX
- ) {
+ // Restore app popups for ChromeOS alone.
+ if (window_type == SessionWindow::TYPE_POPUP && app_type == TYPE_APP)
return true;
+#endif
+
+ return window_type == SessionWindow::TYPE_TABBED;
+}
+
+void SessionService::RemoveUnusedRestoreWindows(
+ std::vector<SessionWindow*>* window_list) {
+ std::vector<SessionWindow*>::iterator i = window_list->begin();
+ while (i != window_list->end()) {
+ SessionWindow* window = *i;
+ if (!ShouldRestoreWindowOfType(window->type,
+ window->app_name.empty() ? TYPE_NORMAL :
+ TYPE_APP)) {
+ delete window;
+ window_list->erase(i++);
+ } else {
+ ++i;
+ }
}
- return false;
}
bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open,
const content::NotificationDetails& details) {
// All of our messages have the NavigationController as the source.
switch (type) {
- case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
- Browser* browser = content::Source<Browser>(source).ptr();
- if (!ShouldTrackBrowser(browser))
- return;
-
- AppType app_type = browser->is_app() ? TYPE_APP : TYPE_NORMAL;
- RestoreIfNecessary(std::vector<GURL>(), browser);
- SetWindowType(browser->session_id(), browser->type(), app_type);
- SetWindowAppName(browser->session_id(), browser->app_name());
- break;
- }
-
case content::NOTIFICATION_NAV_LIST_PRUNED: {
WebContents* web_contents =
content::Source<content::NavigationController>(source).ptr()->
return;
content::Details<content::EntryChangedDetails> changed(details);
const SerializedNavigationEntry navigation =
- SerializedNavigationEntry::FromNavigationEntry(
+ ContentSerializedNavigationBuilder::FromNavigationEntry(
changed->index, *changed->changed_entry);
UpdateTabNavigation(session_tab_helper->window_id(),
session_tab_helper->session_id(),
session_tab_helper->session_id(),
current_entry_index);
const SerializedNavigationEntry navigation =
- SerializedNavigationEntry::FromNavigationEntry(
+ ContentSerializedNavigationBuilder::FromNavigationEntry(
current_entry_index,
*web_contents->GetController().GetEntryAtIndex(
current_entry_index));
void SessionService::OnBrowserSetLastActive(Browser* browser) {
if (ShouldTrackBrowser(browser))
- ScheduleCommand(CreateSetActiveWindowCommand(browser->session_id()));
-}
-
-void SessionService::SetTabExtensionAppID(
- const SessionID& window_id,
- const SessionID& tab_id,
- const std::string& extension_app_id) {
- if (!ShouldTrackChangesToWindow(window_id))
- return;
-
- ScheduleCommand(CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID,
- tab_id.id(), extension_app_id));
-}
-
-SessionCommand* SessionService::CreateSetSelectedTabInWindow(
- const SessionID& window_id,
- int index) {
- SelectedTabInIndexPayload payload = { 0 };
- payload.id = window_id.id();
- payload.index = index;
- SessionCommand* command = new SessionCommand(kCommandSetSelectedTabInIndex,
- sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateSetTabWindowCommand(
- const SessionID& window_id,
- const SessionID& tab_id) {
- SessionID::id_type payload[] = { window_id.id(), tab_id.id() };
- SessionCommand* command =
- new SessionCommand(kCommandSetTabWindow, sizeof(payload));
- memcpy(command->contents(), payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateSetWindowBoundsCommand(
- const SessionID& window_id,
- const gfx::Rect& bounds,
- ui::WindowShowState show_state) {
- WindowBoundsPayload3 payload = { 0 };
- payload.window_id = window_id.id();
- payload.x = bounds.x();
- payload.y = bounds.y();
- payload.w = bounds.width();
- payload.h = bounds.height();
- payload.show_state = AdjustShowState(show_state);
- SessionCommand* command = new SessionCommand(kCommandSetWindowBounds3,
- sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateSetTabIndexInWindowCommand(
- const SessionID& tab_id,
- int new_index) {
- TabIndexInWindowPayload payload = { 0 };
- payload.id = tab_id.id();
- payload.index = new_index;
- SessionCommand* command =
- new SessionCommand(kCommandSetTabIndexInWindow, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateTabClosedCommand(
- const SessionID::id_type tab_id) {
- ClosedPayload payload;
- // Because of what appears to be a compiler bug setting payload to {0} doesn't
- // set the padding to 0, resulting in Purify reporting an UMR when we write
- // the structure to disk. To avoid this we explicitly memset the struct.
- memset(&payload, 0, sizeof(payload));
- payload.id = tab_id;
- payload.close_time = Time::Now().ToInternalValue();
- SessionCommand* command =
- new SessionCommand(kCommandTabClosed, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateWindowClosedCommand(
- const SessionID::id_type window_id) {
- ClosedPayload payload;
- // See comment in CreateTabClosedCommand as to why we do this.
- memset(&payload, 0, sizeof(payload));
- payload.id = window_id;
- payload.close_time = Time::Now().ToInternalValue();
- SessionCommand* command =
- new SessionCommand(kCommandWindowClosed, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateSetSelectedNavigationIndexCommand(
- const SessionID& tab_id,
- int index) {
- SelectedNavigationIndexPayload payload = { 0 };
- payload.id = tab_id.id();
- payload.index = index;
- SessionCommand* command = new SessionCommand(
- kCommandSetSelectedNavigationIndex, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateSetWindowTypeCommand(
- const SessionID& window_id,
- WindowType type) {
- WindowTypePayload payload = { 0 };
- payload.id = window_id.id();
- payload.index = static_cast<int32>(type);
- SessionCommand* command = new SessionCommand(
- kCommandSetWindowType, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreatePinnedStateCommand(
- const SessionID& tab_id,
- bool is_pinned) {
- PinnedStatePayload payload = { 0 };
- payload.tab_id = tab_id.id();
- payload.pinned_state = is_pinned;
- SessionCommand* command =
- new SessionCommand(kCommandSetPinnedState, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
-}
-
-SessionCommand* SessionService::CreateSessionStorageAssociatedCommand(
- const SessionID& tab_id,
- const std::string& session_storage_persistent_id) {
- Pickle pickle;
- pickle.WriteInt(tab_id.id());
- pickle.WriteString(session_storage_persistent_id);
- return new SessionCommand(kCommandSessionStorageAssociated, pickle);
-}
-
-SessionCommand* SessionService::CreateSetActiveWindowCommand(
- const SessionID& window_id) {
- ActiveWindowPayload payload = 0;
- payload = window_id.id();
- SessionCommand* command =
- new SessionCommand(kCommandSetActiveWindow, sizeof(payload));
- memcpy(command->contents(), &payload, sizeof(payload));
- return command;
+ ScheduleCommand(CreateSetActiveWindowCommand(browser->session_id()).Pass());
}
void SessionService::OnGotSessionCommands(
ScopedVector<SessionWindow> valid_windows;
SessionID::id_type active_window_id = 0;
- RestoreSessionFromCommands(
- commands.get(), &valid_windows.get(), &active_window_id);
- callback.Run(valid_windows.Pass(), active_window_id);
-}
-
-void SessionService::RestoreSessionFromCommands(
- const std::vector<SessionCommand*>& commands,
- std::vector<SessionWindow*>* valid_windows,
- SessionID::id_type* active_window_id) {
- std::map<int, SessionTab*> tabs;
- std::map<int, SessionWindow*> windows;
-
- VLOG(1) << "RestoreSessionFromCommands " << commands.size();
- if (CreateTabsAndWindows(commands, &tabs, &windows, active_window_id)) {
- AddTabsToWindows(&tabs, &windows);
- SortTabsBasedOnVisualOrderAndPrune(&windows, valid_windows);
- UpdateSelectedTabIndex(valid_windows);
- }
- STLDeleteValues(&tabs);
- // Don't delete conents of windows, that is done by the caller as all
- // valid windows are added to valid_windows.
-}
-
-void SessionService::UpdateSelectedTabIndex(
- std::vector<SessionWindow*>* windows) {
- for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
- i != windows->end(); ++i) {
- // See note in SessionWindow as to why we do this.
- int new_index = 0;
- for (std::vector<SessionTab*>::const_iterator j = (*i)->tabs.begin();
- j != (*i)->tabs.end(); ++j) {
- if ((*j)->tab_visual_index == (*i)->selected_tab_index) {
- new_index = static_cast<int>(j - (*i)->tabs.begin());
- break;
- }
- }
- (*i)->selected_tab_index = new_index;
- }
-}
-
-SessionWindow* SessionService::GetWindow(
- SessionID::id_type window_id,
- IdToSessionWindow* windows) {
- std::map<int, SessionWindow*>::iterator i = windows->find(window_id);
- if (i == windows->end()) {
- SessionWindow* window = new SessionWindow();
- window->window_id.set_id(window_id);
- (*windows)[window_id] = window;
- return window;
- }
- return i->second;
-}
-
-SessionTab* SessionService::GetTab(
- SessionID::id_type tab_id,
- IdToSessionTab* tabs) {
- DCHECK(tabs);
- std::map<int, SessionTab*>::iterator i = tabs->find(tab_id);
- if (i == tabs->end()) {
- SessionTab* tab = new SessionTab();
- tab->tab_id.set_id(tab_id);
- (*tabs)[tab_id] = tab;
- return tab;
- }
- return i->second;
-}
-
-std::vector<SerializedNavigationEntry>::iterator
- SessionService::FindClosestNavigationWithIndex(
- std::vector<SerializedNavigationEntry>* navigations,
- int index) {
- DCHECK(navigations);
- for (std::vector<SerializedNavigationEntry>::iterator
- i = navigations->begin(); i != navigations->end(); ++i) {
- if (i->index() >= index)
- return i;
- }
- return navigations->end();
-}
-
-// Function used in sorting windows. Sorting is done based on window id. As
-// window ids increment for each new window, this effectively sorts by creation
-// time.
-static bool WindowOrderSortFunction(const SessionWindow* w1,
- const SessionWindow* w2) {
- return w1->window_id.id() < w2->window_id.id();
-}
-
-// Compares the two tabs based on visual index.
-static bool TabVisualIndexSortFunction(const SessionTab* t1,
- const SessionTab* t2) {
- const int delta = t1->tab_visual_index - t2->tab_visual_index;
- return delta == 0 ? (t1->tab_id.id() < t2->tab_id.id()) : (delta < 0);
-}
-
-void SessionService::SortTabsBasedOnVisualOrderAndPrune(
- std::map<int, SessionWindow*>* windows,
- std::vector<SessionWindow*>* valid_windows) {
- std::map<int, SessionWindow*>::iterator i = windows->begin();
- while (i != windows->end()) {
- SessionWindow* window = i->second;
- AppType app_type = window->app_name.empty() ? TYPE_NORMAL : TYPE_APP;
- if (window->tabs.empty() || window->is_constrained ||
- !should_track_changes_for_browser_type(
- static_cast<Browser::Type>(window->type),
- app_type)) {
- delete window;
- windows->erase(i++);
- } else {
- // Valid window; sort the tabs and add it to the list of valid windows.
- std::sort(window->tabs.begin(), window->tabs.end(),
- &TabVisualIndexSortFunction);
- // Otherwise, add the window such that older windows appear first.
- if (valid_windows->empty()) {
- valid_windows->push_back(window);
- } else {
- valid_windows->insert(
- std::upper_bound(valid_windows->begin(), valid_windows->end(),
- window, &WindowOrderSortFunction),
- window);
- }
- ++i;
- }
- }
-}
-
-void SessionService::AddTabsToWindows(std::map<int, SessionTab*>* tabs,
- std::map<int, SessionWindow*>* windows) {
- VLOG(1) << "AddTabsToWindws";
- VLOG(1) << "Tabs " << tabs->size() << ", windows " << windows->size();
- std::map<int, SessionTab*>::iterator i = tabs->begin();
- while (i != tabs->end()) {
- SessionTab* tab = i->second;
- if (tab->window_id.id() && !tab->navigations.empty()) {
- SessionWindow* window = GetWindow(tab->window_id.id(), windows);
- window->tabs.push_back(tab);
- tabs->erase(i++);
-
- // See note in SessionTab as to why we do this.
- std::vector<SerializedNavigationEntry>::iterator j =
- FindClosestNavigationWithIndex(&(tab->navigations),
- tab->current_navigation_index);
- if (j == tab->navigations.end()) {
- tab->current_navigation_index =
- static_cast<int>(tab->navigations.size() - 1);
- } else {
- tab->current_navigation_index =
- static_cast<int>(j - tab->navigations.begin());
- }
- } else {
- // Never got a set tab index in window, or tabs are empty, nothing
- // to do.
- ++i;
- }
- }
-}
-
-bool SessionService::CreateTabsAndWindows(
- const std::vector<SessionCommand*>& data,
- std::map<int, SessionTab*>* tabs,
- std::map<int, SessionWindow*>* windows,
- SessionID::id_type* active_window_id) {
- // If the file is corrupt (command with wrong size, or unknown command), we
- // still return true and attempt to restore what we we can.
- VLOG(1) << "CreateTabsAndWindows";
-
startup_metric_utils::ScopedSlowStartupUMA
scoped_timer("Startup.SlowStartupSessionServiceCreateTabsAndWindows");
- for (std::vector<SessionCommand*>::const_iterator i = data.begin();
- i != data.end(); ++i) {
- const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
- const SessionCommand* command = *i;
-
- VLOG(1) << "Read command " << (int) command->id();
- switch (command->id()) {
- case kCommandSetTabWindow: {
- SessionID::id_type payload[2];
- if (!command->GetPayload(payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetTab(payload[1], tabs)->window_id.set_id(payload[0]);
- break;
- }
-
- // This is here for forward migration only. New data is saved with
- // |kCommandSetWindowBounds3|.
- case kCommandSetWindowBounds2: {
- WindowBoundsPayload2 payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x,
- payload.y,
- payload.w,
- payload.h);
- GetWindow(payload.window_id, windows)->show_state =
- payload.is_maximized ?
- ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL;
- break;
- }
-
- case kCommandSetWindowBounds3: {
- WindowBoundsPayload3 payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x,
- payload.y,
- payload.w,
- payload.h);
- // SHOW_STATE_INACTIVE is not persisted.
- ui::WindowShowState show_state = ui::SHOW_STATE_NORMAL;
- if (payload.show_state > ui::SHOW_STATE_DEFAULT &&
- payload.show_state < ui::SHOW_STATE_END &&
- payload.show_state != ui::SHOW_STATE_INACTIVE) {
- show_state = static_cast<ui::WindowShowState>(payload.show_state);
- } else {
- NOTREACHED();
- }
- GetWindow(payload.window_id, windows)->show_state = show_state;
- break;
- }
-
- case kCommandSetTabIndexInWindow: {
- TabIndexInWindowPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetTab(payload.id, tabs)->tab_visual_index = payload.index;
- break;
- }
-
- case kCommandTabClosedObsolete:
- case kCommandWindowClosedObsolete:
- case kCommandTabClosed:
- case kCommandWindowClosed: {
- ClosedPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload)) &&
- !MigrateClosedPayload(*command, &payload)) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- if (command->id() == kCommandTabClosed ||
- command->id() == kCommandTabClosedObsolete) {
- delete GetTab(payload.id, tabs);
- tabs->erase(payload.id);
- } else {
- delete GetWindow(payload.id, windows);
- windows->erase(payload.id);
- }
- break;
- }
-
- case kCommandTabNavigationPathPrunedFromBack: {
- TabNavigationPathPrunedFromBackPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- SessionTab* tab = GetTab(payload.id, tabs);
- tab->navigations.erase(
- FindClosestNavigationWithIndex(&(tab->navigations), payload.index),
- tab->navigations.end());
- break;
- }
-
- case kCommandTabNavigationPathPrunedFromFront: {
- TabNavigationPathPrunedFromFrontPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload)) ||
- payload.index <= 0) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- SessionTab* tab = GetTab(payload.id, tabs);
-
- // Update the selected navigation index.
- tab->current_navigation_index =
- std::max(-1, tab->current_navigation_index - payload.index);
-
- // And update the index of existing navigations.
- for (std::vector<SerializedNavigationEntry>::iterator
- i = tab->navigations.begin();
- i != tab->navigations.end();) {
- i->set_index(i->index() - payload.index);
- if (i->index() < 0)
- i = tab->navigations.erase(i);
- else
- ++i;
- }
- break;
- }
-
- case kCommandUpdateTabNavigation: {
- SerializedNavigationEntry navigation;
- SessionID::id_type tab_id;
- if (!RestoreUpdateTabNavigationCommand(
- *command, &navigation, &tab_id)) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- SessionTab* tab = GetTab(tab_id, tabs);
- std::vector<SerializedNavigationEntry>::iterator i =
- FindClosestNavigationWithIndex(&(tab->navigations),
- navigation.index());
- if (i != tab->navigations.end() && i->index() == navigation.index())
- *i = navigation;
- else
- tab->navigations.insert(i, navigation);
- break;
- }
-
- case kCommandSetSelectedNavigationIndex: {
- SelectedNavigationIndexPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetTab(payload.id, tabs)->current_navigation_index = payload.index;
- break;
- }
-
- case kCommandSetSelectedTabInIndex: {
- SelectedTabInIndexPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetWindow(payload.id, windows)->selected_tab_index = payload.index;
- break;
- }
-
- case kCommandSetWindowType: {
- WindowTypePayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetWindow(payload.id, windows)->is_constrained = false;
- GetWindow(payload.id, windows)->type =
- BrowserTypeForWindowType(
- static_cast<WindowType>(payload.index));
- break;
- }
+ RestoreSessionFromCommands(commands, &valid_windows.get(), &active_window_id);
+ RemoveUnusedRestoreWindows(&valid_windows.get());
- case kCommandSetPinnedState: {
- PinnedStatePayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state;
- break;
- }
-
- case kCommandSetWindowAppName: {
- SessionID::id_type window_id;
- std::string app_name;
- if (!RestoreSetWindowAppNameCommand(*command, &window_id, &app_name))
- return true;
-
- GetWindow(window_id, windows)->app_name.swap(app_name);
- break;
- }
-
- case kCommandSetExtensionAppID: {
- SessionID::id_type tab_id;
- std::string extension_app_id;
- if (!RestoreSetTabExtensionAppIDCommand(
- *command, &tab_id, &extension_app_id)) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
-
- GetTab(tab_id, tabs)->extension_app_id.swap(extension_app_id);
- break;
- }
-
- case kCommandSetTabUserAgentOverride: {
- SessionID::id_type tab_id;
- std::string user_agent_override;
- if (!RestoreSetTabUserAgentOverrideCommand(
- *command, &tab_id, &user_agent_override)) {
- return true;
- }
-
- GetTab(tab_id, tabs)->user_agent_override.swap(user_agent_override);
- break;
- }
-
- case kCommandSessionStorageAssociated: {
- scoped_ptr<Pickle> command_pickle(command->PayloadAsPickle());
- SessionID::id_type command_tab_id;
- std::string session_storage_persistent_id;
- PickleIterator iter(*command_pickle.get());
- if (!command_pickle->ReadInt(&iter, &command_tab_id) ||
- !command_pickle->ReadString(&iter, &session_storage_persistent_id))
- return true;
- // Associate the session storage back.
- GetTab(command_tab_id, tabs)->session_storage_persistent_id =
- session_storage_persistent_id;
- break;
- }
-
- case kCommandSetActiveWindow: {
- ActiveWindowPayload payload;
- if (!command->GetPayload(&payload, sizeof(payload))) {
- VLOG(1) << "Failed reading command " << command->id();
- return true;
- }
- *active_window_id = payload;
- break;
- }
-
- default:
- VLOG(1) << "Failed reading an unknown command " << command->id();
- return true;
- }
- }
- return true;
+ callback.Run(valid_windows.Pass(), active_window_id);
}
void SessionService::BuildCommandsForTab(const SessionID& window_id,
WebContents* tab,
int index_in_window,
bool is_pinned,
- std::vector<SessionCommand*>* commands,
IdToRange* tab_to_available_range) {
- DCHECK(tab && commands && window_id.id());
+ DCHECK(tab && window_id.id());
SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(tab);
const SessionID& session_id(session_tab_helper->session_id());
- commands->push_back(CreateSetTabWindowCommand(window_id, session_id));
+ base_session_service_->AppendRebuildCommand(
+ CreateSetTabWindowCommand(window_id, session_id));
const int current_index = tab->GetController().GetCurrentEntryIndex();
- const int min_index = std::max(0,
- current_index - max_persist_navigation_count);
- const int max_index =
- std::min(current_index + max_persist_navigation_count,
- tab->GetController().GetEntryCount());
+ const int min_index = std::max(current_index - gMaxPersistNavigationCount, 0);
+ const int max_index = std::min(current_index + gMaxPersistNavigationCount,
+ tab->GetController().GetEntryCount());
const int pending_index = tab->GetController().GetPendingEntryIndex();
if (tab_to_available_range) {
(*tab_to_available_range)[session_id.id()] =
}
if (is_pinned) {
- commands->push_back(CreatePinnedStateCommand(session_id, true));
+ base_session_service_->AppendRebuildCommand(
+ CreatePinnedStateCommand(session_id, true));
}
extensions::TabHelper* extensions_tab_helper =
extensions::TabHelper::FromWebContents(tab);
if (extensions_tab_helper->extension_app()) {
- commands->push_back(
+ base_session_service_->AppendRebuildCommand(
CreateSetTabExtensionAppIDCommand(
- kCommandSetExtensionAppID, session_id.id(),
+ session_id,
extensions_tab_helper->extension_app()->id()));
}
const std::string& ua_override = tab->GetUserAgentOverride();
if (!ua_override.empty()) {
- commands->push_back(
- CreateSetTabUserAgentOverrideCommand(
- kCommandSetTabUserAgentOverride, session_id.id(), ua_override));
+ base_session_service_->AppendRebuildCommand(
+ CreateSetTabUserAgentOverrideCommand(session_id, ua_override));
}
for (int i = min_index; i < max_index; ++i) {
DCHECK(entry);
if (ShouldTrackEntry(entry->GetVirtualURL())) {
const SerializedNavigationEntry navigation =
- SerializedNavigationEntry::FromNavigationEntry(i, *entry);
- commands->push_back(
- CreateUpdateTabNavigationCommand(
- kCommandUpdateTabNavigation, session_id.id(), navigation));
+ ContentSerializedNavigationBuilder::FromNavigationEntry(i, *entry);
+ base_session_service_->AppendRebuildCommand(
+ CreateUpdateTabNavigationCommand(session_id, navigation));
}
}
- commands->push_back(
- CreateSetSelectedNavigationIndexCommand(session_id, current_index));
+ base_session_service_->AppendRebuildCommand(
+ CreateSetSelectedNavigationIndexCommand(session_id,
+ current_index));
if (index_in_window != -1) {
- commands->push_back(
- CreateSetTabIndexInWindowCommand(session_id, index_in_window));
+ base_session_service_->AppendRebuildCommand(
+ CreateSetTabIndexInWindowCommand(session_id,
+ index_in_window));
}
// Record the association between the sessionStorage namespace and the tab.
tab->GetController().GetDefaultSessionStorageNamespace();
ScheduleCommand(CreateSessionStorageAssociatedCommand(
session_tab_helper->session_id(),
- session_storage_namespace->persistent_id()));
+ session_storage_namespace->persistent_id()).Pass());
}
void SessionService::BuildCommandsForBrowser(
Browser* browser,
- std::vector<SessionCommand*>* commands,
IdToRange* tab_to_available_range,
std::set<SessionID::id_type>* windows_to_track) {
- DCHECK(browser && commands);
+ DCHECK(browser);
DCHECK(browser->session_id().id());
- commands->push_back(
- CreateSetWindowBoundsCommand(browser->session_id(),
- browser->window()->GetRestoredBounds(),
- browser->window()->GetRestoredState()));
+ base_session_service_->AppendRebuildCommand(CreateSetWindowBoundsCommand(
+ browser->session_id(),
+ browser->window()->GetRestoredBounds(),
+ browser->window()->GetRestoredState()));
- commands->push_back(CreateSetWindowTypeCommand(
- browser->session_id(), WindowTypeForBrowserType(browser->type())));
+ base_session_service_->AppendRebuildCommand(CreateSetWindowTypeCommand(
+ browser->session_id(),
+ WindowTypeForBrowserType(browser->type())));
if (!browser->app_name().empty()) {
- commands->push_back(CreateSetWindowAppNameCommand(
- kCommandSetWindowAppName,
- browser->session_id().id(),
+ base_session_service_->AppendRebuildCommand(CreateSetWindowAppNameCommand(
+ browser->session_id(),
browser->app_name()));
}
for (int i = 0; i < tab_strip->count(); ++i) {
WebContents* tab = tab_strip->GetWebContentsAt(i);
DCHECK(tab);
- BuildCommandsForTab(browser->session_id(), tab, i,
+ BuildCommandsForTab(browser->session_id(),
+ tab,
+ i,
tab_strip->IsTabPinned(i),
- commands, tab_to_available_range);
+ tab_to_available_range);
}
- commands->push_back(
- CreateSetSelectedTabInWindow(browser->session_id(),
- browser->tab_strip_model()->active_index()));
+ base_session_service_->AppendRebuildCommand(
+ CreateSetSelectedTabInWindowCommand(
+ browser->session_id(),
+ browser->tab_strip_model()->active_index()));
}
void SessionService::BuildCommandsFromBrowsers(
- std::vector<SessionCommand*>* commands,
IdToRange* tab_to_available_range,
std::set<SessionID::id_type>* windows_to_track) {
- DCHECK(commands);
for (chrome::BrowserIterator it; !it.done(); it.Next()) {
Browser* browser = *it;
// Make sure the browser has tabs and a window. Browser's destructor
// deleted, so we ignore it.
if (ShouldTrackBrowser(browser) && browser->tab_strip_model()->count() &&
browser->window()) {
- BuildCommandsForBrowser(browser, commands, tab_to_available_range,
+ BuildCommandsForBrowser(browser,
+ tab_to_available_range,
windows_to_track);
}
}
}
-void SessionService::ScheduleReset() {
- set_pending_reset(true);
- STLDeleteElements(&pending_commands());
+void SessionService::ScheduleResetCommands() {
+ base_session_service_->set_pending_reset(true);
+ base_session_service_->ClearPendingCommands();
tab_to_available_range_.clear();
windows_tracking_.clear();
- BuildCommandsFromBrowsers(&pending_commands(), &tab_to_available_range_,
+ BuildCommandsFromBrowsers(&tab_to_available_range_,
&windows_tracking_);
if (!windows_tracking_.empty()) {
// We're lazily created on startup and won't get an initial batch of
has_open_trackable_browsers_ = true;
move_on_new_browser_ = true;
}
- StartSaveTimer();
-}
-
-bool SessionService::ReplacePendingCommand(SessionCommand* command) {
- // We optimize page navigations, which can happen quite frequently and
- // are expensive. And activation is like Highlander, there can only be one!
- if (command->id() != kCommandUpdateTabNavigation &&
- command->id() != kCommandSetActiveWindow) {
- return false;
- }
- for (std::vector<SessionCommand*>::reverse_iterator i =
- pending_commands().rbegin(); i != pending_commands().rend(); ++i) {
- SessionCommand* existing_command = *i;
- if (command->id() == kCommandUpdateTabNavigation &&
- existing_command->id() == kCommandUpdateTabNavigation) {
- scoped_ptr<Pickle> command_pickle(command->PayloadAsPickle());
- PickleIterator iterator(*command_pickle);
- SessionID::id_type command_tab_id;
- int command_nav_index;
- if (!command_pickle->ReadInt(&iterator, &command_tab_id) ||
- !command_pickle->ReadInt(&iterator, &command_nav_index)) {
- return false;
- }
- SessionID::id_type existing_tab_id;
- int existing_nav_index;
- {
- // Creating a pickle like this means the Pickle references the data from
- // the command. Make sure we delete the pickle before the command, else
- // the pickle references deleted memory.
- scoped_ptr<Pickle> existing_pickle(existing_command->PayloadAsPickle());
- iterator = PickleIterator(*existing_pickle);
- if (!existing_pickle->ReadInt(&iterator, &existing_tab_id) ||
- !existing_pickle->ReadInt(&iterator, &existing_nav_index)) {
- return false;
- }
- }
- if (existing_tab_id == command_tab_id &&
- existing_nav_index == command_nav_index) {
- // existing_command is an update for the same tab/index pair. Replace
- // it with the new one. We need to add to the end of the list just in
- // case there is a prune command after the update command.
- delete existing_command;
- pending_commands().erase(i.base() - 1);
- pending_commands().push_back(command);
- return true;
- }
- return false;
- }
- if (command->id() == kCommandSetActiveWindow &&
- existing_command->id() == kCommandSetActiveWindow) {
- *i = command;
- delete existing_command;
- return true;
- }
- }
- return false;
+ base_session_service_->StartSaveTimer();
}
-void SessionService::ScheduleCommand(SessionCommand* command) {
+void SessionService::ScheduleCommand(scoped_ptr<SessionCommand> command) {
DCHECK(command);
- if (ReplacePendingCommand(command))
+ if (ReplacePendingCommand(base_session_service_.get(), &command))
return;
- BaseSessionService::ScheduleCommand(command);
+ bool is_closing_command = IsClosingCommand(command.get());
+ base_session_service_->ScheduleCommand(command.Pass());
// Don't schedule a reset on tab closed/window closed. Otherwise we may
// lose tabs/windows we want to restore from if we exit right after this.
- if (!pending_reset() && pending_window_close_ids_.empty() &&
- commands_since_reset() >= kWritesPerReset &&
- (command->id() != kCommandTabClosed &&
- command->id() != kCommandWindowClosed)) {
- ScheduleReset();
+ if (!base_session_service_->pending_reset() &&
+ pending_window_close_ids_.empty() &&
+ base_session_service_->commands_since_reset() >= kWritesPerReset &&
+ !is_closing_command) {
+ ScheduleResetCommands();
}
}
void SessionService::CommitPendingCloses() {
for (PendingTabCloseIDs::iterator i = pending_tab_close_ids_.begin();
i != pending_tab_close_ids_.end(); ++i) {
- ScheduleCommand(CreateTabClosedCommand(*i));
+ ScheduleCommand(CreateTabClosedCommand(*i).Pass());
}
pending_tab_close_ids_.clear();
for (PendingWindowCloseIDs::iterator i = pending_window_close_ids_.begin();
i != pending_window_close_ids_.end(); ++i) {
- ScheduleCommand(CreateWindowClosedCommand(*i));
+ ScheduleCommand(CreateWindowClosedCommand(*i).Pass());
}
pending_window_close_ids_.clear();
}
bool SessionService::IsOnlyOneTabLeft() const {
- if (!profile()) {
+ if (!profile() || profile()->AsTestingProfile()) {
// We're testing, always return false.
return false;
}
bool SessionService::HasOpenTrackableBrowsers(
const SessionID& window_id) const {
- if (!profile()) {
- // We're testing, always return false.
+ if (!profile() || profile()->AsTestingProfile()) {
+ // We're testing, always return true.
return true;
}
}
bool SessionService::ShouldTrackBrowser(Browser* browser) const {
- AppType app_type = browser->is_app() ? TYPE_APP : TYPE_NORMAL;
- return browser->profile() == profile() &&
- should_track_changes_for_browser_type(browser->type(), app_type);
-}
-
-bool SessionService::should_track_changes_for_browser_type(Browser::Type type,
- AppType app_type) {
-#if defined(OS_CHROMEOS)
- // Restore app popups for chromeos alone.
- if (type == Browser::TYPE_POPUP && app_type == TYPE_APP)
- return true;
-#endif
-
- return type == Browser::TYPE_TABBED ||
- (type == Browser::TYPE_POPUP && browser_defaults::kRestorePopups);
-}
-
-SessionService::WindowType SessionService::WindowTypeForBrowserType(
- Browser::Type type) {
- switch (type) {
- case Browser::TYPE_POPUP:
- return TYPE_POPUP;
- case Browser::TYPE_TABBED:
- return TYPE_TABBED;
- default:
- DCHECK(false);
- return TYPE_TABBED;
- }
-}
-
-Browser::Type SessionService::BrowserTypeForWindowType(WindowType type) {
- switch (type) {
- case TYPE_POPUP:
- return Browser::TYPE_POPUP;
- case TYPE_TABBED:
- default:
- return Browser::TYPE_TABBED;
+ if (browser->profile() != profile())
+ return false;
+ // Never track app popup windows that do not have a trusted source (i.e.
+ // popup windows spawned by an app). If this logic changes, be sure to also
+ // change SessionRestoreImpl::CreateRestoredBrowser().
+ if (browser->is_app() && browser->is_type_popup() &&
+ !browser->is_trusted_source()) {
+ return false;
}
+ return ShouldRestoreWindowOfType(WindowTypeForBrowserType(browser->type()),
+ browser->is_app() ? TYPE_APP : TYPE_NORMAL);
}
void SessionService::RecordSessionUpdateHistogramData(int type,
}
}
-void SessionService::RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta,
- bool use_long_period) {
- std::string name("SessionRestore.NavOrTabUpdatePeriod");
+void SessionService::RecordUpdatedSaveTime(base::TimeDelta delta,
+ bool use_long_period) {
+ std::string name("SessionRestore.SavePeriod");
UMA_HISTOGRAM_CUSTOM_TIMES(name,
delta,
// 2500ms is the default save delay.
save_delay_in_mins_,
50);
if (use_long_period) {
- std::string long_name_("SessionRestore.NavOrTabUpdateLongPeriod");
+ std::string long_name_("SessionRestore.SaveLongPeriod");
UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
delta,
save_delay_in_mins_,
}
}
-void SessionService::RecordUpdatedSaveTime(base::TimeDelta delta,
- bool use_long_period) {
- std::string name("SessionRestore.SavePeriod");
+void SessionService::RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta,
+ bool use_long_period) {
+ std::string name("SessionRestore.NavOrTabUpdatePeriod");
UMA_HISTOGRAM_CUSTOM_TIMES(name,
delta,
// 2500ms is the default save delay.
save_delay_in_mins_,
50);
if (use_long_period) {
- std::string long_name_("SessionRestore.SaveLongPeriod");
+ std::string long_name_("SessionRestore.NavOrTabUpdateLongPeriod");
UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
delta,
save_delay_in_mins_,
}
}
-void SessionService::TabInserted(WebContents* contents) {
- SessionTabHelper* session_tab_helper =
- SessionTabHelper::FromWebContents(contents);
- if (!ShouldTrackChangesToWindow(session_tab_helper->window_id()))
+void SessionService::MaybeDeleteSessionOnlyData() {
+ // Don't try anything if we're testing. The browser_process is not fully
+ // created and DeleteSession will crash if we actually attempt it.
+ if (!profile() || profile()->AsTestingProfile())
+ return;
+
+ // Clear session data if the last window for a profile has been closed and
+ // closing the last window would normally close Chrome, unless background mode
+ // is active. Tests don't have a background_mode_manager.
+ if (has_open_trackable_browsers_ ||
+ browser_defaults::kBrowserAliveWithNoWindows ||
+ g_browser_process->background_mode_manager()->IsBackgroundModeActive()) {
return;
- SetTabWindow(session_tab_helper->window_id(),
- session_tab_helper->session_id());
- extensions::TabHelper* extensions_tab_helper =
- extensions::TabHelper::FromWebContents(contents);
- if (extensions_tab_helper &&
- extensions_tab_helper->extension_app()) {
- SetTabExtensionAppID(
- session_tab_helper->window_id(),
- session_tab_helper->session_id(),
- extensions_tab_helper->extension_app()->id());
}
- // Record the association between the SessionStorageNamespace and the
- // tab.
- //
- // TODO(ajwong): This should be processing the whole map rather than
- // just the default. This in particular will not work for tabs with only
- // isolated apps which won't have a default partition.
- content::SessionStorageNamespace* session_storage_namespace =
- contents->GetController().GetDefaultSessionStorageNamespace();
- ScheduleCommand(CreateSessionStorageAssociatedCommand(
- session_tab_helper->session_id(),
- session_storage_namespace->persistent_id()));
- session_storage_namespace->SetShouldPersist(true);
+ // Check for any open windows for the current profile that we aren't tracking.
+ for (chrome::BrowserIterator it; !it.done(); it.Next()) {
+ if ((*it)->profile() == profile())
+ return;
+ }
+ DeleteSessionOnlyData(profile());
}
-void SessionService::TabClosing(WebContents* contents) {
- // Allow the associated sessionStorage to get deleted; it won't be needed
- // in the session restore.
- content::SessionStorageNamespace* session_storage_namespace =
- contents->GetController().GetDefaultSessionStorageNamespace();
- session_storage_namespace->SetShouldPersist(false);
- SessionTabHelper* session_tab_helper =
- SessionTabHelper::FromWebContents(contents);
- TabClosed(session_tab_helper->window_id(),
- session_tab_helper->session_id(),
- contents->GetClosedByUserGesture());
- RecordSessionUpdateHistogramData(content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- &last_updated_tab_closed_time_);
+BaseSessionService* SessionService::GetBaseSessionServiceForTest() {
+ return base_session_service_.get();
}