hints_manager.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. // Copyright 2021 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. #ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_HINTS_MANAGER_H_
  5. #define COMPONENTS_OPTIMIZATION_GUIDE_CORE_HINTS_MANAGER_H_
  6. #include <memory>
  7. #include <string>
  8. #include <vector>
  9. #include "base/callback_forward.h"
  10. #include "base/containers/flat_map.h"
  11. #include "base/containers/flat_set.h"
  12. #include "base/containers/lru_cache.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/memory/scoped_refptr.h"
  15. #include "base/memory/weak_ptr.h"
  16. #include "base/task/sequenced_task_runner.h"
  17. #include "base/time/clock.h"
  18. #include "base/timer/timer.h"
  19. #include "components/optimization_guide/core/hints_component_info.h"
  20. #include "components/optimization_guide/core/hints_fetcher.h"
  21. #include "components/optimization_guide/core/optimization_guide_decision.h"
  22. #include "components/optimization_guide/core/optimization_hints_component_observer.h"
  23. #include "components/optimization_guide/core/push_notification_manager.h"
  24. #include "components/optimization_guide/proto/hints.pb.h"
  25. #include "third_party/abseil-cpp/absl/types/optional.h"
  26. class OptimizationGuideLogger;
  27. class OptimizationGuideNavigationData;
  28. class OptimizationGuideTestAppInterfaceWrapper;
  29. class PrefService;
  30. namespace network {
  31. class SharedURLLoaderFactory;
  32. } // namespace network
  33. namespace optimization_guide {
  34. class HintCache;
  35. class HintsFetcherFactory;
  36. class OptimizationFilter;
  37. class OptimizationGuideStore;
  38. class OptimizationMetadata;
  39. enum class OptimizationTypeDecision;
  40. class StoreUpdateData;
  41. class TabUrlProvider;
  42. class TopHostProvider;
  43. class HintsManager : public OptimizationHintsComponentObserver,
  44. public PushNotificationManager::Delegate {
  45. public:
  46. HintsManager(
  47. bool is_off_the_record,
  48. const std::string& application_locale,
  49. PrefService* pref_service,
  50. base::WeakPtr<OptimizationGuideStore> hint_store,
  51. TopHostProvider* top_host_provider,
  52. TabUrlProvider* tab_url_provider,
  53. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  54. std::unique_ptr<PushNotificationManager> push_notification_manager,
  55. OptimizationGuideLogger* optimization_guide_logger);
  56. ~HintsManager() override;
  57. HintsManager(const HintsManager&) = delete;
  58. HintsManager& operator=(const HintsManager&) = delete;
  59. // Unhooks the observer to |optimization_guide_service_|.
  60. void Shutdown();
  61. // Returns the OptimizationGuideDecision from |optimization_type_decision|.
  62. static OptimizationGuideDecision
  63. GetOptimizationGuideDecisionFromOptimizationTypeDecision(
  64. OptimizationTypeDecision optimization_type_decision);
  65. // OptimizationHintsComponentObserver implementation:
  66. void OnHintsComponentAvailable(const HintsComponentInfo& info) override;
  67. // |next_update_closure| is called the next time OnHintsComponentAvailable()
  68. // is called and the corresponding hints have been updated.
  69. void ListenForNextUpdateForTesting(base::OnceClosure next_update_closure);
  70. // Registers the optimization types that have the potential for hints to be
  71. // called by consumers of the Optimization Guide.
  72. void RegisterOptimizationTypes(
  73. const std::vector<proto::OptimizationType>& optimization_types);
  74. // Returns the optimization types that are registered.
  75. base::flat_set<proto::OptimizationType> registered_optimization_types()
  76. const {
  77. return registered_optimization_types_;
  78. }
  79. // Returns whether there is an optimization allowlist loaded for
  80. // |optimization_type|.
  81. bool HasLoadedOptimizationAllowlist(
  82. proto::OptimizationType optimization_type);
  83. // Returns whether there is an optimization blocklist loaded for
  84. // |optimization_type|.
  85. bool HasLoadedOptimizationBlocklist(
  86. proto::OptimizationType optimization_type);
  87. // Returns the OptimizationTypeDecision based on the given parameters.
  88. // |optimization_metadata| will be populated, if applicable.
  89. OptimizationTypeDecision CanApplyOptimization(
  90. const GURL& navigation_url,
  91. proto::OptimizationType optimization_type,
  92. OptimizationMetadata* optimization_metadata);
  93. // Invokes |callback| with the decision for the URL contained in |url| and
  94. // |optimization_type|, when sufficient information has been collected to
  95. // make the decision.
  96. virtual void CanApplyOptimization(
  97. const GURL& url,
  98. optimization_guide::proto::OptimizationType optimization_type,
  99. optimization_guide::OptimizationGuideDecisionCallback callback);
  100. // Invokes |callback| with the decision for |navigation_url| and
  101. // |optimization_type|, when sufficient information has been collected by
  102. // |this| to make the decision. Virtual for testing.
  103. virtual void CanApplyOptimizationAsync(
  104. const GURL& navigation_url,
  105. proto::OptimizationType optimization_type,
  106. OptimizationGuideDecisionCallback callback);
  107. // Invokes |callback| with the decision for all types contained in
  108. // |optimization_types| for each URL contained in |urls|, when sufficient
  109. // information has been collected to make decisions. If information is not
  110. // available for all URLs, the remote Optimization Guide Service will be
  111. // contacted to fetch information for those URLs using |request_context|.
  112. void CanApplyOptimizationOnDemand(
  113. const std::vector<GURL>& urls,
  114. const base::flat_set<proto::OptimizationType>& optimization_types,
  115. proto::RequestContext request_context,
  116. OnDemandOptimizationGuideDecisionRepeatingCallback callback);
  117. // Clears all fetched hints from |hint_cache_|.
  118. void ClearFetchedHints();
  119. // Clears the host-keyed fetched hints from |hint_cache_|, both the persisted
  120. // and in memory ones.
  121. void ClearHostKeyedHints();
  122. // Overrides |hints_fetcher_factory| for testing.
  123. void SetHintsFetcherFactoryForTesting(
  124. std::unique_ptr<HintsFetcherFactory> hints_fetcher_factory);
  125. // Overrides |clock_| for testing.
  126. void SetClockForTesting(const base::Clock* clock);
  127. // Notifies |this| that a navigation with |navigation_data| started.
  128. // |callback| is run when the request has finished regardless of whether there
  129. // was actually a hint for that load or not. The callback can be used as a
  130. // signal for tests.
  131. void OnNavigationStartOrRedirect(
  132. OptimizationGuideNavigationData* navigation_data,
  133. base::OnceClosure callback);
  134. // Notifies |this| that a navigation with redirect chain
  135. // |navigation_redirect_chain| has finished.
  136. void OnNavigationFinish(const std::vector<GURL>& navigation_redirect_chain);
  137. // Notifies |this| that deferred startup has occurred. This enables |this|
  138. // to execute background tasks while minimizing the risk of regressing
  139. // metrics such as jank.
  140. void OnDeferredStartup();
  141. // Fetch the hints for the given URLs with the provided |request_context|.
  142. void FetchHintsForURLs(const std::vector<GURL>& target_urls,
  143. proto::RequestContext request_context);
  144. // PushNotificationManager::Delegate:
  145. void RemoveFetchedEntriesByHintKeys(
  146. base::OnceClosure on_success,
  147. proto::KeyRepresentation key_representation,
  148. const base::flat_set<std::string>& hint_keys) override;
  149. // Returns true if |this| is allowed to fetch hints at the navigation time for
  150. // |url|.
  151. bool IsAllowedToFetchNavigationHints(const GURL& url);
  152. // Returns the hint cache for |this|.
  153. HintCache* hint_cache();
  154. // Returns the persistent store for |this|.
  155. base::WeakPtr<OptimizationGuideStore> hint_store();
  156. // Returns the push notification manager for |this|. May be nullptr;
  157. PushNotificationManager* push_notification_manager();
  158. // Add hints to the cache with the provided metadata. For testing only.
  159. void AddHintForTesting(const GURL& url,
  160. proto::OptimizationType optimization_type,
  161. const absl::optional<OptimizationMetadata>& metadata);
  162. private:
  163. friend class ::OptimizationGuideTestAppInterfaceWrapper;
  164. friend class HintsManagerTest;
  165. // Processes the optimization filters contained in the hints component.
  166. void ProcessOptimizationFilters(
  167. const google::protobuf::RepeatedPtrField<proto::OptimizationFilter>&
  168. allowlist_optimization_filters,
  169. const google::protobuf::RepeatedPtrField<proto::OptimizationFilter>&
  170. blocklist_optimization_filters);
  171. // Process a set of optimization filters.
  172. //
  173. // |is_allowlist| will be used to ensure that the filters are either uses as
  174. // allowlists or blocklists.
  175. void ProcessOptimizationFilterSet(const google::protobuf::RepeatedPtrField<
  176. proto::OptimizationFilter>& filters,
  177. bool is_allowlist);
  178. // Callback run after the hint cache is fully initialized. At this point,
  179. // the HintsManager is ready to process hints.
  180. void OnHintCacheInitialized();
  181. // Updates the cache with the latest hints sent by the Component Updater.
  182. void UpdateComponentHints(base::OnceClosure update_closure,
  183. std::unique_ptr<StoreUpdateData> update_data,
  184. std::unique_ptr<proto::Configuration> config);
  185. // Called when the hints have been fully updated with the latest hints from
  186. // the Component Updater. This is used as a signal during tests.
  187. void OnComponentHintsUpdated(base::OnceClosure update_closure,
  188. bool hints_updated);
  189. // Initiates fetching of hints - either immediately over via a timer.
  190. void InitiateHintsFetchScheduling();
  191. // Returns the URLs that are currently in the active tab model that do not
  192. // have a hint available in |hint_cache_|.
  193. const std::vector<GURL> GetActiveTabURLsToRefresh();
  194. // Schedules |active_tabs_hints_fetch_timer_| to fire based on the last time a
  195. // fetch attempt was made.
  196. void ScheduleActiveTabsHintsFetch();
  197. // Called to make a request to fetch hints from the remote Optimization Guide
  198. // Service. Used to fetch hints for origins frequently visited by the user and
  199. // URLs open in the active tab model.
  200. void FetchHintsForActiveTabs();
  201. // Called when the hints for active tabs have been fetched from the remote
  202. // Optimization Guide Service and are ready for parsing. This is used when
  203. // fetching hints in batch mode.
  204. void OnHintsForActiveTabsFetched(
  205. const base::flat_set<std::string>& hosts_fetched,
  206. const base::flat_set<GURL>& urls_fetched,
  207. absl::optional<std::unique_ptr<proto::GetHintsResponse>>
  208. get_hints_response);
  209. // Called when the batch update hints have been fetched from the remote
  210. // Optimization Guide Service and are ready for parsing. This is used when
  211. // fetching hints on demand or from SRP.
  212. void OnBatchUpdateHintsFetched(
  213. int32_t request_id,
  214. proto::RequestContext request_context,
  215. const base::flat_set<std::string>& hosts_fetched,
  216. const base::flat_set<GURL>& urls_fetched,
  217. const base::flat_set<GURL>& urls_for_callback,
  218. const base::flat_set<proto::OptimizationType>& optimization_types,
  219. OnDemandOptimizationGuideDecisionRepeatingCallback callback,
  220. absl::optional<std::unique_ptr<proto::GetHintsResponse>>
  221. get_hints_response);
  222. // Called when information is ready such that we can invoke any callbacks that
  223. // require returning decisions to consumer features.
  224. //
  225. // TODO(crbug/1279536): Clean this up when we clean up some of the existing
  226. // interfaces.
  227. void OnBatchUpdateHintsStored(
  228. const base::flat_set<GURL>& urls_fetched,
  229. const base::flat_set<proto::OptimizationType>& optimization_types,
  230. OnDemandOptimizationGuideDecisionRepeatingCallback callback);
  231. // Creates a hints fetcher and stores it in |batch_update_hints_fetchers_| and
  232. // returns the request ID associated with the fetch. It is expected to call
  233. // `CleanUpBatchUpdateHintsFetcher` with the returned request ID once the
  234. // fetch has finished.
  235. std::pair<int32_t, HintsFetcher*> CreateAndTrackBatchUpdateHintsFetcher();
  236. // Called to inform |this| that the batch fetcher with |request_id| is no
  237. // longer needed removes the request from |batch_update_hints_fetchers_|
  238. void CleanUpBatchUpdateHintsFetcher(int32_t request_id);
  239. // Returns decisions for |url| and |optimization_types| based on what's cached
  240. // locally.
  241. base::flat_map<proto::OptimizationType, OptimizationGuideDecisionWithMetadata>
  242. GetDecisionsWithCachedInformationForURLAndOptimizationTypes(
  243. const GURL& url,
  244. const base::flat_set<proto::OptimizationType>& optimization_types);
  245. // Invokes |callback| for |url| and |optimization_types| based on what is
  246. // cached on device.
  247. void InvokeOnDemandHintsCallbackForURL(
  248. const GURL& url,
  249. const base::flat_set<proto::OptimizationType>& optimization_types,
  250. OnDemandOptimizationGuideDecisionRepeatingCallback callback);
  251. // Called when the hints for a navigation have been fetched from the remote
  252. // Optimization Guide Service and are ready for parsing. This is used when
  253. // fetching hints in real-time. |navigation_url| is the URL associated with
  254. // the navigation handle that initiated the fetch.
  255. // |page_navigation_urls_requested| contains the URLs that were requested by
  256. // |this| to be fetched. |page_navigation_hosts_requested| contains the hosts
  257. // that were requested by |this| to be fetched.
  258. void OnPageNavigationHintsFetched(
  259. base::WeakPtr<OptimizationGuideNavigationData> navigation_data_weak_ptr,
  260. const absl::optional<GURL>& navigation_url,
  261. const base::flat_set<GURL>& page_navigation_urls_requested,
  262. const base::flat_set<std::string>& page_navigation_hosts_requested,
  263. absl::optional<std::unique_ptr<proto::GetHintsResponse>>
  264. get_hints_response);
  265. // Called when the fetched hints have been stored in |hint_cache| and are
  266. // ready to be used. This is used when hints were fetched in batch mode.
  267. void OnFetchedActiveTabsHintsStored();
  268. // Called when the fetched hints have been stored in |hint_cache| and are
  269. // ready to be used. This is used when hints were fetched in real-time.
  270. // |navigation_url| is the URL associated with the navigation handle that
  271. // initiated the fetch. |page_navigation_hosts_requested| contains the hosts
  272. // whose hints should be loaded into memory when invoked.
  273. void OnFetchedPageNavigationHintsStored(
  274. base::WeakPtr<OptimizationGuideNavigationData> navigation_data_weak_ptr,
  275. const absl::optional<GURL>& navigation_url,
  276. const base::flat_set<std::string>& page_navigation_hosts_requested);
  277. // Returns true if there is a fetch currently in-flight for |navigation_url|.
  278. bool IsHintBeingFetchedForNavigation(const GURL& navigation_url);
  279. // Cleans up the hints fetcher for |navigation_url|, if applicable.
  280. void CleanUpFetcherForNavigation(const GURL& navigation_url);
  281. // Returns the time when a hints fetch request was last attempted.
  282. base::Time GetLastHintsFetchAttemptTime() const;
  283. // Sets the time when a hints fetch was last attempted to |last_attempt_time|.
  284. void SetLastHintsFetchAttemptTime(base::Time last_attempt_time);
  285. // Called when the request to load a hint has completed.
  286. void OnHintLoaded(base::OnceClosure callback,
  287. const proto::Hint* loaded_hint) const;
  288. // Loads the hint if available for navigation to |url|.
  289. // |callback| is run when the request has finished regardless of whether there
  290. // was actually a hint for that load or not. The callback can be used as a
  291. // signal for tests.
  292. void LoadHintForURL(const GURL& url, base::OnceClosure callback);
  293. // Loads the hint for |host| if available.
  294. // |callback| is run when the request has finished regardless of whether there
  295. // was actually a hint for that |host| or not. The callback can be used as a
  296. // signal for tests.
  297. void LoadHintForHost(const std::string& host, base::OnceClosure callback);
  298. // Returns whether there is an optimization type to fetch for. Will return
  299. // false if no optimization types are registered or if all registered
  300. // optimization types are covered by optimization filters.
  301. bool HasOptimizationTypeToFetchFor();
  302. // Creates a hints fetch for navigation represented by |navigation_data|, if
  303. // it is allowed. The fetch will include the host and URL of the
  304. // |navigation_data| if the associated hints for each are not already in the
  305. // cache.
  306. void MaybeFetchHintsForNavigation(
  307. OptimizationGuideNavigationData* navigation_data);
  308. // If an entry for |navigation_url| is contained in |registered_callbacks_|,
  309. // it will load the hint for |navigation_url|'s host and upon completion, will
  310. // invoke the registered callbacks for |navigation_url|.
  311. void PrepareToInvokeRegisteredCallbacks(const GURL& navigation_url);
  312. // Invokes the registered callbacks for |navigation_url|, if applicable.
  313. void OnReadyToInvokeRegisteredCallbacks(const GURL& navigation_url);
  314. // Whether all information was available to make a decision for
  315. // |navigation_url| and |optimization type}.
  316. bool HasAllInformationForDecisionAvailable(
  317. const GURL& navigation_url,
  318. proto::OptimizationType optimization_type);
  319. HintsFetcherFactory* GetHintsFetcherFactory();
  320. // Returns the number of batch update hints fetches initiated.
  321. //
  322. // Exposed here for testing.
  323. int32_t num_batch_update_hints_fetches_initiated() const {
  324. return batch_update_hints_fetcher_request_id_;
  325. }
  326. // Returns the current active tabs batch update hints fetcher.
  327. //
  328. // Exposed here for testing.
  329. HintsFetcher* active_tabs_batch_update_hints_fetcher() const {
  330. return active_tabs_batch_update_hints_fetcher_.get();
  331. }
  332. // The information of the latest component delivered by
  333. // |optimization_guide_service_|.
  334. absl::optional<HintsComponentInfo> hints_component_info_;
  335. // The component version that failed to process in the last session, if
  336. // applicable.
  337. const absl::optional<base::Version> failed_component_version_;
  338. // The version of the component that is currently being processed.
  339. absl::optional<base::Version> currently_processing_component_version_;
  340. // The set of optimization types that have been registered with the hints
  341. // manager.
  342. //
  343. // Should only be read and modified on the UI thread.
  344. base::flat_set<proto::OptimizationType> registered_optimization_types_;
  345. // The set of optimization types that the component specified by
  346. // |component_info_| has optimization filters for.
  347. base::flat_set<proto::OptimizationType> optimization_types_with_filter_;
  348. // A map from optimization type to the host filter that holds the allowlist
  349. // for that type.
  350. base::flat_map<proto::OptimizationType, std::unique_ptr<OptimizationFilter>>
  351. allowlist_optimization_filters_;
  352. // A map from optimization type to the host filter that holds the blocklist
  353. // for that type.
  354. base::flat_map<proto::OptimizationType, std::unique_ptr<OptimizationFilter>>
  355. blocklist_optimization_filters_;
  356. // A map from URL to a map of callbacks keyed by their optimization type.
  357. base::flat_map<GURL,
  358. base::flat_map<proto::OptimizationType,
  359. std::vector<OptimizationGuideDecisionCallback>>>
  360. registered_callbacks_;
  361. // Whether |this| was created for an off the record profile.
  362. const bool is_off_the_record_;
  363. // The current applcation locale of Chrome.
  364. const std::string application_locale_;
  365. // A reference to the PrefService for this profile. Not owned.
  366. raw_ptr<PrefService> pref_service_ = nullptr;
  367. // The hint cache that holds both hints received from the component and
  368. // fetched from the remote Optimization Guide Service.
  369. std::unique_ptr<HintCache> hint_cache_;
  370. // The fetcher that handles making requests for hints for active tabs from
  371. // the remote Optimization Guide Service.
  372. std::unique_ptr<HintsFetcher> active_tabs_batch_update_hints_fetcher_;
  373. // A map from request ID to the fetcher that handles making requests for hints
  374. // for multiple hosts from the remote Optimization Guide Service.
  375. base::LRUCache<int32_t, std::unique_ptr<HintsFetcher>>
  376. batch_update_hints_fetchers_;
  377. int32_t batch_update_hints_fetcher_request_id_ = 0;
  378. // A cache keyed by navigation URL to the fetcher making a request for a hint
  379. // for that URL and/or host to the remote Optimization Guide Service that
  380. // keeps track of when an entry has been placed in the cache.
  381. base::LRUCache<GURL, std::unique_ptr<HintsFetcher>>
  382. page_navigation_hints_fetchers_;
  383. // The factory used to create hints fetchers. It is mostly used to create
  384. // new fetchers for use under the page navigation context, but will also be
  385. // used to create the initial fetcher for the batch update context.
  386. std::unique_ptr<HintsFetcherFactory> hints_fetcher_factory_;
  387. // The top host provider that can be queried. Not owned.
  388. raw_ptr<TopHostProvider> top_host_provider_ = nullptr;
  389. // The tab URL provider that can be queried. Not owned.
  390. raw_ptr<TabUrlProvider> tab_url_provider_ = nullptr;
  391. // The timer used to schedule fetching hints from the remote Optimization
  392. // Guide Service.
  393. base::OneShotTimer active_tabs_hints_fetch_timer_;
  394. // The class that handles push notification processing and informs |this| of
  395. // what to do through the implemented Delegate above.
  396. std::unique_ptr<PushNotificationManager> push_notification_manager_;
  397. // The logger that plumbs the debug logs to the optimization guide
  398. // internals page. Not owned. Guaranteed to outlive |this|, since the logger
  399. // and |this| are owned by the optimization guide keyed service.
  400. raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
  401. // The clock used to schedule fetching from the remote Optimization Guide
  402. // Service.
  403. raw_ptr<const base::Clock> clock_;
  404. // Whether fetched hints should be cleared when the store is initialized
  405. // because a new optimization type was registered.
  406. bool should_clear_hints_for_new_type_ = false;
  407. // Used in testing to subscribe to an update event in this class.
  408. base::OnceClosure next_update_closure_;
  409. // Background thread where hints processing should be performed.
  410. //
  411. // Warning: This must be the last object, so it is destroyed (and flushed)
  412. // first. This will prevent use-after-free issues where the background thread
  413. // would access other member variables after they have been destroyed.
  414. scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
  415. SEQUENCE_CHECKER(sequence_checker_);
  416. // Used to get |weak_ptr_| to self.
  417. base::WeakPtrFactory<HintsManager> weak_ptr_factory_{this};
  418. };
  419. } // namespace optimization_guide
  420. #endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_HINTS_MANAGER_H_