1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
6 #define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
11 #include "base/basictypes.h"
12 #include "base/callback.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/task/cancelable_task_tracker.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/defaults.h"
18 #include "chrome/browser/sessions/session_common_utils.h"
19 #include "chrome/browser/sessions/session_service_utils.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/browser/ui/browser_list_observer.h"
23 #include "components/keyed_service/core/keyed_service.h"
24 #include "components/sessions/base_session_service_delegate.h"
25 #include "components/sessions/core/tab_restore_service_client.h"
26 #include "components/sessions/session_service_commands.h"
27 #include "content/public/browser/notification_observer.h"
28 #include "content/public/browser/notification_registrar.h"
29 #include "ui/base/ui_base_types.h"
34 class NavigationEntry
;
36 } // namespace content
42 } // namespace sessions
44 // SessionService ------------------------------------------------------------
46 // SessionService is responsible for maintaining the state of open windows
47 // and tabs so that they can be restored at a later date. The state of the
48 // currently open browsers is referred to as the current session.
50 // SessionService supports restoring from the last session. The last session
51 // typically corresponds to the last run of the browser, but not always. For
52 // example, if the user has a tabbed browser and app window running, closes the
53 // tabbed browser, then creates a new tabbed browser the current session is made
54 // the last session and the current session reset. This is done to provide the
55 // illusion that app windows run in separate processes. Similar behavior occurs
56 // with incognito windows.
58 // SessionService itself uses functions from session_service_commands to store
59 // commands which can rebuild the open state of the browser (as |SessionWindow|,
60 // |SessionTab| and |SerializedNavigationEntry|). The commands are periodically
61 // flushed to |SessionBackend| and written to a file. Every so often
62 // |SessionService| rebuilds the contents of the file from the open state of the
64 class SessionService
: public sessions::BaseSessionServiceDelegate
,
66 public content::NotificationObserver
,
67 public chrome::BrowserListObserver
{
68 friend class SessionServiceTestHelper
;
70 // Used to distinguish an application from a ordinary content window.
76 // Creates a SessionService for the specified profile.
77 explicit SessionService(Profile
* profile
);
79 explicit SessionService(const base::FilePath
& save_path
);
81 ~SessionService() override
;
83 // This may be NULL during testing.
84 Profile
* profile() const { return profile_
; }
86 // Returns true if a new window opening should really be treated like the
87 // start of a session (with potential session restore, startup URLs, etc.).
88 // In particular, this is true if there are no tabbed browsers running
89 // currently (eg. because only background or other app pages are running).
90 bool ShouldNewWindowStartSession();
92 // Invoke at a point when you think session restore might occur. For example,
93 // during startup and window creation this is invoked to see if a session
94 // needs to be restored. If a session needs to be restored it is done so
95 // asynchronously and true is returned. If false is returned the session was
96 // not restored and the caller needs to create a new window.
97 bool RestoreIfNecessary(const std::vector
<GURL
>& urls_to_open
);
99 // Resets the contents of the file from the current state of all open
100 // browsers whose profile matches our profile.
101 void ResetFromCurrentBrowsers();
103 // Moves the current session to the last session. This is useful when a
104 // checkpoint occurs, such as when the user launches the app and no tabbed
105 // browsers are running.
106 void MoveCurrentSessionToLastSession();
108 // Deletes the last session.
109 void DeleteLastSession();
111 // Associates a tab with a window.
112 void SetTabWindow(const SessionID
& window_id
,
113 const SessionID
& tab_id
);
115 // Sets the bounds of a window.
116 void SetWindowBounds(const SessionID
& window_id
,
117 const gfx::Rect
& bounds
,
118 ui::WindowShowState show_state
);
120 // Sets the visual index of the tab in its parent window.
121 void SetTabIndexInWindow(const SessionID
& window_id
,
122 const SessionID
& tab_id
,
125 // Sets the pinned state of the tab.
126 void SetPinnedState(const SessionID
& window_id
,
127 const SessionID
& tab_id
,
130 // Notification that a tab has been closed. |closed_by_user_gesture| comes
131 // from |WebContents::closed_by_user_gesture|; see it for details.
133 // Note: this is invoked from the NavigationController's destructor, which is
134 // after the actual tab has been removed.
135 void TabClosed(const SessionID
& window_id
,
136 const SessionID
& tab_id
,
137 bool closed_by_user_gesture
);
139 // Notification a window has opened.
140 void WindowOpened(Browser
* browser
);
142 // Notification the window is about to close.
143 void WindowClosing(const SessionID
& window_id
);
145 // Notification a window has finished closing.
146 void WindowClosed(const SessionID
& window_id
);
148 // Called when a tab is inserted.
149 void TabInserted(content::WebContents
* contents
);
151 // Called when a tab is closing.
152 void TabClosing(content::WebContents
* contents
);
154 // Sets the type of window. In order for the contents of a window to be
155 // tracked SetWindowType must be invoked with a type we track
156 // (ShouldRestoreOfWindowType returns true).
157 void SetWindowType(const SessionID
& window_id
,
161 // Sets the application name of the specified window.
162 void SetWindowAppName(const SessionID
& window_id
,
163 const std::string
& app_name
);
165 // Invoked when the NavigationController has removed entries from the back of
166 // the list. |count| gives the number of entries in the navigation controller.
167 void TabNavigationPathPrunedFromBack(const SessionID
& window_id
,
168 const SessionID
& tab_id
,
171 // Invoked when the NavigationController has removed entries from the front of
172 // the list. |count| gives the number of entries that were removed.
173 void TabNavigationPathPrunedFromFront(const SessionID
& window_id
,
174 const SessionID
& tab_id
,
177 // Updates the navigation entry for the specified tab.
178 void UpdateTabNavigation(
179 const SessionID
& window_id
,
180 const SessionID
& tab_id
,
181 const sessions::SerializedNavigationEntry
& navigation
);
183 // Notification that a tab has restored its entries or a closed tab is being
185 void TabRestored(content::WebContents
* tab
, bool pinned
);
187 // Sets the index of the selected entry in the navigation controller for the
189 void SetSelectedNavigationIndex(const SessionID
& window_id
,
190 const SessionID
& tab_id
,
193 // Sets the index of the selected tab in the specified window.
194 void SetSelectedTabInWindow(const SessionID
& window_id
, int index
);
196 // Sets the user agent override of the specified tab.
197 void SetTabUserAgentOverride(const SessionID
& window_id
,
198 const SessionID
& tab_id
,
199 const std::string
& user_agent_override
);
201 // Sets the application extension id of the specified tab.
202 void SetTabExtensionAppID(const SessionID
& window_id
,
203 const SessionID
& tab_id
,
204 const std::string
& extension_app_id
);
206 // Sets the last active time of the tab.
207 void SetLastActiveTime(const SessionID
& window_id
,
208 const SessionID
& tab_id
,
209 base::TimeTicks last_active_time
);
211 // Fetches the contents of the last session, notifying the callback when
212 // done. If the callback is supplied an empty vector of SessionWindows
213 // it means the session could not be restored.
214 base::CancelableTaskTracker::TaskId
GetLastSession(
215 const sessions::GetLastSessionCallback
& callback
,
216 base::CancelableTaskTracker
* tracker
);
218 // sessions::BaseSessionServiceDelegate:
219 base::SequencedWorkerPool
* GetBlockingPool() override
;
220 bool ShouldUseDelayedSave() override
;
221 void OnSavedCommands() override
;
224 // Allow tests to access our innards for testing purposes.
225 FRIEND_TEST_ALL_PREFIXES(SessionServiceTest
, SavedSessionNotification
);
226 FRIEND_TEST_ALL_PREFIXES(SessionServiceTest
, RestoreActivation1
);
227 FRIEND_TEST_ALL_PREFIXES(SessionServiceTest
, RestoreActivation2
);
228 FRIEND_TEST_ALL_PREFIXES(SessionServiceTest
, RemoveUnusedRestoreWindowsTest
);
229 FRIEND_TEST_ALL_PREFIXES(NoStartupWindowTest
, DontInitSessionServiceForApps
);
231 typedef std::map
<SessionID::id_type
, std::pair
<int, int> > IdToRange
;
235 // Returns true if a window of given |window_type| and |app_type| should get
236 // restored upon session restore.
237 bool ShouldRestoreWindowOfType(sessions::SessionWindow::WindowType type
,
238 AppType app_type
) const;
240 // Removes unrestorable windows from the previous windows list.
241 void RemoveUnusedRestoreWindows(
242 std::vector
<sessions::SessionWindow
*>* window_list
);
244 // Implementation of RestoreIfNecessary. If |browser| is non-null and we need
245 // to restore, the tabs are added to it, otherwise a new browser is created.
246 bool RestoreIfNecessary(const std::vector
<GURL
>& urls_to_open
,
249 void Observe(int type
,
250 const content::NotificationSource
& source
,
251 const content::NotificationDetails
& details
) override
;
253 // chrome::BrowserListObserver
254 void OnBrowserAdded(Browser
* browser
) override
{}
255 void OnBrowserRemoved(Browser
* browser
) override
{}
256 void OnBrowserSetLastActive(Browser
* browser
) override
;
258 // Converts |commands| to SessionWindows and notifies the callback.
259 void OnGotSessionCommands(const sessions::GetLastSessionCallback
& callback
,
260 ScopedVector
<sessions::SessionCommand
> commands
);
262 // Adds commands to commands that will recreate the state of the specified
263 // tab. This adds at most kMaxNavigationCountToPersist navigations (in each
264 // direction from the current navigation index).
265 // A pair is added to tab_to_available_range indicating the range of
266 // indices that were written.
267 void BuildCommandsForTab(
268 const SessionID
& window_id
,
269 content::WebContents
* tab
,
272 IdToRange
* tab_to_available_range
);
274 // Adds commands to create the specified browser, and invokes
275 // BuildCommandsForTab for each of the tabs in the browser. This ignores
276 // any tabs not in the profile we were created with.
277 void BuildCommandsForBrowser(
279 IdToRange
* tab_to_available_range
,
280 std::set
<SessionID::id_type
>* windows_to_track
);
282 // Iterates over all the known browsers invoking BuildCommandsForBrowser.
283 // This only adds browsers that should be tracked (|ShouldRestoreWindowOfType|
284 // returns true). All browsers that are tracked are added to windows_to_track
285 // (as long as it is non-null).
286 void BuildCommandsFromBrowsers(
287 IdToRange
* tab_to_available_range
,
288 std::set
<SessionID::id_type
>* windows_to_track
);
290 // Schedules a reset of the existing commands. A reset means the contents
291 // of the file are recreated from the state of the browser.
292 void ScheduleResetCommands();
294 // Schedules the specified command.
295 void ScheduleCommand(scoped_ptr
<sessions::SessionCommand
> command
);
297 // Converts all pending tab/window closes to commands and schedules them.
298 void CommitPendingCloses();
300 // Returns true if there is only one window open with a single tab that shares
302 bool IsOnlyOneTabLeft() const;
304 // Returns true if there are open trackable browser windows whose ids do
305 // match |window_id| with our profile. A trackable window is a window from
306 // which |ShouldRestoreWindowOfType| returns true. See
307 // |ShouldRestoreWindowOfType| for details.
308 bool HasOpenTrackableBrowsers(const SessionID
& window_id
) const;
310 // Returns true if changes to tabs in the specified window should be tracked.
311 bool ShouldTrackChangesToWindow(const SessionID
& window_id
) const;
313 // Returns true if we track changes to the specified browser.
314 bool ShouldTrackBrowser(Browser
* browser
) const;
316 // Call when certain session relevant notifications
317 // (tab_closed, nav_list_pruned) occur. In addition, this is
318 // currently called when Save() is called to compare how often the
319 // session data is currently saved verses when we may want to save it.
320 // It records the data in UMA stats.
321 void RecordSessionUpdateHistogramData(int type
,
322 base::TimeTicks
* last_updated_time
);
324 // Helper methods to record the histogram data
325 void RecordUpdatedTabClosed(base::TimeDelta delta
, bool use_long_period
);
326 void RecordUpdatedNavListPruned(base::TimeDelta delta
, bool use_long_period
);
327 void RecordUpdatedNavEntryCommit(base::TimeDelta delta
, bool use_long_period
);
328 void RecordUpdatedSaveTime(base::TimeDelta delta
, bool use_long_period
);
329 void RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta
,
330 bool use_long_period
);
332 // Deletes session data if no windows are open for the current profile.
333 void MaybeDeleteSessionOnlyData();
335 // Unit test accessors.
336 sessions::BaseSessionService
* GetBaseSessionServiceForTest();
338 // The profile. This may be null during testing.
341 // Whether to use delayed save. Set to false when constructed with a FilePath
342 // (which should only be used for testing).
343 bool should_use_delayed_save_
;
345 // The owned BaseSessionService.
346 scoped_ptr
<sessions::BaseSessionService
> base_session_service_
;
348 content::NotificationRegistrar registrar_
;
350 // Maps from session tab id to the range of navigation entries that has
351 // been written to disk.
353 // This is only used if not all the navigation entries have been
355 IdToRange tab_to_available_range_
;
357 // When the user closes the last window, where the last window is the
358 // last tabbed browser and no more tabbed browsers are open with the same
359 // profile, the window ID is added here. These IDs are only committed (which
360 // marks them as closed) if the user creates a new tabbed browser.
361 typedef std::set
<SessionID::id_type
> PendingWindowCloseIDs
;
362 PendingWindowCloseIDs pending_window_close_ids_
;
364 // Set of tabs that have been closed by way of the last window or last tab
365 // closing, but not yet committed.
366 typedef std::set
<SessionID::id_type
> PendingTabCloseIDs
;
367 PendingTabCloseIDs pending_tab_close_ids_
;
369 // When a window other than the last window (see description of
370 // pending_window_close_ids) is closed, the id is added to this set.
371 typedef std::set
<SessionID::id_type
> WindowClosingIDs
;
372 WindowClosingIDs window_closing_ids_
;
374 // Set of windows we're tracking changes to. This is only browsers that
375 // return true from |ShouldRestoreWindowOfType|.
376 typedef std::set
<SessionID::id_type
> WindowsTracking
;
377 WindowsTracking windows_tracking_
;
379 // Are there any open trackable browsers?
380 bool has_open_trackable_browsers_
;
382 // If true and a new tabbed browser is created and there are no opened tabbed
383 // browser (has_open_trackable_browsers_ is false), then the current session
384 // is made the last session. See description above class for details on
385 // current/last session.
386 bool move_on_new_browser_
;
388 // Used for reporting frequency of session altering operations.
389 base::TimeTicks last_updated_tab_closed_time_
;
390 base::TimeTicks last_updated_nav_list_pruned_time_
;
391 base::TimeTicks last_updated_nav_entry_commit_time_
;
392 base::TimeTicks last_updated_save_time_
;
394 // Constants used in calculating histogram data.
395 const base::TimeDelta save_delay_in_millis_
;
396 const base::TimeDelta save_delay_in_mins_
;
397 const base::TimeDelta save_delay_in_hrs_
;
399 // For browser_tests, since we want to simulate the browser shutting down
401 bool force_browser_not_alive_with_no_windows_
;
403 base::WeakPtrFactory
<SessionService
> weak_factory_
;
405 DISALLOW_COPY_AND_ASSIGN(SessionService
);
408 #endif // CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_