1 // Copyright 2013 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_SYNC_SESSIONS2_SESSIONS_SYNC_MANAGER_H_ 6 #define CHROME_BROWSER_SYNC_SESSIONS2_SESSIONS_SYNC_MANAGER_H_ 7 8 #include <map> 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "base/basictypes.h" 14 #include "base/gtest_prod_util.h" 15 #include "base/memory/scoped_vector.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/time/time.h" 18 #include "chrome/browser/sessions/session_id.h" 19 #include "chrome/browser/sessions/session_types.h" 20 #include "chrome/browser/sync/glue/device_info.h" 21 #include "chrome/browser/sync/glue/favicon_cache.h" 22 #include "chrome/browser/sync/glue/synced_session.h" 23 #include "chrome/browser/sync/glue/synced_session_tracker.h" 24 #include "chrome/browser/sync/open_tabs_ui_delegate.h" 25 #include "chrome/browser/sync/sessions2/tab_node_pool2.h" 26 #include "chrome/browser/sync/sync_prefs.h" 27 #include "sync/api/syncable_service.h" 28 29 class Profile; 30 31 namespace syncer { 32 class SyncErrorFactory; 33 } 34 35 namespace sync_pb { 36 class SessionHeader; 37 class SessionSpecifics; 38 class SessionTab; 39 class SessionWindow; 40 class TabNavigation; 41 } // namespace sync_pb 42 43 namespace browser_sync { 44 45 class DataTypeErrorHandler; 46 class SyncedTabDelegate; 47 class SyncedWindowDelegate; 48 49 // An interface defining the ways in which local open tab events can interact 50 // with session sync. All local tab events flow to sync via this interface. 51 // In that way it is analogous to sync changes flowing to the local model 52 // via ProcessSyncChanges, just with a more granular breakdown. 53 class LocalSessionEventHandler { 54 public: 55 // A local navigation event took place that affects the synced session 56 // for this instance of Chrome. 57 virtual void OnLocalTabModified(SyncedTabDelegate* modified_tab) = 0; 58 59 // A local navigation occurred that triggered updates to favicon data for 60 // each URL in |updated_page_urls|. This is routed through Sessions Sync so 61 // that we can filter (exclude) favicon updates for pages that aren't 62 // currently part of the set of local open tabs, and pass relevant updates 63 // on to FaviconCache for out-of-band favicon syncing. 64 virtual void OnFaviconPageUrlsUpdated( 65 const std::set<GURL>& updated_page_urls) = 0; 66 }; 67 68 // The LocalSessionEventRouter is responsible for hooking itself up to various 69 // notification sources in the browser process and forwarding relevant 70 // events to a handler as defined in the LocalSessionEventHandler contract. 71 class LocalSessionEventRouter { 72 public: 73 virtual ~LocalSessionEventRouter(); 74 virtual void StartRoutingTo(LocalSessionEventHandler* handler) = 0; 75 virtual void Stop() = 0; 76 }; 77 78 // Contains all logic for associating the Chrome sessions model and 79 // the sync sessions model. 80 class SessionsSyncManager : public syncer::SyncableService, 81 public OpenTabsUIDelegate, 82 public LocalSessionEventHandler { 83 public: 84 // Isolates SessionsSyncManager from having to depend on sync internals. 85 class SyncInternalApiDelegate { 86 public: ~SyncInternalApiDelegate()87 virtual ~SyncInternalApiDelegate() {} 88 89 // Returns sync's representation of the local device info. 90 // Return value is an empty scoped_ptr if the device info is unavailable. 91 virtual scoped_ptr<DeviceInfo> GetLocalDeviceInfo() const = 0; 92 93 // Used for creation of the machine tag for this local session. 94 virtual std::string GetLocalSyncCacheGUID() const = 0; 95 }; 96 97 SessionsSyncManager(Profile* profile, 98 SyncInternalApiDelegate* delegate, 99 scoped_ptr<LocalSessionEventRouter> router); 100 virtual ~SessionsSyncManager(); 101 102 // syncer::SyncableService implementation. 103 virtual syncer::SyncMergeResult MergeDataAndStartSyncing( 104 syncer::ModelType type, 105 const syncer::SyncDataList& initial_sync_data, 106 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 107 scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE; 108 virtual void StopSyncing(syncer::ModelType type) OVERRIDE; 109 virtual syncer::SyncDataList GetAllSyncData( 110 syncer::ModelType type) const OVERRIDE; 111 virtual syncer::SyncError ProcessSyncChanges( 112 const tracked_objects::Location& from_here, 113 const syncer::SyncChangeList& change_list) OVERRIDE; 114 115 // OpenTabsUIDelegate implementation. 116 virtual bool GetSyncedFaviconForPageURL( 117 const std::string& pageurl, 118 scoped_refptr<base::RefCountedMemory>* favicon_png) const OVERRIDE; 119 virtual bool GetAllForeignSessions( 120 std::vector<const SyncedSession*>* sessions) OVERRIDE; 121 virtual bool GetForeignSession( 122 const std::string& tag, 123 std::vector<const SessionWindow*>* windows) OVERRIDE; 124 virtual bool GetForeignTab(const std::string& tag, 125 const SessionID::id_type tab_id, 126 const SessionTab** tab) OVERRIDE; 127 virtual void DeleteForeignSession(const std::string& tag) OVERRIDE; 128 129 // LocalSessionEventHandler implementation. 130 virtual void OnLocalTabModified(SyncedTabDelegate* modified_tab) OVERRIDE; 131 virtual void OnFaviconPageUrlsUpdated( 132 const std::set<GURL>& updated_favicon_page_urls) OVERRIDE; 133 134 // Returns the tag used to uniquely identify this machine's session in the 135 // sync model. current_machine_tag()136 const std::string& current_machine_tag() const { 137 DCHECK(!current_machine_tag_.empty()); 138 return current_machine_tag_; 139 } 140 141 // Return the virtual URL of the current tab, even if it's pending. 142 static GURL GetCurrentVirtualURL(const SyncedTabDelegate& tab_delegate); 143 144 // Return the favicon url of the current tab, even if it's pending. 145 static GURL GetCurrentFaviconURL(const SyncedTabDelegate& tab_delegate); 146 147 FaviconCache* GetFaviconCache(); 148 149 // Triggers garbage collection of stale sessions (as defined by 150 // |stale_session_threshold_days_|). This is called automatically every 151 // time we start up (via AssociateModels) and when new sessions data is 152 // downloaded (sync cycles complete). 153 void DoGarbageCollection(); 154 155 private: 156 // Keep all the links to local tab data in one place. A tab_node_id and tab 157 // must be passed at creation. The tab_node_id is not mutable, although 158 // all other fields are. 159 class TabLink { 160 public: TabLink(int tab_node_id,const SyncedTabDelegate * tab)161 TabLink(int tab_node_id, const SyncedTabDelegate* tab) 162 : tab_node_id_(tab_node_id), 163 tab_(tab) {} 164 set_tab(const SyncedTabDelegate * tab)165 void set_tab(const SyncedTabDelegate* tab) { tab_ = tab; } set_url(const GURL & url)166 void set_url(const GURL& url) { url_ = url; } 167 tab_node_id()168 int tab_node_id() const { return tab_node_id_; } tab()169 const SyncedTabDelegate* tab() const { return tab_; } url()170 const GURL& url() const { return url_; } 171 172 private: 173 // The id for the sync node this tab is stored in. 174 const int tab_node_id_; 175 176 // The tab object itself. 177 const SyncedTabDelegate* tab_; 178 179 // The currently visible url of the tab (used for syncing favicons). 180 GURL url_; 181 182 DISALLOW_COPY_AND_ASSIGN(TabLink); 183 }; 184 185 // Container for accessing local tab data by tab id. 186 typedef std::map<SessionID::id_type, linked_ptr<TabLink> > TabLinksMap; 187 188 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, PopulateSessionHeader); 189 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, PopulateSessionWindow); 190 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, ValidTabs); 191 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, SetSessionTabFromDelegate); 192 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, BlockedNavigations); 193 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, DeleteForeignSession); 194 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, 195 SaveUnassociatedNodesForReassociation); 196 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, MergeDeletesCorruptNode); 197 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, 198 MergeLocalSessionExistingTabs); 199 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, 200 CheckPrerenderedWebContentsSwap); 201 FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, 202 AssociateWindowsDontReloadTabs); 203 204 void InitializeCurrentMachineTag(); 205 206 // Load and add window or tab data for a foreign session to our internal 207 // tracking. 208 void UpdateTrackerWithForeignSession( 209 const sync_pb::SessionSpecifics& specifics, 210 const base::Time& modification_time); 211 212 // Returns true if |sync_data| contained a header node for the current 213 // machine, false otherwise. 214 bool InitFromSyncModel(const syncer::SyncDataList& sync_data, 215 syncer::SyncChangeList* new_changes); 216 217 // Helper to construct a deletion SyncChange for a *tab node*. 218 // Caller should check IsValid() on the returned change, as it's possible 219 // this node could not be deleted. 220 syncer::SyncChange TombstoneTab(const sync_pb::SessionSpecifics& tab); 221 222 // Helper method to load the favicon data from the tab specifics. If the 223 // favicon is valid, stores the favicon data into the favicon cache. 224 void RefreshFaviconVisitTimesFromForeignTab( 225 const sync_pb::SessionTab& tab, const base::Time& modification_time); 226 227 // Removes a foreign session from our internal bookkeeping. 228 // Returns true if the session was found and deleted, false if no data was 229 // found for that session. This will *NOT* trigger sync deletions. See 230 // DeleteForeignSession below. 231 bool DisassociateForeignSession(const std::string& foreign_session_tag); 232 233 // Delete a foreign session and all its sync data. 234 // |change_output| *must* be provided as a link to the SyncChange pipeline 235 // that exists in the caller's context. This function will append necessary 236 // changes for processing later. 237 void DeleteForeignSessionInternal(const std::string& tag, 238 syncer::SyncChangeList* change_output); 239 240 // Used to populate a session header from the session specifics header 241 // provided. 242 static void PopulateSessionHeaderFromSpecifics( 243 const sync_pb::SessionHeader& header_specifics, 244 base::Time mtime, 245 SyncedSession* session_header); 246 247 // Builds |session_window| from the session specifics window 248 // provided and updates the SessionTracker with foreign session data created. 249 void BuildSyncedSessionFromSpecifics( 250 const std::string& session_tag, 251 const sync_pb::SessionWindow& specifics, 252 base::Time mtime, 253 SessionWindow* session_window); 254 255 // Resync local window information. Updates the local sessions header node 256 // with the status of open windows and the order of tabs they contain. Should 257 // only be called for changes that affect a window, not a change within a 258 // single tab. 259 // 260 // RELOAD_TABS will additionally cause a resync of all tabs (same as calling 261 // AssociateTabs with a vector of all tabs). 262 // 263 // Returns: false if the local session's sync nodes were deleted and 264 // reassociation is necessary, true otherwise. 265 // 266 // |change_output| *must* be provided as a link to the SyncChange pipeline 267 // that exists in the caller's context. This function will append necessary 268 // changes for processing later. 269 enum ReloadTabsOption { 270 RELOAD_TABS, 271 DONT_RELOAD_TABS 272 }; 273 void AssociateWindows(ReloadTabsOption option, 274 syncer::SyncChangeList* change_output); 275 276 // Loads and reassociates the local tabs referenced in |tabs|. 277 // |change_output| *must* be provided as a link to the SyncChange pipeline 278 // that exists in the caller's context. This function will append necessary 279 // changes for processing later. 280 void AssociateTab(SyncedTabDelegate* const tab, 281 syncer::SyncChangeList* change_output); 282 283 // Control which local tabs we're interested in syncing. 284 // Ensures the profile matches sync's profile and that the tab has valid 285 // entries. 286 bool ShouldSyncTab(const SyncedTabDelegate& tab) const; 287 static bool ShouldSyncWindow(const SyncedWindowDelegate* window); 288 289 // Set |session_tab| from |tab_delegate| and |mtime|. 290 static void SetSessionTabFromDelegate( 291 const SyncedTabDelegate& tab_delegate, 292 base::Time mtime, 293 SessionTab* session_tab); 294 295 // Populates |specifics| based on the data in |tab_delegate|. 296 void LocalTabDelegateToSpecifics(const SyncedTabDelegate& tab_delegate, 297 sync_pb::SessionSpecifics* specifics); 298 299 // It's possible that when we associate windows, tabs aren't all loaded 300 // into memory yet (e.g on android) and we don't have a WebContents. In this 301 // case we can't do a full association, but we still want to update tab IDs 302 // as they may have changed after a session was restored. This method 303 // compares new_tab_id against the previously persisted tab ID (from 304 // our TabNodePool) and updates it if it differs. 305 // TODO(tim): Bug 98892. We should be able to test this for this on android 306 // even though we didn't have tests for old API-based sessions sync. 307 void UpdateTabIdIfNecessary(const SyncedTabDelegate& tab_delegate, 308 SessionID::id_type new_tab_id, 309 syncer::SyncChangeList* change_output); 310 311 // Mapping of current open (local) tabs to their sync identifiers. 312 TabLinksMap local_tab_map_; 313 314 SyncedSessionTracker session_tracker_; 315 FaviconCache favicon_cache_; 316 317 // Pool of used/available sync nodes associated with local tabs. 318 TabNodePool2 local_tab_pool_; 319 320 SyncPrefs sync_prefs_; 321 322 const Profile* const profile_; 323 324 scoped_ptr<syncer::SyncErrorFactory> error_handler_; 325 scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; 326 327 const SyncInternalApiDelegate* const delegate_; 328 329 // Unique client tag. 330 std::string current_machine_tag_; 331 332 // User-visible machine name. 333 std::string current_session_name_; 334 335 // SyncID for the sync node containing all the window information for this 336 // client. 337 int local_session_header_node_id_; 338 339 // Number of days without activity after which we consider a session to be 340 // stale and a candidate for garbage collection. 341 size_t stale_session_threshold_days_; 342 343 scoped_ptr<LocalSessionEventRouter> local_event_router_; 344 345 DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager); 346 }; 347 348 } // namespace browser_sync 349 350 #endif // CHROME_BROWSER_SYNC_SESSIONS2_SESSIONS_SYNC_MANAGER_H_ 351