Commit 87208d64 authored by Parastoo Geranmayeh's avatar Parastoo Geranmayeh Committed by Commit Bot

[Autofill] UKM for potential Reflected Synthetic Fields.

Logs the skipping decision for hidden or representational fields.

Generally, we need to skip the hidden/representational fields, but to
support reflected synthetic fields, we don't skip them if they are of
'select' form control type.

Test added.

See go/1038546-ukm-review for UKM collection review.

Bug: 836949
Change-Id: I68c284d39a25176a008f2ad5305f5844a7b4c697
Reviewed-on: https://chromium-review.googlesource.com/1038546
Commit-Queue: Parastoo Geranmayeh <parastoog@google.com>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarRoger McFarlane <rogerm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561912}
parent 9938ef3a
...@@ -1399,10 +1399,13 @@ void AutofillManager::FillOrPreviewDataModelForm( ...@@ -1399,10 +1399,13 @@ void AutofillManager::FillOrPreviewDataModelForm(
// Don't fill hidden fields, with the exception of <select> fields, for // Don't fill hidden fields, with the exception of <select> fields, for
// the sake of filling the synthetic fields. // the sake of filling the synthetic fields.
if ((!cached_field->is_focusable || if (!cached_field->is_focusable ||
cached_field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION) && cached_field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION) {
result.fields[i].form_control_type != "select-one") { bool skip = result.fields[i].form_control_type != "select-one";
continue; form_interactions_ukm_logger_->LogHiddenRepresentationalFieldSkipDecision(
*form_structure, *cached_field, skip);
if (skip)
continue;
} }
// Don't fill previously autofilled fields except the initiating field or // Don't fill previously autofilled fields except the initiating field or
......
...@@ -635,6 +635,9 @@ class AutofillManager : public AutofillHandler, ...@@ -635,6 +635,9 @@ class AutofillManager : public AutofillHandler,
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardSubmittedFormEvents); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardSubmittedFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest,
CreditCardCheckoutFlowUserActions); CreditCardCheckoutFlowUserActions);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest,
LogHiddenRepresentationalFieldSkipDecision);
FRIEND_TEST_ALL_PREFIXES( FRIEND_TEST_ALL_PREFIXES(
AutofillMetricsTest, AutofillMetricsTest,
CreditCardSubmittedWithoutSelectingSuggestionsNoCard); CreditCardSubmittedWithoutSelectingSuggestionsNoCard);
......
...@@ -1788,6 +1788,29 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFieldType( ...@@ -1788,6 +1788,29 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFieldType(
.Record(ukm_recorder_); .Record(ukm_recorder_);
} }
void AutofillMetrics::FormInteractionsUkmLogger::
LogHiddenRepresentationalFieldSkipDecision(const FormStructure& form,
const AutofillField& field,
bool is_skipped) {
if (!CanLog())
return;
if (source_id_ == -1)
GetNewSourceID();
ukm::builders::Autofill_HiddenRepresentationalFieldSkipDecision(source_id_)
.SetFormSignature(HashFormSignature(form.form_signature()))
.SetFieldSignature(HashFieldSignature(field.GetFieldSignature()))
.SetFieldTypeGroup(static_cast<int>(field.Type().group()))
.SetFieldOverallType(static_cast<int>(field.Type().GetStorableType()))
.SetHeuristicType(static_cast<int>(field.heuristic_type()))
.SetServerType(static_cast<int>(field.server_type()))
.SetHtmlFieldType(static_cast<int>(field.html_type()))
.SetHtmlFieldMode(static_cast<int>(field.html_mode()))
.SetIsSkipped(is_skipped)
.Record(ukm_recorder_);
}
int64_t AutofillMetrics::FormTypesToBitVector( int64_t AutofillMetrics::FormTypesToBitVector(
const std::set<FormType>& form_types) { const std::set<FormType>& form_types) {
int64_t form_type_bv = 0; int64_t form_type_bv = 0;
......
...@@ -703,6 +703,12 @@ class AutofillMetrics { ...@@ -703,6 +703,12 @@ class AutofillMetrics {
const base::TimeTicks& form_parsed_timestamp, const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature); FormSignature form_signature);
// Log whether the autofill decided to skip or to fill each
// hidden/representational field.
void LogHiddenRepresentationalFieldSkipDecision(const FormStructure& form,
const AutofillField& field,
bool is_skipped);
// We initialize |url_| with the form's URL when we log the first form // We initialize |url_| with the form's URL when we log the first form
// interaction. Later, we may update |url_| with the |source_url()| for the // interaction. Later, we may update |url_| with the |source_url()| for the
// submitted form. // submitted form.
......
...@@ -67,6 +67,8 @@ using UkmSelectedMaskedServerCardType = ...@@ -67,6 +67,8 @@ using UkmSelectedMaskedServerCardType =
ukm::builders::Autofill_SelectedMaskedServerCard; ukm::builders::Autofill_SelectedMaskedServerCard;
using UkmSuggestionFilledType = ukm::builders::Autofill_SuggestionFilled; using UkmSuggestionFilledType = ukm::builders::Autofill_SuggestionFilled;
using UkmTextFieldDidChangeType = ukm::builders::Autofill_TextFieldDidChange; using UkmTextFieldDidChangeType = ukm::builders::Autofill_TextFieldDidChange;
using UkmLogHiddenRepresentationalFieldSkipDecisionType =
ukm::builders::Autofill_HiddenRepresentationalFieldSkipDecision;
using UkmFormSubmittedType = ukm::builders::Autofill_FormSubmitted; using UkmFormSubmittedType = ukm::builders::Autofill_FormSubmitted;
using UkmFieldTypeValidationType = ukm::builders::Autofill_FieldTypeValidation; using UkmFieldTypeValidationType = ukm::builders::Autofill_FieldTypeValidation;
using UkmFieldFillStatusType = ukm::builders::Autofill_FieldFillStatus; using UkmFieldFillStatusType = ukm::builders::Autofill_FieldFillStatus;
...@@ -719,6 +721,153 @@ TEST_F(AutofillMetricsTest, ...@@ -719,6 +721,153 @@ TEST_F(AutofillMetricsTest,
} }
} }
// Test that we log the skip decisions for hidden/representational fields
// correctly.
TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
// Create a profile.
RecreateProfile();
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("TestForm");
form.origin = GURL("http://example.com/form.html");
form.action = GURL("http://example.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("http://example_root.com/form.html"));
FormFieldData field;
std::vector<ServerFieldType> field_types;
int64_t field_signature[4];
// no decision
test::CreateTestFormField("Name", "name", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(NAME_FULL);
// skips
test::CreateTestFormField("Street", "street", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
field_types.push_back(ADDRESS_HOME_LINE1);
field_signature[0] = Collapse(CalculateFieldSignatureForField(field));
// skips
test::CreateTestFormField("City", "city", "", "text", &field);
field.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
form.fields.push_back(field);
field_types.push_back(ADDRESS_HOME_CITY);
field_signature[1] = Collapse(CalculateFieldSignatureForField(field));
// doesn't skip
test::CreateTestFormField("State", "state", "", "select-one", &field);
field.is_focusable = false;
form.fields.push_back(field);
field_types.push_back(ADDRESS_HOME_STATE);
field_signature[2] = Collapse(CalculateFieldSignatureForField(field));
// doesn't skip
test::CreateTestFormField("Country", "country", "", "select-one", &field);
field.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
form.fields.push_back(field);
field_types.push_back(ADDRESS_HOME_COUNTRY);
field_signature[3] = Collapse(CalculateFieldSignatureForField(field));
int64_t form_signature = Collapse(CalculateFormSignature(form));
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
autofill_manager_->AddSeenForm(form, field_types, field_types);
// Simulate filling form.
{
base::UserActionTester user_action_tester;
std::string guid("00000000-0000-0000-0000-000000000001"); // local profile.
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(std::string(), guid));
}
VerifyFormInteractionUkm(
test_ukm_recorder_, form,
UkmLogHiddenRepresentationalFieldSkipDecisionType::kEntryName,
{{{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFormSignatureName,
form_signature},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[0]},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
ADDRESS_HOME},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_LINE1},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHeuristicTypeName,
ADDRESS_HOME_LINE1},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kServerTypeName,
ADDRESS_HOME_LINE1},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldModeName,
HTML_MODE_NONE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kIsSkippedName,
true}},
{{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFormSignatureName,
form_signature},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[1]},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
ADDRESS_HOME},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_CITY},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHeuristicTypeName,
ADDRESS_HOME_CITY},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kServerTypeName,
ADDRESS_HOME_CITY},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldModeName,
HTML_MODE_NONE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kIsSkippedName,
true}},
{{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFormSignatureName,
form_signature},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[2]},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
ADDRESS_HOME},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_STATE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHeuristicTypeName,
ADDRESS_HOME_STATE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kServerTypeName,
ADDRESS_HOME_STATE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldModeName,
HTML_MODE_NONE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kIsSkippedName,
false}},
{{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFormSignatureName,
form_signature},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[3]},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
ADDRESS_HOME},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_COUNTRY},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHeuristicTypeName,
ADDRESS_HOME_COUNTRY},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kServerTypeName,
ADDRESS_HOME_COUNTRY},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kHtmlFieldModeName,
HTML_MODE_NONE},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kIsSkippedName,
false}}});
}
// Test that we log quality metrics appropriately with fields having // Test that we log quality metrics appropriately with fields having
// only_fill_when_focused and are supposed to log RATIONALIZATION_BAD. // only_fill_when_focused and are supposed to log RATIONALIZATION_BAD.
TEST_F(AutofillMetricsTest, TEST_F(AutofillMetricsTest,
......
...@@ -161,6 +161,67 @@ be describing additional metrics about the same event. ...@@ -161,6 +161,67 @@ be describing additional metrics about the same event.
</metric> </metric>
</event> </event>
<event name="Autofill.HiddenRepresentationalFieldSkipDecision">
<owner>parastoog@chromium.org</owner>
<summary>
Recorded while trying to fill or preview a hidden or a representational
field.
</summary>
<metric name="FieldOverallType">
<summary>
Field's overall |ServerFieldType|. See |AutofillField.GetStorableType()|.
</summary>
</metric>
<metric name="FieldSignature">
<summary>
The signature of the field. This is the hash identifier used to denote
this field for query and voting purposes. See
components/autofill/core/common/signatures_util.cc for more details.
</summary>
</metric>
<metric name="FieldTypeGroup">
<summary>
Field's |FieldTypeGroup|. See |AutofillType.group()|.
</summary>
</metric>
<metric name="FormSignature">
<summary>
The signature of the form. This is the hash identifier used to denote this
form for query and voting purposes. See
components/autofill/core/common/signatures_util.cc for more details.
</summary>
</metric>
<metric name="HeuristicType">
<summary>
Field's |ServerFieldType| based on heuristics. See
|AutofillField.heuristic_type()|.
</summary>
</metric>
<metric name="HtmlFieldMode">
<summary>
Whether the field's autocomplete hint specified 'billing' or 'shipping'.
See |AutofillField.html_mode()|.
</summary>
</metric>
<metric name="HtmlFieldType">
<summary>
Field's autocomplete field type hint. See |AutofillField.html_type()|.
</summary>
</metric>
<metric name="IsSkipped">
<summary>
True if the field was skipped while filling or previewing the form,
because it was hidden or representational, but not a 'select' one.
</summary>
</metric>
<metric name="ServerType">
<summary>
Field's |ServerFieldType| returned by server. See
|AutofillField.server_type()|.
</summary>
</metric>
</event>
<event name="Autofill.FormSubmitted"> <event name="Autofill.FormSubmitted">
<owner>jiahuiguo@google.com</owner> <owner>jiahuiguo@google.com</owner>
<summary> <summary>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment