• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
6 #define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
7 
8 #include <map>
9 #include <string>
10 
11 #include "base/basictypes.h"
12 #include "base/callback.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/task/cancelable_task_tracker.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/defaults.h"
17 #include "chrome/browser/sessions/base_session_service.h"
18 #include "chrome/browser/sessions/session_id.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_finder.h"
21 #include "chrome/browser/ui/browser_list_observer.h"
22 #include "components/keyed_service/core/keyed_service.h"
23 #include "content/public/browser/notification_observer.h"
24 #include "content/public/browser/notification_registrar.h"
25 #include "ui/base/ui_base_types.h"
26 
27 class Profile;
28 class SessionCommand;
29 struct SessionTab;
30 struct SessionWindow;
31 
32 namespace content {
33 class NavigationEntry;
34 class WebContents;
35 }
36 
37 // SessionService ------------------------------------------------------------
38 
39 // SessionService is responsible for maintaining the state of open windows
40 // and tabs so that they can be restored at a later date. The state of the
41 // currently open browsers is referred to as the current session.
42 //
43 // SessionService supports restoring from the last session. The last session
44 // typically corresponds to the last run of the browser, but not always. For
45 // example, if the user has a tabbed browser and app window running, closes the
46 // tabbed browser, then creates a new tabbed browser the current session is made
47 // the last session and the current session reset. This is done to provide the
48 // illusion that app windows run in separate processes. Similar behavior occurs
49 // with incognito windows.
50 //
51 // SessionService itself maintains a set of SessionCommands that allow
52 // SessionService to rebuild the open state of the browser (as SessionWindow,
53 // SessionTab and SerializedNavigationEntry). The commands are periodically
54 // flushed to SessionBackend and written to a file. Every so often
55 // SessionService rebuilds the contents of the file from the open state of the
56 // browser.
57 class SessionService : public BaseSessionService,
58                        public KeyedService,
59                        public content::NotificationObserver,
60                        public chrome::BrowserListObserver {
61   friend class SessionServiceTestHelper;
62  public:
63   // Used to distinguish an application window from a normal one.
64   enum AppType {
65     TYPE_APP,
66     TYPE_NORMAL
67   };
68 
69   // Creates a SessionService for the specified profile.
70   explicit SessionService(Profile* profile);
71   // For testing.
72   explicit SessionService(const base::FilePath& save_path);
73 
74   virtual ~SessionService();
75 
76   // Returns true if a new window opening should really be treated like the
77   // start of a session (with potential session restore, startup URLs, etc.).
78   // In particular, this is true if there are no tabbed browsers running
79   // currently (eg. because only background or other app pages are running).
80   bool ShouldNewWindowStartSession();
81 
82   // Invoke at a point when you think session restore might occur. For example,
83   // during startup and window creation this is invoked to see if a session
84   // needs to be restored. If a session needs to be restored it is done so
85   // asynchronously and true is returned. If false is returned the session was
86   // not restored and the caller needs to create a new window.
87   bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open);
88 
89   // Resets the contents of the file from the current state of all open
90   // browsers whose profile matches our profile.
91   void ResetFromCurrentBrowsers();
92 
93   // Moves the current session to the last session. This is useful when a
94   // checkpoint occurs, such as when the user launches the app and no tabbed
95   // browsers are running.
96   void MoveCurrentSessionToLastSession();
97 
98   // Associates a tab with a window.
99   void SetTabWindow(const SessionID& window_id,
100                     const SessionID& tab_id);
101 
102   // Sets the bounds of a window.
103   void SetWindowBounds(const SessionID& window_id,
104                        const gfx::Rect& bounds,
105                        ui::WindowShowState show_state);
106 
107   // Sets the visual index of the tab in its parent window.
108   void SetTabIndexInWindow(const SessionID& window_id,
109                            const SessionID& tab_id,
110                            int new_index);
111 
112   // Sets the pinned state of the tab.
113   void SetPinnedState(const SessionID& window_id,
114                       const SessionID& tab_id,
115                       bool is_pinned);
116 
117   // Notification that a tab has been closed. |closed_by_user_gesture| comes
118   // from |WebContents::closed_by_user_gesture|; see it for details.
119   //
120   // Note: this is invoked from the NavigationController's destructor, which is
121   // after the actual tab has been removed.
122   void TabClosed(const SessionID& window_id,
123                  const SessionID& tab_id,
124                  bool closed_by_user_gesture);
125 
126   // Notification a window has opened.
127   void WindowOpened(Browser* browser);
128 
129   // Notification the window is about to close.
130   void WindowClosing(const SessionID& window_id);
131 
132   // Notification a window has finished closing.
133   void WindowClosed(const SessionID& window_id);
134 
135   // Called when a tab is inserted.
136   void TabInserted(content::WebContents* contents);
137 
138   // Called when a tab is closing.
139   void TabClosing(content::WebContents* contents);
140 
141   // Sets the type of window. In order for the contents of a window to be
142   // tracked SetWindowType must be invoked with a type we track
143   // (should_track_changes_for_browser_type returns true).
144   void SetWindowType(const SessionID& window_id,
145                      Browser::Type type,
146                      AppType app_type);
147 
148   // Sets the application name of the specified window.
149   void SetWindowAppName(const SessionID& window_id,
150                         const std::string& app_name);
151 
152   // Invoked when the NavigationController has removed entries from the back of
153   // the list. |count| gives the number of entries in the navigation controller.
154   void TabNavigationPathPrunedFromBack(const SessionID& window_id,
155                                        const SessionID& tab_id,
156                                        int count);
157 
158   // Invoked when the NavigationController has removed entries from the front of
159   // the list. |count| gives the number of entries that were removed.
160   void TabNavigationPathPrunedFromFront(const SessionID& window_id,
161                                         const SessionID& tab_id,
162                                         int count);
163 
164   // Updates the navigation entry for the specified tab.
165   void UpdateTabNavigation(
166       const SessionID& window_id,
167       const SessionID& tab_id,
168       const sessions::SerializedNavigationEntry& navigation);
169 
170   // Notification that a tab has restored its entries or a closed tab is being
171   // reused.
172   void TabRestored(content::WebContents* tab, bool pinned);
173 
174   // Sets the index of the selected entry in the navigation controller for the
175   // specified tab.
176   void SetSelectedNavigationIndex(const SessionID& window_id,
177                                   const SessionID& tab_id,
178                                   int index);
179 
180   // Sets the index of the selected tab in the specified window.
181   void SetSelectedTabInWindow(const SessionID& window_id, int index);
182 
183   // Sets the user agent override of the specified tab.
184   void SetTabUserAgentOverride(const SessionID& window_id,
185                                const SessionID& tab_id,
186                                const std::string& user_agent_override);
187 
188   // Callback from GetLastSession.
189   // The second parameter is the id of the window that was last active.
190   typedef base::Callback<void(ScopedVector<SessionWindow>, SessionID::id_type)>
191       SessionCallback;
192 
193   // Fetches the contents of the last session, notifying the callback when
194   // done. If the callback is supplied an empty vector of SessionWindows
195   // it means the session could not be restored.
196   base::CancelableTaskTracker::TaskId GetLastSession(
197       const SessionCallback& callback,
198       base::CancelableTaskTracker* tracker);
199 
200   // Overridden from BaseSessionService because we want some UMA reporting on
201   // session update activities.
202   virtual void Save() OVERRIDE;
203 
204  private:
205   // Allow tests to access our innards for testing purposes.
206   FRIEND_TEST_ALL_PREFIXES(SessionServiceTest, RestoreActivation1);
207   FRIEND_TEST_ALL_PREFIXES(SessionServiceTest, RestoreActivation2);
208   FRIEND_TEST_ALL_PREFIXES(NoStartupWindowTest, DontInitSessionServiceForApps);
209 
210   typedef std::map<SessionID::id_type, std::pair<int, int> > IdToRange;
211   typedef std::map<SessionID::id_type, SessionTab*> IdToSessionTab;
212   typedef std::map<SessionID::id_type, SessionWindow*> IdToSessionWindow;
213 
214 
215   // These types mirror Browser::Type, but are re-defined here because these
216   // specific enumeration _values_ are written into the session database and
217   // are needed to maintain forward compatibility.
218   // Note that we only store browsers of type TYPE_TABBED and TYPE_POPUP.
219   enum WindowType {
220     TYPE_TABBED = 0,
221     TYPE_POPUP = 1
222   };
223 
224   void Init();
225 
226   // Returns true if we have scheduled any commands, or any scheduled commands
227   // have been saved.
228   bool processed_any_commands();
229 
230   // Implementation of RestoreIfNecessary. If |browser| is non-null and we need
231   // to restore, the tabs are added to it, otherwise a new browser is created.
232   bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open,
233                           Browser* browser);
234 
235   virtual void Observe(int type,
236                        const content::NotificationSource& source,
237                        const content::NotificationDetails& details) OVERRIDE;
238 
239   // chrome::BrowserListObserver
OnBrowserAdded(Browser * browser)240   virtual void OnBrowserAdded(Browser* browser) OVERRIDE {}
OnBrowserRemoved(Browser * browser)241   virtual void OnBrowserRemoved(Browser* browser) OVERRIDE {}
242   virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE;
243 
244   // Sets the application extension id of the specified tab.
245   void SetTabExtensionAppID(const SessionID& window_id,
246                             const SessionID& tab_id,
247                             const std::string& extension_app_id);
248 
249   // Methods to create the various commands. It is up to the caller to delete
250   // the returned the SessionCommand* object.
251   SessionCommand* CreateSetSelectedTabInWindow(const SessionID& window_id,
252                                                int index);
253 
254   SessionCommand* CreateSetTabWindowCommand(const SessionID& window_id,
255                                             const SessionID& tab_id);
256 
257   SessionCommand* CreateSetWindowBoundsCommand(const SessionID& window_id,
258                                                const gfx::Rect& bounds,
259                                                ui::WindowShowState show_state);
260 
261   SessionCommand* CreateSetTabIndexInWindowCommand(const SessionID& tab_id,
262                                                    int new_index);
263 
264   SessionCommand* CreateTabClosedCommand(SessionID::id_type tab_id);
265 
266   SessionCommand* CreateWindowClosedCommand(SessionID::id_type tab_id);
267 
268   SessionCommand* CreateSetSelectedNavigationIndexCommand(
269       const SessionID& tab_id,
270       int index);
271 
272   SessionCommand* CreateSetWindowTypeCommand(const SessionID& window_id,
273                                              WindowType type);
274 
275   SessionCommand* CreatePinnedStateCommand(const SessionID& tab_id,
276                                            bool is_pinned);
277 
278   SessionCommand* CreateSessionStorageAssociatedCommand(
279       const SessionID& tab_id,
280       const std::string& session_storage_persistent_id);
281 
282   SessionCommand* CreateSetActiveWindowCommand(const SessionID& window_id);
283 
284   // Converts |commands| to SessionWindows and notifies the callback.
285   void OnGotSessionCommands(const SessionCallback& callback,
286                             ScopedVector<SessionCommand> commands);
287 
288   // Converts the commands into SessionWindows. On return any valid
289   // windows are added to valid_windows. It is up to the caller to delete
290   // the windows added to valid_windows. |active_window_id| will be set with the
291   // id of the last active window, but it's only valid when this id corresponds
292   // to the id of one of the windows in valid_windows.
293   void RestoreSessionFromCommands(const std::vector<SessionCommand*>& commands,
294                                   std::vector<SessionWindow*>* valid_windows,
295                                   SessionID::id_type* active_window_id);
296 
297   // Iterates through the vector updating the selected_tab_index of each
298   // SessionWindow based on the actual tabs that were restored.
299   void UpdateSelectedTabIndex(std::vector<SessionWindow*>* windows);
300 
301   // Returns the window in windows with the specified id. If a window does
302   // not exist, one is created.
303   SessionWindow* GetWindow(SessionID::id_type window_id,
304                            IdToSessionWindow* windows);
305 
306   // Returns the tab with the specified id in tabs. If a tab does not exist,
307   // it is created.
308   SessionTab* GetTab(SessionID::id_type tab_id,
309                      IdToSessionTab* tabs);
310 
311   // Returns an iterator into navigations pointing to the navigation whose
312   // index matches |index|. If no navigation index matches |index|, the first
313   // navigation with an index > |index| is returned.
314   //
315   // This assumes the navigations are ordered by index in ascending order.
316   std::vector<sessions::SerializedNavigationEntry>::iterator
317   FindClosestNavigationWithIndex(
318       std::vector<sessions::SerializedNavigationEntry>* navigations,
319       int index);
320 
321   // Does the following:
322   // . Deletes and removes any windows with no tabs or windows with types other
323   //   than tabbed_browser or browser. NOTE: constrained windows that have
324   //   been dragged out are of type browser. As such, this preserves any dragged
325   //   out constrained windows (aka popups that have been dragged out).
326   // . Sorts the tabs in windows with valid tabs based on the tabs
327   //   visual order, and adds the valid windows to windows.
328   void SortTabsBasedOnVisualOrderAndPrune(
329       std::map<int, SessionWindow*>* windows,
330       std::vector<SessionWindow*>* valid_windows);
331 
332   // Adds tabs to their parent window based on the tab's window_id. This
333   // ignores tabs with no navigations.
334   void AddTabsToWindows(std::map<int, SessionTab*>* tabs,
335                         std::map<int, SessionWindow*>* windows);
336 
337   // Creates tabs and windows from the commands specified in |data|. The created
338   // tabs and windows are added to |tabs| and |windows| respectively, with the
339   // id of the active window set in |active_window_id|. It is up to the caller
340   // to delete the tabs and windows added to |tabs| and |windows|.
341   //
342   // This does NOT add any created SessionTabs to SessionWindow.tabs, that is
343   // done by AddTabsToWindows.
344   bool CreateTabsAndWindows(const std::vector<SessionCommand*>& data,
345                             std::map<int, SessionTab*>* tabs,
346                             std::map<int, SessionWindow*>* windows,
347                             SessionID::id_type* active_window_id);
348 
349   // Adds commands to commands that will recreate the state of the specified
350   // tab. This adds at most kMaxNavigationCountToPersist navigations (in each
351   // direction from the current navigation index).
352   // A pair is added to tab_to_available_range indicating the range of
353   // indices that were written.
354   void BuildCommandsForTab(
355       const SessionID& window_id,
356       content::WebContents* tab,
357       int index_in_window,
358       bool is_pinned,
359       std::vector<SessionCommand*>* commands,
360       IdToRange* tab_to_available_range);
361 
362   // Adds commands to create the specified browser, and invokes
363   // BuildCommandsForTab for each of the tabs in the browser. This ignores
364   // any tabs not in the profile we were created with.
365   void BuildCommandsForBrowser(
366       Browser* browser,
367       std::vector<SessionCommand*>* commands,
368       IdToRange* tab_to_available_range,
369       std::set<SessionID::id_type>* windows_to_track);
370 
371   // Iterates over all the known browsers invoking BuildCommandsForBrowser.
372   // This only adds browsers that should be tracked
373   // (should_track_changes_for_browser_type returns true). All browsers that
374   // are tracked are added to windows_to_track (as long as it is non-null).
375   void BuildCommandsFromBrowsers(
376       std::vector<SessionCommand*>* commands,
377       IdToRange* tab_to_available_range,
378       std::set<SessionID::id_type>* windows_to_track);
379 
380   // Schedules a reset. A reset means the contents of the file are recreated
381   // from the state of the browser.
382   void ScheduleReset();
383 
384   // Searches for a pending command that can be replaced with command.
385   // If one is found, pending command is removed, command is added to
386   // the pending commands and true is returned.
387   bool ReplacePendingCommand(SessionCommand* command);
388 
389   // Schedules the specified command. This method takes ownership of the
390   // command.
391   virtual void ScheduleCommand(SessionCommand* command) OVERRIDE;
392 
393   // Converts all pending tab/window closes to commands and schedules them.
394   void CommitPendingCloses();
395 
396   // Returns true if there is only one window open with a single tab that shares
397   // our profile.
398   bool IsOnlyOneTabLeft() const;
399 
400   // Returns true if there are open trackable browser windows whose ids do
401   // match |window_id| with our profile. A trackable window is a window from
402   // which |should_track_changes_for_browser_type| returns true. See
403   // |should_track_changes_for_browser_type| for details.
404   bool HasOpenTrackableBrowsers(const SessionID& window_id) const;
405 
406   // Returns true if changes to tabs in the specified window should be tracked.
407   bool ShouldTrackChangesToWindow(const SessionID& window_id) const;
408 
409   // Returns true if we track changes to the specified browser.
410   bool ShouldTrackBrowser(Browser* browser) const;
411 
412   // Returns true if we track changes to the specified browser type.
413   static bool should_track_changes_for_browser_type(
414       Browser::Type type,
415       AppType app_type);
416 
417   // Call when certain session relevant notifications
418   // (tab_closed, nav_list_pruned) occur.  In addition, this is
419   // currently called when Save() is called to compare how often the
420   // session data is currently saved verses when we may want to save it.
421   // It records the data in UMA stats.
422   void RecordSessionUpdateHistogramData(int type,
423     base::TimeTicks* last_updated_time);
424 
425   // Helper methods to record the histogram data
426   void RecordUpdatedTabClosed(base::TimeDelta delta, bool use_long_period);
427   void RecordUpdatedNavListPruned(base::TimeDelta delta, bool use_long_period);
428   void RecordUpdatedNavEntryCommit(base::TimeDelta delta, bool use_long_period);
429   void RecordUpdatedSaveTime(base::TimeDelta delta, bool use_long_period);
430   void RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta,
431                                            bool use_long_period);
432 
433   // Deletes session data if no windows are open for the current profile.
434   void MaybeDeleteSessionOnlyData();
435 
436   // Convert back/forward between the Browser and SessionService DB window
437   // types.
438   static WindowType WindowTypeForBrowserType(Browser::Type type);
439   static Browser::Type BrowserTypeForWindowType(WindowType type);
440 
441   content::NotificationRegistrar registrar_;
442 
443   // Maps from session tab id to the range of navigation entries that has
444   // been written to disk.
445   //
446   // This is only used if not all the navigation entries have been
447   // written.
448   IdToRange tab_to_available_range_;
449 
450   // When the user closes the last window, where the last window is the
451   // last tabbed browser and no more tabbed browsers are open with the same
452   // profile, the window ID is added here. These IDs are only committed (which
453   // marks them as closed) if the user creates a new tabbed browser.
454   typedef std::set<SessionID::id_type> PendingWindowCloseIDs;
455   PendingWindowCloseIDs pending_window_close_ids_;
456 
457   // Set of tabs that have been closed by way of the last window or last tab
458   // closing, but not yet committed.
459   typedef std::set<SessionID::id_type> PendingTabCloseIDs;
460   PendingTabCloseIDs pending_tab_close_ids_;
461 
462   // When a window other than the last window (see description of
463   // pending_window_close_ids) is closed, the id is added to this set.
464   typedef std::set<SessionID::id_type> WindowClosingIDs;
465   WindowClosingIDs window_closing_ids_;
466 
467   // Set of windows we're tracking changes to. This is only browsers that
468   // return true from should_track_changes_for_browser_type.
469   typedef std::set<SessionID::id_type> WindowsTracking;
470   WindowsTracking windows_tracking_;
471 
472   // Are there any open trackable browsers?
473   bool has_open_trackable_browsers_;
474 
475   // If true and a new tabbed browser is created and there are no opened tabbed
476   // browser (has_open_trackable_browsers_ is false), then the current session
477   // is made the last session. See description above class for details on
478   // current/last session.
479   bool move_on_new_browser_;
480 
481   // Used for reporting frequency of session altering operations.
482   base::TimeTicks last_updated_tab_closed_time_;
483   base::TimeTicks last_updated_nav_list_pruned_time_;
484   base::TimeTicks last_updated_nav_entry_commit_time_;
485   base::TimeTicks last_updated_save_time_;
486 
487   // Constants used in calculating histogram data.
488   const base::TimeDelta save_delay_in_millis_;
489   const base::TimeDelta save_delay_in_mins_;
490   const base::TimeDelta save_delay_in_hrs_;
491 
492   // For browser_tests, since we want to simulate the browser shutting down
493   // without quitting.
494   bool force_browser_not_alive_with_no_windows_;
495 
496   DISALLOW_COPY_AND_ASSIGN(SessionService);
497 };
498 
499 #endif  // CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
500