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 COMPONENTS_SYNC_SESSIONS_FAVICON_CACHE_H_ 6 #define COMPONENTS_SYNC_SESSIONS_FAVICON_CACHE_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <map> 12 #include <memory> 13 #include <set> 14 #include <string> 15 #include <vector> 16 17 #include "base/compiler_specific.h" 18 #include "base/gtest_prod_util.h" 19 #include "base/macros.h" 20 #include "base/memory/ref_counted.h" 21 #include "base/memory/ref_counted_memory.h" 22 #include "base/memory/weak_ptr.h" 23 #include "base/scoped_observer.h" 24 #include "base/task/cancelable_task_tracker.h" 25 #include "components/favicon_base/favicon_types.h" 26 #include "components/history/core/browser/history_service.h" 27 #include "components/history/core/browser/history_service_observer.h" 28 #include "components/history/core/browser/history_types.h" 29 #include "components/sessions/core/session_id.h" 30 #include "components/sync/model/sync_change.h" 31 #include "components/sync/model/sync_error_factory.h" 32 #include "components/sync/model/syncable_service.h" 33 #include "components/sync/protocol/session_specifics.pb.h" 34 #include "url/gurl.h" 35 36 namespace chrome { 37 struct FaviconRawBitmapResult; 38 } 39 40 namespace favicon { 41 class FaviconService; 42 } 43 44 namespace sync_sessions { 45 46 enum IconSize { 47 SIZE_INVALID, 48 SIZE_16, 49 SIZE_32, 50 SIZE_64, 51 NUM_SIZES 52 }; 53 54 struct SyncedFaviconInfo; 55 56 // FAVICON SYNC IS DEPRECATED: This class now only serves to the translation 57 // from page url to icon url using sessions sync information. 58 // TODO(https://crbug.com/978775): Stop implementing syncer::SyncableService 59 // and rename the class accordingly. 60 // TODO(zea): make this a KeyedService. 61 // Encapsulates the logic for loading and storing synced favicons. 62 class FaviconCache : public syncer::SyncableService, 63 public history::HistoryServiceObserver { 64 public: 65 FaviconCache(favicon::FaviconService* favicon_service, 66 history::HistoryService* history_service, 67 int max_sync_favicon_limit); 68 ~FaviconCache() override; 69 70 // SyncableService implementation. 71 void WaitUntilReadyToSync(base::OnceClosure done) override; 72 syncer::SyncMergeResult MergeDataAndStartSyncing( 73 syncer::ModelType type, 74 const syncer::SyncDataList& initial_sync_data, 75 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, 76 std::unique_ptr<syncer::SyncErrorFactory> error_handler) override; 77 void StopSyncing(syncer::ModelType type) override; 78 syncer::SyncDataList GetAllSyncDataForTesting(syncer::ModelType type) const; 79 syncer::SyncError ProcessSyncChanges( 80 const base::Location& from_here, 81 const syncer::SyncChangeList& change_list) override; 82 83 // If a valid favicon for the icon at |favicon_url| is found, returns a 84 // pointer to the png-encoded image. Otherwise, returns nullptr. 85 favicon_base::FaviconRawBitmapResult GetSyncedFaviconForFaviconURL( 86 const GURL& favicon_url) const; 87 88 // Returns the value associated with |page_url| in |page_favicon_map_| if one 89 // exists, otherwise returns an empty URL. 90 GURL GetIconUrlForPageUrl(const GURL& page_url) const; 91 92 // If a valid favicon for the icon associated with |page_url| is found, 93 // returns a pointer to the png-encoded image. Otherwise, returns nullptr. 94 favicon_base::FaviconRawBitmapResult GetSyncedFaviconForPageURL( 95 const GURL& page_url) const; 96 97 // Load the favicon for |page_url|. Will create a new sync node or update 98 // an existing one as necessary, and update the last visit time with |mtime|, 99 // Only those favicon types defined in SupportedFaviconTypes will be synced. 100 void OnPageFaviconUpdated(const GURL& page_url, base::Time mtime); 101 102 // Update the visit count for the favicon associated with |favicon_url|. 103 // If no favicon exists associated with |favicon_url|, triggers a load 104 // for the favicon associated with |page_url|. 105 void OnFaviconVisited(const GURL& page_url, const GURL& favicon_url); 106 107 // Consume Session sync favicon data to update the in-memory page->favicon url 108 // mappings and visit times. 109 void UpdateMappingsFromForeignTab(const sync_pb::SessionTab& tab, 110 base::Time visit_time); 111 112 base::WeakPtr<FaviconCache> GetWeakPtr(); 113 114 // For testing only. 115 size_t NumFaviconsForTest() const; 116 size_t NumTasksForTest() const; 117 base::Time GetLastVisitTimeForTest(const GURL& favicon_url) const; 118 119 private: 120 FRIEND_TEST_ALL_PREFIXES(SyncFaviconCacheTest, HistoryFullClear); 121 FRIEND_TEST_ALL_PREFIXES(SyncFaviconCacheTest, HistorySubsetClear); 122 123 // Functor for ordering SyncedFaviconInfo objects by recency; 124 struct FaviconRecencyFunctor { 125 bool operator()(const SyncedFaviconInfo* lhs, 126 const SyncedFaviconInfo* rhs) const; 127 }; 128 129 130 // Map of favicon url to favicon image. 131 using FaviconMap = std::map<GURL, std::unique_ptr<SyncedFaviconInfo>>; 132 using RecencySet = std::set<SyncedFaviconInfo*, FaviconRecencyFunctor>; 133 134 // Callback method to store a tab's favicon into its sync node once it becomes 135 // available. Does nothing if no favicon data was available. 136 void OnFaviconDataAvailable( 137 const GURL& page_url, 138 base::Time mtime, 139 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_result); 140 141 // Helper method to update the sync state of the favicon at |icon_url|. If 142 // either |image_change_type| or |tracking_change_type| is ACTION_INVALID, 143 // the corresponding datatype won't be updated. 144 // Note: should only be called after both FAVICON_IMAGES and FAVICON_TRACKING 145 // have been successfully set up. 146 void UpdateSyncState(const GURL& icon_url, 147 syncer::SyncChange::SyncChangeType image_change_type, 148 syncer::SyncChange::SyncChangeType tracking_change_type); 149 150 // Helper method to get favicon info from |synced_favicons_|. If no info 151 // exists for |icon_url|, creates a new SyncedFaviconInfo in both 152 // |synced_favicons_| and |recent_favicons_| and returns it. 153 SyncedFaviconInfo* GetFaviconInfo(const GURL& icon_url); 154 155 // Updates the last visit time for the favicon at |icon_url| to |time| and 156 // correspondingly updates position in |recent_favicons_|. 157 void UpdateFaviconVisitTime(const GURL& icon_url, base::Time time); 158 159 // Expiration method. Looks through |recent_favicons_| to find any favicons 160 // that should be expired in order to maintain the sync favicon limit, 161 // appending deletions to |image_changes| and |tracking_changes| as necessary. 162 void ExpireFaviconsIfNecessary(syncer::SyncChangeList* image_changes, 163 syncer::SyncChangeList* tracking_changes); 164 165 // Returns the local favicon url associated with |sync_favicon| if one exists 166 // in |synced_favicons_|, else returns an invalid GURL. 167 GURL GetLocalFaviconFromSyncedData( 168 const syncer::SyncData& sync_favicon) const; 169 170 // Merges |sync_favicon| into |synced_favicons_|, updating |local_changes| 171 // with any changes that should be pushed to the sync processor. 172 void MergeSyncFavicon(const syncer::SyncData& sync_favicon, 173 syncer::SyncChangeList* sync_changes); 174 175 // Updates |synced_favicons_| with the favicon data from |sync_favicon|. 176 void AddLocalFaviconFromSyncedData(const syncer::SyncData& sync_favicon); 177 178 // Creates a SyncData object from the |type| data of |favicon_url| 179 // from within |synced_favicons_|. 180 syncer::SyncData CreateSyncDataFromLocalFavicon( 181 syncer::ModelType type, 182 const GURL& favicon_url) const; 183 184 // Deletes all synced favicons corresponding with |favicon_urls| and pushes 185 // the deletions to sync. 186 void DeleteSyncedFavicons(const std::set<GURL>& favicon_urls); 187 188 // Deletes the favicon pointed to by |favicon_iter| and appends the necessary 189 // sync deletions to |image_changes| and |tracking_changes|. 190 void DeleteSyncedFavicon(FaviconMap::iterator favicon_iter, 191 syncer::SyncChangeList* image_changes, 192 syncer::SyncChangeList* tracking_changes); 193 194 // Locally drops the favicon pointed to by |favicon_iter|. 195 void DropSyncedFavicon(FaviconMap::iterator favicon_iter); 196 197 // Only drops the data associated with |type| of |favicon_iter|. 198 void DropPartialFavicon(FaviconMap::iterator favicon_iter, 199 syncer::ModelType type); 200 201 // history::HistoryServiceObserver: 202 void OnURLsDeleted(history::HistoryService* history_service, 203 const history::DeletionInfo& deletion_info) override; 204 void OnHistoryServiceLoaded( 205 history::HistoryService* history_service) override; 206 207 favicon::FaviconService* const favicon_service_; 208 history::HistoryService* const history_service_; 209 210 // Task tracker for loading favicons. 211 base::CancelableTaskTracker cancelable_task_tracker_; 212 213 // Our actual cached favicon data. Owns the favicons. 214 FaviconMap synced_favicons_; 215 216 // An LRU ordering of the favicons comprising |synced_favicons_| (oldest to 217 // newest). 218 RecencySet recent_favicons_; 219 220 // Pending favicon loads, map of page url to task id. 221 std::map<GURL, base::CancelableTaskTracker::TaskId> page_task_map_; 222 223 // Map of page url to favicon url. 224 std::map<GURL, GURL> page_favicon_map_; 225 226 // TODO(zea): consider creating a favicon handler here for fetching unsynced 227 // favicons from the web. 228 229 std::unique_ptr<syncer::SyncChangeProcessor> favicon_images_sync_processor_; 230 std::unique_ptr<syncer::SyncChangeProcessor> favicon_tracking_sync_processor_; 231 232 // Maximum number of favicons to sync. 0 means no limit. 233 const size_t max_sync_favicon_limit_; 234 235 // A vector is needed to support concurrent calls to WaitUntilReadyToSync() 236 // because this class powers two datatypes. 237 std::vector<base::OnceClosure> wait_until_ready_to_sync_cb_; 238 239 ScopedObserver<history::HistoryService, history::HistoryServiceObserver> 240 history_service_observer_{this}; 241 242 // Weak pointer factory for favicon loads. 243 base::WeakPtrFactory<FaviconCache> weak_ptr_factory_{this}; 244 245 DISALLOW_COPY_AND_ASSIGN(FaviconCache); 246 }; 247 248 } // namespace sync_sessions 249 250 #endif // COMPONENTS_SYNC_SESSIONS_FAVICON_CACHE_H_ 251