| // 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_ |