blob: c98ca85b77543b4b4f223998973257863207248f [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_BASE_H_
#define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_BASE_H_
#include <map>
#include <optional>
#include <string>
#include <utility>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/sessions/session_common_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/sessions/content/session_tab_helper_delegate.h"
#include "components/sessions/core/command_storage_manager_delegate.h"
#include "components/sessions/core/session_service_commands.h"
#include "components/sessions/core/tab_restore_service_client.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/mojom/window_show_state.mojom-forward.h"
#include "ui/base/ui_base_types.h"
class Profile;
namespace base {
class Value;
}
namespace content {
class WebContents;
} // namespace content
namespace sessions {
class CommandStorageManager;
class SessionCommand;
struct SessionWindow;
} // namespace sessions
// SessionServiceBase -----
// SessionServiceBase is used by SessionService and AppSessionService to
// restore browser windows and apps respectively. Base is never intended
// to be instantiated and contains the common functionality that both
// SessionService and AppSessionService share in common. Some functions
// are implemented by both if they have differing behavior while others
// exist in one but not the other.
class SessionServiceBase : public sessions::CommandStorageManagerDelegate,
public sessions::SessionTabHelperDelegate,
public KeyedService,
public BrowserListObserver {
public:
enum class SessionServiceType { kAppRestore, kSessionRestore };
SessionServiceBase(const SessionServiceBase&) = delete;
SessionServiceBase& operator=(const SessionServiceBase&) = delete;
~SessionServiceBase() override;
static Browser::Type GetBrowserTypeFromWebContents(
content::WebContents* web_contents);
Profile* profile() const { return profile_; }
bool is_saving_enabled() const { return is_saving_enabled_; }
// Sets whether the window is visible on all workspaces or not.
void SetWindowVisibleOnAllWorkspaces(SessionID window_id,
bool visible_on_all_workspaces);
// Resets the contents of the file from the current state of all open
// apps whose profile matches our profile.
void ResetFromCurrentBrowsers();
// Associates a tab with a window.
void SetTabWindow(SessionID window_id, SessionID tab_id);
// Sets the bounds of a window.
void SetWindowBounds(SessionID window_id,
const gfx::Rect& bounds,
ui::mojom::WindowShowState show_state);
// Sets the workspace the window resides in.
void SetWindowWorkspace(SessionID window_id, const std::string& workspace);
// Sets the visual index of the tab in its parent window.
void SetTabIndexInWindow(SessionID window_id,
SessionID tab_id,
int new_index);
// Note: this is invoked from the NavigationController's destructor, which is
// after the actual tab has been removed.
virtual void TabClosed(SessionID window_id, SessionID tab_id) = 0;
// Notification a window has opened.
virtual void WindowOpened(Browser* browser) = 0;
// Notification the window is about to close.
virtual void WindowClosing(SessionID window_id) = 0;
// Notification a window has finished closing.
virtual void WindowClosed(SessionID window_id) = 0;
// Called when a tab is inserted.
void TabInserted(content::WebContents* contents);
// Called when a tab is closing.
void TabClosing(content::WebContents* contents);
// Notification that a tab has restored its entries or a closed tab is being
// reused.
void TabRestored(content::WebContents* tab, bool pinned);
// Sets the type of window. In order for the contents of a window to be
// tracked SetWindowType must be invoked with a type we track
// (ShouldRestoreOfWindowType returns true).
virtual void SetWindowType(SessionID window_id, Browser::Type type) = 0;
// Sets the index of the selected tab in the specified window.
void SetSelectedTabInWindow(SessionID window_id, int index);
// Sets the application extension id of the specified tab.
void SetTabExtensionAppID(SessionID window_id,
SessionID tab_id,
const std::string& extension_app_id);
// Sets the last active time of the tab.
void SetLastActiveTime(SessionID window_id,
SessionID tab_id,
base::Time last_active_time);
// Fetches the contents of the last session, notifying the callback when
// done. If the callback is supplied an empty vector of SessionWindows
// it means the session could not be restored.
void GetLastSession(sessions::GetLastSessionCallback callback);
// Sets the application name of the specified window.
void SetWindowAppName(SessionID window_id, const std::string& app_name);
// Sets the pinned state of the tab.
void SetPinnedState(SessionID window_id, SessionID tab_id, bool is_pinned);
// CommandStorageManagerDelegate:
bool ShouldUseDelayedSave() override;
void OnWillSaveCommands() override;
// This implementation in SessionServiceBase is mostly a no-op.
// Full support for Session Service logging will come with
// https://crbug.com/1193711
void OnErrorWritingSessionCommands() override;
// sessions::SessionTabHelperDelegate:
void SetTabUserAgentOverride(SessionID window_id,
SessionID tab_id,
const sessions::SerializedUserAgentOverride&
user_agent_override) override;
void SetSelectedNavigationIndex(SessionID window_id,
SessionID tab_id,
int index) override;
void UpdateTabNavigation(
SessionID window_id,
SessionID tab_id,
const sessions::SerializedNavigationEntry& navigation) override;
void TabNavigationPathPruned(SessionID window_id,
SessionID tab_id,
int index,
int count) override;
void TabNavigationPathEntriesDeleted(SessionID window_id,
SessionID tab_id) override;
#if DCHECK_IS_ON()
// Returns the state of this class and logs for the
// chrome://internals/session-service debug page. The logs are in reverse
// order for truncation ease. This value is NOT STABLE -
// do not rely on it's contents for anything.
virtual base::Value ToDebugValue() const;
#endif // DCHECK_IS_ON()
// Some platforms support windowing system level session management, in such
// cases, GetPlatformSessionId() returns a non-empty string identifier
// provided by the platform at session initialization and persisted in the
// session command backing storage for future session restoration.
// See ui/ozone/public/platfrom_session_manager.h for more details.
std::optional<std::string> GetPlatformSessionId();
void SetPlatformSessionIdForTesting(const std::string& id);
protected:
// Creates a SessionService for the specified profile.
SessionServiceBase(Profile* profile, SessionServiceType type);
// This method is implemented by child classes to pass us the type.
virtual Browser::Type GetDesiredBrowserTypeForWebContents() = 0;
bool rebuild_on_next_save() const { return rebuild_on_next_save_; }
void set_rebuild_on_next_save(bool value) { rebuild_on_next_save_ = value; }
std::map<SessionID, int>* last_selected_tab_in_window() {
return &last_selected_tab_in_window_;
}
using IdToRange = std::map<SessionID, std::pair<int, int>>;
IdToRange* tab_to_available_range() { return &tab_to_available_range_; }
sessions::CommandStorageManager* command_storage_manager() {
return command_storage_manager_.get();
}
using WindowsTracking = std::set<SessionID>;
WindowsTracking* windows_tracking() { return &windows_tracking_; }
// This should only be used by derived classes in their destructors.
void DestroyCommandStorageManager();
// Returns true if a window of given |window_type| should get
// restored upon session restore.
virtual bool ShouldRestoreWindowOfType(
sessions::SessionWindow::WindowType type) const = 0;
// Removes unrestorable windows from the previous windows list.
void RemoveUnusedRestoreWindows(
std::vector<std::unique_ptr<sessions::SessionWindow>>* window_list);
// BrowserListObserver
void OnBrowserAdded(Browser* browser) override {}
void OnBrowserRemoved(Browser* browser) override {}
void OnBrowserSetLastActive(Browser* browser) override;
// Converts |commands| to SessionWindows and notifies the callback.
void OnGotSessionCommands(
sessions::GetLastSessionCallback callback,
std::vector<std::unique_ptr<sessions::SessionCommand>> commands,
bool read_error);
// Adds commands to commands that will recreate the state of the specified
// tab. This adds at most kMaxNavigationCountToPersist navigations (in each
// direction from the current navigation index).
// A pair is added to tab_to_available_range indicating the range of
// indices that were written.
virtual void BuildCommandsForTab(SessionID window_id,
content::WebContents* tab,
int index_in_window,
std::optional<tab_groups::TabGroupId> group,
std::optional<split_tabs::SplitTabId> split,
bool is_pinned,
IdToRange* tab_to_available_range);
// Adds commands to create the specified browser, and invokes
// BuildCommandsForTab for each of the tabs in the browser. This ignores
// any tabs not in the profile we were created with.
virtual void BuildCommandsForBrowser(Browser* browser,
IdToRange* tab_to_available_range,
std::set<SessionID>* windows_to_track);
// Iterates over all the known browsers invoking BuildCommandsForBrowser.
// This only adds browsers that should be tracked (|ShouldRestoreWindowOfType|
// returns true). All browsers that are tracked are added to windows_to_track
// (as long as it is non-null).
void BuildCommandsFromBrowsers(IdToRange* tab_to_available_range,
std::set<SessionID>* windows_to_track);
// Schedules a reset of the existing commands. A reset means the contents
// of the file are recreated from the state of the browser.
virtual void ScheduleResetCommands() = 0;
// Schedules the specified command.
void ScheduleCommand(std::unique_ptr<sessions::SessionCommand> command);
virtual void DidScheduleCommand() {}
// Returns true if changes to tabs in the specified window should be tracked.
bool ShouldTrackChangesToWindow(SessionID window_id) const;
// Returns true if we track changes to the specified browser.
bool ShouldTrackBrowser(Browser* browser) const;
// Will rebuild session commands if rebuild_on_next_save_ is true.
virtual void RebuildCommandsIfRequired() = 0;
// Unit test accessors.
sessions::CommandStorageManager* GetCommandStorageManagerForTest();
void SetAvailableRangeForTest(SessionID tab_id,
const std::pair<int, int>& range);
bool GetAvailableRangeForTest(SessionID tab_id, std::pair<int, int>* range);
// Sets whether commands are saved. If false, SessionCommands are effectively
// dropped (deleted). This is intended for use after a crash to ensure no
// commands are written before the user acknowledges/restores the crash.
void SetSavingEnabled(bool enabled);
private:
friend class SessionServiceBaseTestHelper;
friend class SessionServiceTestHelper;
// If supported by the platform, initializes windowing system level session
// and requests `discarded_window_ids` to be removed from the session. If it
// succeeds, `platform_session_id_` should contain the session id to be used
// by browser windows to associate them to a given platform session.
void InitializePlatformSessionIfNeeded(
const std::string& restored_platform_session_id,
const std::set<SessionID>& discarded_window_ids);
// This is always non-null.
raw_ptr<Profile> profile_;
// Whether to use delayed save. Set to false when constructed with a FilePath
// (which should only be used for testing).
bool should_use_delayed_save_ = true;
std::unique_ptr<sessions::CommandStorageManager> command_storage_manager_;
// Maps from session tab id to the range of navigation entries that has
// been written to disk.
//
// This is only used if not all the navigation entries have been
// written.
IdToRange tab_to_available_range_;
// Force session commands to be rebuild before next save event.
bool rebuild_on_next_save_ = false;
// Don't send duplicate SetSelectedTabInWindow commands when the selected
// tab's index hasn't changed.
std::map<SessionID, int> last_selected_tab_in_window_;
// Set of windows we're tracking changes to. This is only browsers that
// return true from |ShouldRestoreWindowOfType|.
WindowsTracking windows_tracking_;
bool is_saving_enabled_ = true;
bool did_save_commands_at_least_once_ = false;
// The platform session identifier, if supported and successfully initialized.
// See GetPlatformSessionId() for more details.
std::optional<std::string> platform_session_id_;
base::WeakPtrFactory<SessionServiceBase> weak_factory_{this};
};
#endif // CHROME_BROWSER_SESSIONS_SESSION_SERVICE_BASE_H_