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/time/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_finder.h" 20 #include "chrome/browser/ui/browser_list_observer.h" 21 #include "chrome/common/cancelable_task_tracker.h" 22 #include "components/browser_context_keyed_service/browser_context_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 BrowserContextKeyedService, 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 the window is about to close. 127 void WindowClosing(const SessionID& window_id); 128 129 // Notification a window has finished closing. 130 void WindowClosed(const SessionID& window_id); 131 132 // Called when a tab is inserted. 133 void TabInserted(content::WebContents* contents); 134 135 // Called when a tab is closing. 136 void TabClosing(content::WebContents* contents); 137 138 // Sets the type of window. In order for the contents of a window to be 139 // tracked SetWindowType must be invoked with a type we track 140 // (should_track_changes_for_browser_type returns true). 141 void SetWindowType(const SessionID& window_id, 142 Browser::Type type, 143 AppType app_type); 144 145 // Sets the application name of the specified window. 146 void SetWindowAppName(const SessionID& window_id, 147 const std::string& app_name); 148 149 // Invoked when the NavigationController has removed entries from the back of 150 // the list. |count| gives the number of entries in the navigation controller. 151 void TabNavigationPathPrunedFromBack(const SessionID& window_id, 152 const SessionID& tab_id, 153 int count); 154 155 // Invoked when the NavigationController has removed entries from the front of 156 // the list. |count| gives the number of entries that were removed. 157 void TabNavigationPathPrunedFromFront(const SessionID& window_id, 158 const SessionID& tab_id, 159 int count); 160 161 // Updates the navigation entry for the specified tab. 162 void UpdateTabNavigation( 163 const SessionID& window_id, 164 const SessionID& tab_id, 165 const sessions::SerializedNavigationEntry& navigation); 166 167 // Notification that a tab has restored its entries or a closed tab is being 168 // reused. 169 void TabRestored(content::WebContents* tab, bool pinned); 170 171 // Sets the index of the selected entry in the navigation controller for the 172 // specified tab. 173 void SetSelectedNavigationIndex(const SessionID& window_id, 174 const SessionID& tab_id, 175 int index); 176 177 // Sets the index of the selected tab in the specified window. 178 void SetSelectedTabInWindow(const SessionID& window_id, int index); 179 180 // Sets the user agent override of the specified tab. 181 void SetTabUserAgentOverride(const SessionID& window_id, 182 const SessionID& tab_id, 183 const std::string& user_agent_override); 184 185 // Callback from GetLastSession. 186 // The second parameter is the id of the window that was last active. 187 typedef base::Callback<void(ScopedVector<SessionWindow>, SessionID::id_type)> 188 SessionCallback; 189 190 // Fetches the contents of the last session, notifying the callback when 191 // done. If the callback is supplied an empty vector of SessionWindows 192 // it means the session could not be restored. 193 CancelableTaskTracker::TaskId GetLastSession(const SessionCallback& callback, 194 CancelableTaskTracker* tracker); 195 196 // Overridden from BaseSessionService because we want some UMA reporting on 197 // session update activities. 198 virtual void Save() OVERRIDE; 199 200 private: 201 // Allow tests to access our innards for testing purposes. 202 FRIEND_TEST_ALL_PREFIXES(SessionServiceTest, RestoreActivation1); 203 FRIEND_TEST_ALL_PREFIXES(SessionServiceTest, RestoreActivation2); 204 FRIEND_TEST_ALL_PREFIXES(NoStartupWindowTest, DontInitSessionServiceForApps); 205 206 typedef std::map<SessionID::id_type, std::pair<int, int> > IdToRange; 207 typedef std::map<SessionID::id_type, SessionTab*> IdToSessionTab; 208 typedef std::map<SessionID::id_type, SessionWindow*> IdToSessionWindow; 209 210 211 // These types mirror Browser::Type, but are re-defined here because these 212 // specific enumeration _values_ are written into the session database and 213 // are needed to maintain forward compatibility. 214 // Note that we only store browsers of type TYPE_TABBED and TYPE_POPUP. 215 enum WindowType { 216 TYPE_TABBED = 0, 217 TYPE_POPUP = 1 218 }; 219 220 void Init(); 221 222 // Returns true if we have scheduled any commands, or any scheduled commands 223 // have been saved. 224 bool processed_any_commands(); 225 226 // Implementation of RestoreIfNecessary. If |browser| is non-null and we need 227 // to restore, the tabs are added to it, otherwise a new browser is created. 228 bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open, 229 Browser* browser); 230 231 virtual void Observe(int type, 232 const content::NotificationSource& source, 233 const content::NotificationDetails& details) OVERRIDE; 234 235 // chrome::BrowserListObserver 236 virtual void OnBrowserAdded(Browser* browser) OVERRIDE {} 237 virtual void OnBrowserRemoved(Browser* browser) OVERRIDE {} 238 virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE; 239 240 // Sets the application extension id of the specified tab. 241 void SetTabExtensionAppID(const SessionID& window_id, 242 const SessionID& tab_id, 243 const std::string& extension_app_id); 244 245 // Methods to create the various commands. It is up to the caller to delete 246 // the returned the SessionCommand* object. 247 SessionCommand* CreateSetSelectedTabInWindow(const SessionID& window_id, 248 int index); 249 250 SessionCommand* CreateSetTabWindowCommand(const SessionID& window_id, 251 const SessionID& tab_id); 252 253 SessionCommand* CreateSetWindowBoundsCommand(const SessionID& window_id, 254 const gfx::Rect& bounds, 255 ui::WindowShowState show_state); 256 257 SessionCommand* CreateSetTabIndexInWindowCommand(const SessionID& tab_id, 258 int new_index); 259 260 SessionCommand* CreateTabClosedCommand(SessionID::id_type tab_id); 261 262 SessionCommand* CreateWindowClosedCommand(SessionID::id_type tab_id); 263 264 SessionCommand* CreateSetSelectedNavigationIndexCommand( 265 const SessionID& tab_id, 266 int index); 267 268 SessionCommand* CreateSetWindowTypeCommand(const SessionID& window_id, 269 WindowType type); 270 271 SessionCommand* CreatePinnedStateCommand(const SessionID& tab_id, 272 bool is_pinned); 273 274 SessionCommand* CreateSessionStorageAssociatedCommand( 275 const SessionID& tab_id, 276 const std::string& session_storage_persistent_id); 277 278 SessionCommand* CreateSetActiveWindowCommand(const SessionID& window_id); 279 280 // Converts |commands| to SessionWindows and notifies the callback. 281 void OnGotSessionCommands(const SessionCallback& callback, 282 ScopedVector<SessionCommand> commands); 283 284 // Converts the commands into SessionWindows. On return any valid 285 // windows are added to valid_windows. It is up to the caller to delete 286 // the windows added to valid_windows. |active_window_id| will be set with the 287 // id of the last active window, but it's only valid when this id corresponds 288 // to the id of one of the windows in valid_windows. 289 void RestoreSessionFromCommands(const std::vector<SessionCommand*>& commands, 290 std::vector<SessionWindow*>* valid_windows, 291 SessionID::id_type* active_window_id); 292 293 // Iterates through the vector updating the selected_tab_index of each 294 // SessionWindow based on the actual tabs that were restored. 295 void UpdateSelectedTabIndex(std::vector<SessionWindow*>* windows); 296 297 // Returns the window in windows with the specified id. If a window does 298 // not exist, one is created. 299 SessionWindow* GetWindow(SessionID::id_type window_id, 300 IdToSessionWindow* windows); 301 302 // Returns the tab with the specified id in tabs. If a tab does not exist, 303 // it is created. 304 SessionTab* GetTab(SessionID::id_type tab_id, 305 IdToSessionTab* tabs); 306 307 // Returns an iterator into navigations pointing to the navigation whose 308 // index matches |index|. If no navigation index matches |index|, the first 309 // navigation with an index > |index| is returned. 310 // 311 // This assumes the navigations are ordered by index in ascending order. 312 std::vector<sessions::SerializedNavigationEntry>::iterator 313 FindClosestNavigationWithIndex( 314 std::vector<sessions::SerializedNavigationEntry>* navigations, 315 int index); 316 317 // Does the following: 318 // . Deletes and removes any windows with no tabs or windows with types other 319 // than tabbed_browser or browser. NOTE: constrained windows that have 320 // been dragged out are of type browser. As such, this preserves any dragged 321 // out constrained windows (aka popups that have been dragged out). 322 // . Sorts the tabs in windows with valid tabs based on the tabs 323 // visual order, and adds the valid windows to windows. 324 void SortTabsBasedOnVisualOrderAndPrune( 325 std::map<int, SessionWindow*>* windows, 326 std::vector<SessionWindow*>* valid_windows); 327 328 // Adds tabs to their parent window based on the tab's window_id. This 329 // ignores tabs with no navigations. 330 void AddTabsToWindows(std::map<int, SessionTab*>* tabs, 331 std::map<int, SessionWindow*>* windows); 332 333 // Creates tabs and windows from the commands specified in |data|. The created 334 // tabs and windows are added to |tabs| and |windows| respectively, with the 335 // id of the active window set in |active_window_id|. It is up to the caller 336 // to delete the tabs and windows added to |tabs| and |windows|. 337 // 338 // This does NOT add any created SessionTabs to SessionWindow.tabs, that is 339 // done by AddTabsToWindows. 340 bool CreateTabsAndWindows(const std::vector<SessionCommand*>& data, 341 std::map<int, SessionTab*>* tabs, 342 std::map<int, SessionWindow*>* windows, 343 SessionID::id_type* active_window_id); 344 345 // Adds commands to commands that will recreate the state of the specified 346 // tab. This adds at most kMaxNavigationCountToPersist navigations (in each 347 // direction from the current navigation index). 348 // A pair is added to tab_to_available_range indicating the range of 349 // indices that were written. 350 void BuildCommandsForTab( 351 const SessionID& window_id, 352 content::WebContents* tab, 353 int index_in_window, 354 bool is_pinned, 355 std::vector<SessionCommand*>* commands, 356 IdToRange* tab_to_available_range); 357 358 // Adds commands to create the specified browser, and invokes 359 // BuildCommandsForTab for each of the tabs in the browser. This ignores 360 // any tabs not in the profile we were created with. 361 void BuildCommandsForBrowser( 362 Browser* browser, 363 std::vector<SessionCommand*>* commands, 364 IdToRange* tab_to_available_range, 365 std::set<SessionID::id_type>* windows_to_track); 366 367 // Iterates over all the known browsers invoking BuildCommandsForBrowser. 368 // This only adds browsers that should be tracked 369 // (should_track_changes_for_browser_type returns true). All browsers that 370 // are tracked are added to windows_to_track (as long as it is non-null). 371 void BuildCommandsFromBrowsers( 372 std::vector<SessionCommand*>* commands, 373 IdToRange* tab_to_available_range, 374 std::set<SessionID::id_type>* windows_to_track); 375 376 // Schedules a reset. A reset means the contents of the file are recreated 377 // from the state of the browser. 378 void ScheduleReset(); 379 380 // Searches for a pending command that can be replaced with command. 381 // If one is found, pending command is removed, command is added to 382 // the pending commands and true is returned. 383 bool ReplacePendingCommand(SessionCommand* command); 384 385 // Schedules the specified command. This method takes ownership of the 386 // command. 387 virtual void ScheduleCommand(SessionCommand* command) OVERRIDE; 388 389 // Converts all pending tab/window closes to commands and schedules them. 390 void CommitPendingCloses(); 391 392 // Returns true if there is only one window open with a single tab that shares 393 // our profile. 394 bool IsOnlyOneTabLeft() const; 395 396 // Returns true if there are open trackable browser windows whose ids do 397 // match |window_id| with our profile. A trackable window is a window from 398 // which |should_track_changes_for_browser_type| returns true. See 399 // |should_track_changes_for_browser_type| for details. 400 bool HasOpenTrackableBrowsers(const SessionID& window_id) const; 401 402 // Returns true if changes to tabs in the specified window should be tracked. 403 bool ShouldTrackChangesToWindow(const SessionID& window_id) const; 404 405 // Returns true if we track changes to the specified browser. 406 bool ShouldTrackBrowser(Browser* browser) const; 407 408 // Returns true if we track changes to the specified browser type. 409 static bool should_track_changes_for_browser_type( 410 Browser::Type type, 411 AppType app_type); 412 413 // Returns true if we should record a window close as pending. 414 // |has_open_trackable_browsers_| must be up-to-date before calling this. 415 bool should_record_close_as_pending() const { 416 // When this is called, the browser window being closed is still open, hence 417 // still in the browser list. If there is a browser window other than the 418 // one being closed but no trackable windows, then the others must be App 419 // windows or similar. In this case, we record the close as pending. 420 return !has_open_trackable_browsers_ && 421 (!browser_defaults::kBrowserAliveWithNoWindows || 422 force_browser_not_alive_with_no_windows_ || 423 chrome::GetTotalBrowserCount() > 1); 424 } 425 426 // Call when certain session relevant notifications 427 // (tab_closed, nav_list_pruned) occur. In addition, this is 428 // currently called when Save() is called to compare how often the 429 // session data is currently saved verses when we may want to save it. 430 // It records the data in UMA stats. 431 void RecordSessionUpdateHistogramData(int type, 432 base::TimeTicks* last_updated_time); 433 434 // Helper methods to record the histogram data 435 void RecordUpdatedTabClosed(base::TimeDelta delta, bool use_long_period); 436 void RecordUpdatedNavListPruned(base::TimeDelta delta, bool use_long_period); 437 void RecordUpdatedNavEntryCommit(base::TimeDelta delta, bool use_long_period); 438 void RecordUpdatedSaveTime(base::TimeDelta delta, bool use_long_period); 439 void RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta, 440 bool use_long_period); 441 442 // Convert back/forward between the Browser and SessionService DB window 443 // types. 444 static WindowType WindowTypeForBrowserType(Browser::Type type); 445 static Browser::Type BrowserTypeForWindowType(WindowType type); 446 447 content::NotificationRegistrar registrar_; 448 449 // Maps from session tab id to the range of navigation entries that has 450 // been written to disk. 451 // 452 // This is only used if not all the navigation entries have been 453 // written. 454 IdToRange tab_to_available_range_; 455 456 // When the user closes the last window, where the last window is the 457 // last tabbed browser and no more tabbed browsers are open with the same 458 // profile, the window ID is added here. These IDs are only committed (which 459 // marks them as closed) if the user creates a new tabbed browser. 460 typedef std::set<SessionID::id_type> PendingWindowCloseIDs; 461 PendingWindowCloseIDs pending_window_close_ids_; 462 463 // Set of tabs that have been closed by way of the last window or last tab 464 // closing, but not yet committed. 465 typedef std::set<SessionID::id_type> PendingTabCloseIDs; 466 PendingTabCloseIDs pending_tab_close_ids_; 467 468 // When a window other than the last window (see description of 469 // pending_window_close_ids) is closed, the id is added to this set. 470 typedef std::set<SessionID::id_type> WindowClosingIDs; 471 WindowClosingIDs window_closing_ids_; 472 473 // Set of windows we're tracking changes to. This is only browsers that 474 // return true from should_track_changes_for_browser_type. 475 typedef std::set<SessionID::id_type> WindowsTracking; 476 WindowsTracking windows_tracking_; 477 478 // Are there any open trackable browsers? 479 bool has_open_trackable_browsers_; 480 481 // If true and a new tabbed browser is created and there are no opened tabbed 482 // browser (has_open_trackable_browsers_ is false), then the current session 483 // is made the last session. See description above class for details on 484 // current/last session. 485 bool move_on_new_browser_; 486 487 // Used for reporting frequency of session altering operations. 488 base::TimeTicks last_updated_tab_closed_time_; 489 base::TimeTicks last_updated_nav_list_pruned_time_; 490 base::TimeTicks last_updated_nav_entry_commit_time_; 491 base::TimeTicks last_updated_save_time_; 492 493 // Constants used in calculating histogram data. 494 const base::TimeDelta save_delay_in_millis_; 495 const base::TimeDelta save_delay_in_mins_; 496 const base::TimeDelta save_delay_in_hrs_; 497 498 // For browser_tests, since we want to simulate the browser shutting down 499 // without quitting. 500 bool force_browser_not_alive_with_no_windows_; 501 502 DISALLOW_COPY_AND_ASSIGN(SessionService); 503 }; 504 505 #endif // CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_ 506