Home | History | Annotate | Download | only in sessions
      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.
    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.
    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