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