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