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