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 240 virtual void OnBrowserAdded(Browser* browser) OVERRIDE {} 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