[omnibox] Add feature-slicing to omnibox logs.

Adds a OmniboxTriggeredFeatureService, accessible through
AutocompleteProviderClient, that registers features as they're triggered
which are copied to the metrics logs once an omnibox session ends.

Change-Id: I311fc20b185dd58b1acc6174321e47a38f794c67
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2437743
Commit-Queue: manuk hovanesian <[email protected]>
Reviewed-by: Moe Ahmadi <[email protected]>
Reviewed-by: David Roger <[email protected]>
Reviewed-by: Mark Pearson <[email protected]>
Cr-Commit-Position: refs/heads/master@{#823683}
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index 08a46a8..d45d791 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -329,7 +329,7 @@
       now - autocomplete_controller_->last_time_default_match_changed(),
       autocomplete_controller_->result());
   log.is_query_started_from_tile = is_query_started_from_tiles_;
-  autocomplete_controller_->AddProvidersInfo(&log.providers_info);
+  autocomplete_controller_->AddProviderAndTriggeringLogs(&log);
 
   OmniboxEventGlobalTracker::GetInstance()->OnURLOpened(&log);
 
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
index aa4c7807..fff6990 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -180,7 +180,9 @@
           unified_consent::UrlKeyedDataCollectionConsentHelper::
               NewPersonalizedDataCollectionConsentHelper(
                   ProfileSyncServiceFactory::GetForProfile(profile_))),
-      storage_partition_(nullptr) {
+      storage_partition_(nullptr),
+      omnibox_triggered_feature_service_(
+          std::make_unique<OmniboxTriggeredFeatureService>()) {
   if (OmniboxFieldTrial::IsPedalSuggestionsEnabled())
     pedal_provider_ = std::make_unique<OmniboxPedalProvider>(*this);
 }
@@ -250,12 +252,6 @@
                                                         create_if_necessary);
 }
 
-query_tiles::TileService*
-ChromeAutocompleteProviderClient::GetQueryTileService() const {
-  ProfileKey* profile_key = profile_->GetProfileKey();
-  return query_tiles::TileServiceFactory::GetForKey(profile_key);
-}
-
 DocumentSuggestionsService*
 ChromeAutocompleteProviderClient::GetDocumentSuggestionsService(
     bool create_if_necessary) const {
@@ -344,6 +340,17 @@
   return g_browser_process->component_updater();
 }
 
+query_tiles::TileService*
+ChromeAutocompleteProviderClient::GetQueryTileService() const {
+  ProfileKey* profile_key = profile_->GetProfileKey();
+  return query_tiles::TileServiceFactory::GetForKey(profile_key);
+}
+
+OmniboxTriggeredFeatureService*
+ChromeAutocompleteProviderClient::GetOmniboxTriggeredFeatureService() const {
+  return omnibox_triggered_feature_service_.get();
+}
+
 bool ChromeAutocompleteProviderClient::IsOffTheRecord() const {
   return profile_->IsOffTheRecord();
 }
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
index 85b4082..fcb6fae 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -62,6 +62,8 @@
   component_updater::ComponentUpdateService* GetComponentUpdateService()
       override;
   query_tiles::TileService* GetQueryTileService() const override;
+  OmniboxTriggeredFeatureService* GetOmniboxTriggeredFeatureService()
+      const override;
 
   bool IsOffTheRecord() const override;
   bool SearchSuggestEnabled() const override;
@@ -118,6 +120,9 @@
   // Injectable storage partitiion, used for testing.
   content::StoragePartition* storage_partition_;
 
+  std::unique_ptr<OmniboxTriggeredFeatureService>
+      omnibox_triggered_feature_service_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeAutocompleteProviderClient);
 };
 
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index be2d4e5..2153c4a 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -914,7 +914,7 @@
       /*elapsed_time_since_last_change_to_default_match=*/
       elapsed_time_since_last_change_to_default_match,
       /*result=*/autocomplete_controller_->result());
-  autocomplete_controller_->AddProvidersInfo(&log.providers_info);
+  autocomplete_controller_->AddProviderAndTriggeringLogs(&log);
 
   OmniboxEventGlobalTracker::GetInstance()->OnURLOpened(&log);
 
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index cf1f33ed..06138c3 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -1127,7 +1127,7 @@
       /*elapsed_time_since_last_change_to_default_match=*/
       elapsed_time_since_last_change_to_default_match,
       /*result=*/autocomplete_controller_->result());
