browsing_topics_page_load_data_tracker.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2022 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. #include "components/browsing_topics/browsing_topics_page_load_data_tracker.h"
  5. #include "components/browsing_topics/util.h"
  6. #include "components/history/content/browser/history_context_helper.h"
  7. #include "components/history/core/browser/history_service.h"
  8. #include "content/public/browser/browsing_topics_site_data_manager.h"
  9. #include "content/public/browser/navigation_entry.h"
  10. #include "content/public/browser/render_frame_host.h"
  11. #include "content/public/browser/render_process_host.h"
  12. #include "content/public/browser/storage_partition.h"
  13. #include "content/public/browser/web_contents.h"
  14. #include "services/metrics/public/cpp/metrics_utils.h"
  15. #include "services/metrics/public/cpp/ukm_builders.h"
  16. #include "services/metrics/public/cpp/ukm_recorder.h"
  17. #include "third_party/blink/public/common/features.h"
  18. #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
  19. namespace browsing_topics {
  20. // Max number of context domains to keep track of per page load to limit in-use
  21. // memory. This should also be greater than
  22. // `kBrowsingTopicsMaxNumberOfApiUsageContextDomainsToStorePerPageLoad`.
  23. constexpr int kMaxNumberOfContextDomainsToMonitor = 1000;
  24. BrowsingTopicsPageLoadDataTracker::~BrowsingTopicsPageLoadDataTracker() {
  25. if (observed_hashed_context_domains_.empty())
  26. return;
  27. // TODO(yaoxia): consider also recording metrics when the Chrome app goes into
  28. // background, in which case the destructor may never be called.
  29. ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
  30. ukm::builders::BrowsingTopics_PageLoad builder(source_id_);
  31. builder.SetTopicsRequestingContextDomainsCount(
  32. ukm::GetExponentialBucketMinForCounts1000(
  33. observed_hashed_context_domains_.size()));
  34. builder.Record(ukm_recorder->Get());
  35. }
  36. BrowsingTopicsPageLoadDataTracker::BrowsingTopicsPageLoadDataTracker(
  37. content::Page& page)
  38. : content::PageUserData<BrowsingTopicsPageLoadDataTracker>(page),
  39. hashed_main_frame_host_(HashMainFrameHostForStorage(
  40. page.GetMainDocument().GetLastCommittedOrigin().host())),
  41. source_id_(page.GetMainDocument().GetPageUkmSourceId()) {
  42. DCHECK(page.IsPrimary());
  43. // TODO(yaoxia): consider dropping the permissions policy checks. We require
  44. // that the API is used in the page, and that already implies that the
  45. // permissions policy is allowed.
  46. if ((page.GetMainDocument().IsLastCommitIPAddressPubliclyRoutable() ||
  47. base::FeatureList::IsEnabled(
  48. blink::features::kBrowsingTopicsBypassIPIsPubliclyRoutableCheck)) &&
  49. page.GetMainDocument().IsFeatureEnabled(
  50. blink::mojom::PermissionsPolicyFeature::kBrowsingTopics) &&
  51. page.GetMainDocument().IsFeatureEnabled(
  52. blink::mojom::PermissionsPolicyFeature::
  53. kBrowsingTopicsBackwardCompatible)) {
  54. eligible_to_commit_ = true;
  55. }
  56. }
  57. void BrowsingTopicsPageLoadDataTracker::OnBrowsingTopicsApiUsed(
  58. const HashedDomain& hashed_context_domain,
  59. history::HistoryService* history_service) {
  60. if (!eligible_to_commit_)
  61. return;
  62. // On the first API usage in the page, set the allowed bit in history.
  63. if (observed_hashed_context_domains_.empty()) {
  64. content::WebContents* web_contents =
  65. content::WebContents::FromRenderFrameHost(&page().GetMainDocument());
  66. history_service->SetBrowsingTopicsAllowed(
  67. history::ContextIDForWebContents(web_contents),
  68. web_contents->GetController().GetLastCommittedEntry()->GetUniqueID(),
  69. web_contents->GetLastCommittedURL());
  70. }
  71. DCHECK_LE(
  72. blink::features::
  73. kBrowsingTopicsMaxNumberOfApiUsageContextDomainsToStorePerPageLoad
  74. .Get(),
  75. kMaxNumberOfContextDomainsToMonitor);
  76. // Cap the number of context domains to keep track of per page load to limit
  77. // in-use memory.
  78. if (observed_hashed_context_domains_.size() >=
  79. kMaxNumberOfContextDomainsToMonitor) {
  80. return;
  81. }
  82. bool is_new_domain =
  83. observed_hashed_context_domains_.insert(hashed_context_domain).second;
  84. // Ignore this context if we've already added it.
  85. if (!is_new_domain)
  86. return;
  87. // Cap the number of context domains to store to disk per page load to limit
  88. // disk memory usage.
  89. if (observed_hashed_context_domains_.size() >
  90. static_cast<size_t>(
  91. blink::features::
  92. kBrowsingTopicsMaxNumberOfApiUsageContextDomainsToStorePerPageLoad
  93. .Get())) {
  94. return;
  95. }
  96. // Persist the usage now rather than at the end of the page load, as when the
  97. // app enters background, it may be killed without further notification.
  98. page()
  99. .GetMainDocument()
  100. .GetProcess()
  101. ->GetStoragePartition()
  102. ->GetBrowsingTopicsSiteDataManager()
  103. ->OnBrowsingTopicsApiUsed(hashed_main_frame_host_,
  104. {hashed_context_domain}, base::Time::Now());
  105. }
  106. PAGE_USER_DATA_KEY_IMPL(BrowsingTopicsPageLoadDataTracker);
  107. } // namespace browsing_topics