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