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