-  autocomplete_controller_->AddProvidersInfo(&log.providers_info);
+  autocomplete_controller_->AddProviderAndTriggeringLogs(&log);
 
   OmniboxEventGlobalTracker::GetInstance()->OnURLOpened(&log);
 
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index f6528b2..701a48d 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -167,6 +167,8 @@
     "omnibox_popup_view.h",
     "omnibox_prefs.cc",
     "omnibox_prefs.h",
+    "omnibox_triggered_feature_service.cc",
+    "omnibox_triggered_feature_service.h",
     "omnibox_view.cc",
     "omnibox_view.h",
     "on_device_head_model.cc",
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index f9ec488..ca4d188 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -544,12 +544,12 @@
     UpdateResult(false, false);
 }
 
-void AutocompleteController::AddProvidersInfo(
-    ProvidersInfo* provider_info) const {
-  provider_info->clear();
-  for (auto i(providers_.begin()); i != providers_.end(); ++i) {
+void AutocompleteController::AddProviderAndTriggeringLogs(
+    OmniboxLog* logs) const {
+  logs->providers_info.clear();
+  for (const auto& provider : providers_) {
     // Add per-provider info, if any.
-    (*i)->AddProviderInfo(provider_info);
+    provider->AddProviderInfo(&logs->providers_info);
 
     // This is also a good place to put code to add info that you want to
     // add for every provider.
@@ -559,16 +559,22 @@
     // OmniboxPedalProvider is not a "true" AutocompleteProvider and isn't
     // included in the list of providers, though needs to report information for
     // its field trial.  Manually call AddProviderInfo for pedals.
-    provider_client_->GetPedalProvider()->AddProviderInfo(provider_info);
+    provider_client_->GetPedalProvider()->AddProviderInfo(
+        &logs->providers_info);
   }
+
+  // Add any features that have been triggered.
+  // |GetOmniboxTriggeredFeatureService()| can be null in tests.
+  if (provider_client_->GetOmniboxTriggeredFeatureService())
+    provider_client_->GetOmniboxTriggeredFeatureService()->RecordToLogs(
+        &logs->feature_triggered_in_session);
 }
 
 void AutocompleteController::ResetSession() {
   search_service_worker_signal_sent_ = false;
 
-  for (Providers::const_iterator i(providers_.begin()); i != providers_.end();
-       ++i) {
-    (*i)->ResetSession();
+  for (const auto& provider : providers_) {
+    provider->ResetSession();
   }
 
   if (OmniboxFieldTrial::IsPedalSuggestionsEnabled()) {
@@ -576,6 +582,10 @@
     // a "true" AutocompleteProvider.  Manually call ResetSession() for pedals.
     provider_client_->GetPedalProvider()->ResetSession();
   }
+
+  // |GetOmniboxTriggeredFeatureService()| can be null in tests.
+  if (provider_client_->GetOmniboxTriggeredFeatureService())
+    provider_client_->GetOmniboxTriggeredFeatureService()->ResetSession();
 }
 
 void AutocompleteController::UpdateMatchDestinationURLWithQueryFormulationTime(
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 7459a65..7aada34 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -23,6 +23,7 @@
 #include "components/omnibox/browser/autocomplete_provider_client.h"
 #include "components/omnibox/browser/autocomplete_provider_listener.h"
 #include "components/omnibox/browser/autocomplete_result.h"
+#include "components/omnibox/browser/omnibox_log.h"
 
 class ClipboardProvider;
 class DocumentProvider;
@@ -127,12 +128,10 @@
   void OnProviderUpdate(bool updated_matches) override;
 
   // Called when an omnibox event log entry is generated.
-  // Populates provider_info with diagnostic information about the status
-  // of various providers.  In turn, calls
-  // AutocompleteProvider::AddProviderInfo() so each provider can add
-  // provider-specific information, information we want to log for a particular
-  // provider but not others.
-  void AddProvidersInfo(ProvidersInfo* provider_info) const;
+  // Populates |log.provider_info| with diagnostic information about the status
+  // of various providers and |log.feature_triggered_in_session| with triggered
+  // features.
+  void AddProviderAndTriggeringLogs(OmniboxLog* logs) const;
 
   // Called when a new omnibox session starts.
   // We start a new session when the user first begins modifying the omnibox
diff --git a/components/omnibox/browser/autocomplete_provider_client.h b/components/omnibox/browser/autocomplete_provider_client.h
index 3b1db1a..bee7622 100644
--- a/components/omnibox/browser/autocomplete_provider_client.h
+++ b/components/omnibox/browser/autocomplete_provider_client.h
@@ -14,6 +14,7 @@
 #include "components/history/core/browser/keyword_id.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/omnibox/browser/keyword_extensions_delegate.h"
+#include "components/omnibox/browser/omnibox_triggered_feature_service.h"
 #include "components/omnibox/browser/shortcuts_backend.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 
@@ -79,6 +80,8 @@
   virtual std::unique_ptr<KeywordExtensionsDelegate>
   GetKeywordExtensionsDelegate(KeywordProvider* keyword_provider) = 0;
   virtual query_tiles::TileService* GetQueryTileService() const = 0;
+  virtual OmniboxTriggeredFeatureService* GetOmniboxTriggeredFeatureService()
+      const = 0;
 
   // The value to use for Accept-Languages HTTP header when making an HTTP
   // request.
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.h b/components/omnibox/browser/mock_autocomplete_provider_client.h
index 437e235..ab25d94 100644
--- a/components/omnibox/browser/mock_autocomplete_provider_client.h
+++ b/components/omnibox/browser/mock_autocomplete_provider_client.h
@@ -83,6 +83,10 @@
   query_tiles::TileService* GetQueryTileService() const override {
     return nullptr;
   }
+  OmniboxTriggeredFeatureService* GetOmniboxTriggeredFeatureService()
+      const override {
+    return nullptr;
+  }
 
   component_updater::ComponentUpdateService* GetComponentUpdateService()
       override {
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index 0facb49..16a7ad1 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -846,7 +846,7 @@
     // tab, we don't know the tab ID yet.)
     log.tab_id = client_->GetSessionID();
   }
-  autocomplete_controller()->AddProvidersInfo(&log.providers_info);
+  autocomplete_controller()->AddProviderAndTriggeringLogs(&log);
   client_->OnURLOpenedFromOmnibox(&log);
   OmniboxEventGlobalTracker::GetInstance()->OnURLOpened(&log);
   LOCAL_HISTOGRAM_BOOLEAN("Omnibox.EventCount", true);
diff --git a/components/omnibox/browser/omnibox_log.h b/components/omnibox/browser/omnibox_log.h
index 2a916786b..5a18a09b 100644
--- a/components/omnibox/browser/omnibox_log.h
+++ b/components/omnibox/browser/omnibox_log.h
@@ -10,6 +10,7 @@
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "components/omnibox/browser/autocomplete_provider.h"
+#include "components/omnibox/browser/omnibox_triggered_feature_service.h"
 #include "components/sessions/core/session_id.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
@@ -107,10 +108,14 @@
   const AutocompleteResult& result;
 
   // Diagnostic information from providers.  See
-  // AutocompleteController::AddProvidersInfo() and
-  // AutocompleteProvider::AddProviderInfo() above.
+  // AutocompleteController::AddProviderAndTriggeringLogs() and
+  // AutocompleteProvider::AddProviderInfo().
   ProvidersInfo providers_info;
 
+  // The features that have been triggered (see
+  // OmniboxTriggeredFeatureService::Feature).
+  OmniboxTriggeredFeatureService::Features feature_triggered_in_session;
+
   // Whether the omnibox input is a search query that is started
   // by clicking on a image tile. Currently only used on Android.
   bool is_query_started_from_tile = false;
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc
index c64f268..e88b1d2 100644
--- a/components/omnibox/browser/omnibox_metrics_provider.cc
+++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -119,4 +119,8 @@
     omnibox_event->set_keyword_mode_entry_method(log.keyword_mode_entry_method);
   if (log.is_query_started_from_tile)
     omnibox_event->set_is_query_started_from_tile(true);
+  for (auto feature : log.feature_triggered_in_session) {
+    omnibox_event->add_feature_triggered_in_session(
+        static_cast<size_t>(feature));
+  }
 }
diff --git a/components/omnibox/browser/omnibox_triggered_feature_service.cc b/components/omnibox/browser/omnibox_triggered_feature_service.cc
new file mode 100644
index 0000000..455106b
--- /dev/null
+++ b/components/omnibox/browser/omnibox_triggered_feature_service.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "omnibox_triggered_feature_service.h"
+
+OmniboxTriggeredFeatureService::OmniboxTriggeredFeatureService() = default;
+OmniboxTriggeredFeatureService::~OmniboxTriggeredFeatureService() = default;
+
+void OmniboxTriggeredFeatureService::RecordToLogs(
+    Features* feature_triggered_in_session) const {
+  *feature_triggered_in_session = features_;
+}
+
+void OmniboxTriggeredFeatureService::TriggerFeature(Feature feature) {
+  features_.insert(feature);
+}
+
+void OmniboxTriggeredFeatureService::ResetSession() {
+  features_.clear();
+}
diff --git a/components/omnibox/browser/omnibox_triggered_feature_service.h b/components/omnibox/browser/omnibox_triggered_feature_service.h
new file mode 100644
index 0000000..0b9c246
--- /dev/null
+++ b/components/omnibox/browser/omnibox_triggered_feature_service.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_TRIGGERED_FEATURE_SERVICE_H_
+#define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_TRIGGERED_FEATURE_SERVICE_H_
+
+#include <set>
+#include <vector>
+
+// Tracks the features that trigger during an omnibox session and records them
+// to the logs. This is used for counterfactual slicing metrics by feature.
+class OmniboxTriggeredFeatureService {
+ public:
+  // The list of features used for counterfactual slicing.
+  enum class Feature {};
+  using Features = std::set<Feature>;
+
+  OmniboxTriggeredFeatureService();
+  ~OmniboxTriggeredFeatureService();
+
+  // Records |features_| for this session to |feature_triggered_in_session|.
+  void RecordToLogs(Features* feature_triggered_in_session) const;
+
+  // Invoked to indicate |feature| was triggered.
+  void TriggerFeature(Feature feature);
+
+  // Invoked when a new omnibox session starts. Clears |features_|.
+  void ResetSession();
+
+ private:
+  // The set of features triggered in the current omnibox session via
+  // |TriggerFeature()|.
+  std::set<Feature> features_;
+};
+
+#endif  // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_TRIGGERED_FEATURE_SERVICE_H_
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
index 901d8e14..a9f78f2 100644
--- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
+++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
@@ -48,6 +48,8 @@
   std::unique_ptr<KeywordExtensionsDelegate> GetKeywordExtensionsDelegate(
       KeywordProvider* keyword_provider) override;
   query_tiles::TileService* GetQueryTileService() const override;
+  OmniboxTriggeredFeatureService* GetOmniboxTriggeredFeatureService()
+      const override;
   std::string GetAcceptLanguages() const override;
   std::string GetEmbedderRepresentationOfAboutScheme() const override;
   std::vector<base::string16> GetBuiltinURLs() override;
@@ -78,6 +80,8 @@
   AutocompleteSchemeClassifierImpl scheme_classifier_;
   std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper>
       url_consent_helper_;
+  std::unique_ptr<OmniboxTriggeredFeatureService>
+      omnibox_triggered_feature_service_;
 
   DISALLOW_COPY_AND_ASSIGN(AutocompleteProviderClientImpl);
 };
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm
index d8e6db0..079f728 100644
--- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm
+++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm
@@ -45,7 +45,9 @@
       url_consent_helper_(unified_consent::UrlKeyedDataCollectionConsentHelper::
                               NewPersonalizedDataCollectionConsentHelper(
                                   ProfileSyncServiceFactory::GetForBrowserState(
-                                      browser_state_))) {}
+                                      browser_state_))),
+      omnibox_triggered_feature_service_(
+          std::make_unique<OmniboxTriggeredFeatureService>()) {}
 
 AutocompleteProviderClientImpl::~AutocompleteProviderClientImpl() {}
 
@@ -141,6 +143,11 @@
   return nullptr;
 }
 
+OmniboxTriggeredFeatureService*
+AutocompleteProviderClientImpl::GetOmniboxTriggeredFeatureService() const {
+  return omnibox_triggered_feature_service_.get();
+}
+
 std::string AutocompleteProviderClientImpl::GetAcceptLanguages() const {
   return browser_state_->GetPrefs()->GetString(
       language::prefs::kAcceptLanguages);