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