blob: cb95a2b7c5877a4cb2cf98675a94820c55fa8ec0 [file] [log] [blame]
// Copyright 2017 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 "components/autofill/core/browser/autofill_manager.h"
#include "base/bind.h"
#include "base/containers/adapters.h"
#include "base/feature_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/autofill_data_validation.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/translate/core/common/language_detection_details.h"
#include "google_apis/google_api_keys.h"
#include "ui/gfx/geometry/rect_f.h"
namespace autofill {
namespace {
// Set a conservative upper bound on the number of forms we are willing to
// cache, simply to prevent unbounded memory consumption.
const size_t kAutofillManagerMaxFormCacheSize = 100;
// Returns the AutofillField* corresponding to |field| in |form| or nullptr,
// if not found.
AutofillField* FindAutofillFillField(const FormStructure& form,
const FormFieldData& field) {
for (const auto& f : form) {
if (field.global_id() == f->global_id())
return f.get();
}
for (const auto& cur_field : form) {
if (cur_field->SameFieldAs(field)) {
return cur_field.get();
}
}
return nullptr;
}
// Returns true if |live_form| does not match |cached_form|.
bool CachedFormNeedsUpdate(const FormData& live_form,
const FormStructure& cached_form) {
if (live_form.fields.size() != cached_form.field_count())
return true;
for (size_t i = 0; i < cached_form.field_count(); ++i) {
if (!cached_form.field(i)->SameFieldAs(live_form.fields[i]))
return true;
}
return false;
}
std::string GetAPIKeyForUrl(version_info::Channel channel) {
// First look if we can get API key from command line flag.
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kAutofillAPIKey))
return command_line.GetSwitchValueASCII(switches::kAutofillAPIKey);
// Get the API key from Chrome baked keys.
if (channel == version_info::Channel::STABLE)
return google_apis::GetAPIKey();
return google_apis::GetNonStableAPIKey();
}
} // namespace
using base::TimeTicks;
// static
void AutofillManager::LogAutofillTypePredictionsAvailable(
LogManager* log_manager,
const std::vector<FormStructure*>& forms) {
if (VLOG_IS_ON(1)) {
VLOG(1) << "Parsed forms:";
for (FormStructure* form : forms)
VLOG(1) << *form;
}
if (!log_manager || !log_manager->IsLoggingActive())
return;
LogBuffer buffer;
for (FormStructure* form : forms)
buffer << *form;
log_manager->Log() << LoggingScope::kParsing << LogMessage::kParsedForms
<< std::move(buffer);
}
// static
bool AutofillManager::IsRawMetadataUploadingEnabled(
version_info::Channel channel) {
return channel == version_info::Channel::CANARY ||
channel == version_info::Channel::DEV;
}
AutofillManager::AutofillManager(
AutofillDriver* driver,
AutofillClient* client,
AutofillDownloadManagerState enable_download_manager)
: AutofillManager(driver,
client,
enable_download_manager,
client->GetChannel()) {
DCHECK(driver);
DCHECK(client);
}
AutofillManager::AutofillManager(
AutofillDriver* driver,
AutofillClient* client,
AutofillDownloadManagerState enable_download_manager,
version_info::Channel channel)
: driver_(driver),
client_(client),
log_manager_(client ? client->GetLogManager() : nullptr),
form_interactions_ukm_logger_(CreateFormInteractionsUkmLogger()) {
if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {
download_manager_ = std::make_unique<AutofillDownloadManager>(
driver, this, GetAPIKeyForUrl(channel),
AutofillDownloadManager::IsRawMetadataUploadingEnabled(
IsRawMetadataUploadingEnabled(channel)),
log_manager_);
}
if (client) {
translate::TranslateDriver* translate_driver = client->GetTranslateDriver();
if (translate_driver) {
translate_observation_.Observe(translate_driver);
}
}
}
AutofillManager::~AutofillManager() {
translate_observation_.Reset();
if (!query_result_delay_task_.IsCancelled())
query_result_delay_task_.Cancel();
}
void AutofillManager::OnLanguageDetermined(
const translate::LanguageDetectionDetails& details) {
if (!base::FeatureList::IsEnabled(
features::kAutofillParsingPatternsLanguageDetection)) {
return;
}
for (auto& p : form_structures_) {
std::unique_ptr<FormStructure>& form_structure = p.second;
form_structure->set_current_page_language(
LanguageCode(details.adopted_language));
form_structure->DetermineHeuristicTypes(form_interactions_ukm_logger(),
log_manager_);
}
}
void AutofillManager::OnTranslateDriverDestroyed(
translate::TranslateDriver* translate_driver) {
translate_observation_.Reset();
}
LanguageCode AutofillManager::GetCurrentPageLanguage() {
DCHECK(client());
const translate::LanguageState* language_state = client()->GetLanguageState();
if (!language_state)
return LanguageCode();
return LanguageCode(language_state->current_language());
}
void AutofillManager::OnFormSubmitted(const FormData& form,
bool known_success,
mojom::SubmissionSource source) {
if (IsValidFormData(form))
OnFormSubmittedImpl(form, known_success, source);
}
void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms) {
if (!IsValidFormDataVector(forms) || !driver_->RendererIsAvailable())
return;
// This should be called even forms is empty, AutofillProviderAndroid uses
// this event to detect form submission.
if (!ShouldParseForms(forms))
return;
if (forms.empty())
return;
std::vector<const FormData*> new_forms;
for (const FormData& form : forms) {
const auto parse_form_start_time = AutofillTickClock::NowTicks();
FormStructure* cached_form_structure =
FindCachedFormByRendererId(form.global_id());
// Not updating signatures of credit card forms is legacy behaviour. We
// believe that the signatures are kept stable for voting purposes.
bool update_form_signature = false;
if (cached_form_structure) {
const DenseSet<FormType>& form_types =
cached_form_structure->GetFormTypes();
update_form_signature =
form_types.size() > form_types.count(FormType::kCreditCardForm);
}
FormStructure* form_structure = ParseForm(form, cached_form_structure);
if (!form_structure)
continue;
DCHECK(form_structure);
if (update_form_signature)
form_structure->set_form_signature(CalculateFormSignature(form));
new_forms.push_back(&form);
AutofillMetrics::LogParseFormTiming(AutofillTickClock::NowTicks() -
parse_form_start_time);
}
if (new_forms.empty())
return;
OnFormsParsed(new_forms);
}
void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms) {
DCHECK(!forms.empty());
OnBeforeProcessParsedForms();
driver()->HandleParsedForms(forms);
std::vector<FormStructure*> non_queryable_forms;
std::vector<FormStructure*> queryable_forms;
DenseSet<FormType> form_types;
for (const FormData* form : forms) {
FormStructure* form_structure =
FindCachedFormByRendererId(form->global_id());
if (!form_structure) {
NOTREACHED();
continue;
}
form_types.insert_all(form_structure->GetFormTypes());
// Configure the query encoding for this form and add it to the appropriate
// collection of forms: queryable vs non-queryable.
if (form_structure->ShouldBeQueried())
queryable_forms.push_back(form_structure);
else
non_queryable_forms.push_back(form_structure);
OnFormProcessed(*form, *form_structure);
}
if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
OnAfterProcessParsedForms(form_types);
}
// Send the current type predictions to the renderer. For non-queryable forms
// this is all the information about them that will ever be available. The
// queryable forms will be updated once the field type query is complete.
driver()->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
driver()->SendAutofillTypePredictionsToRenderer(queryable_forms);
// Send the fields that are eligible for manual filling to the renderer. If
// server predictions are not yet available for these forms, the eligible
// fields would be updated again once they are available.
driver()->SendFieldsEligibleForManualFillingToRenderer(
FormStructure::FindFieldsEligibleForManualFilling(non_queryable_forms));
driver()->SendFieldsEligibleForManualFillingToRenderer(
FormStructure::FindFieldsEligibleForManualFilling(queryable_forms));
LogAutofillTypePredictionsAvailable(log_manager_, non_queryable_forms);
LogAutofillTypePredictionsAvailable(log_manager_, queryable_forms);
// Query the server if at least one of the forms was parsed.
if (!queryable_forms.empty() && download_manager()) {
download_manager()->StartQueryRequest(queryable_forms);
}
}
void AutofillManager::OnTextFieldDidChange(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
const TimeTicks timestamp) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
OnTextFieldDidChangeImpl(form, field, bounding_box, timestamp);
}
void AutofillManager::OnTextFieldDidScroll(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
OnTextFieldDidScrollImpl(form, field, bounding_box);
}
void AutofillManager::OnSelectControlDidChange(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
OnSelectControlDidChangeImpl(form, field, bounding_box);
}
void AutofillManager::OnAskForValuesToFill(int query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
bool autoselect_first_suggestion) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
OnAskForValuesToFillImpl(query_id, form, field, bounding_box,
autoselect_first_suggestion);
}
void AutofillManager::OnFocusOnFormField(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
OnFocusOnFormFieldImpl(form, field, bounding_box);
}
// Returns true if |live_form| does not match |cached_form|.
bool AutofillManager::GetCachedFormAndField(const FormData& form,
const FormFieldData& field,
FormStructure** form_structure,
AutofillField** autofill_field) {
// Maybe find an existing FormStructure that corresponds to |form|.
FormStructure* cached_form = FindCachedFormByRendererId(form.global_id());
if (cached_form) {
DCHECK(cached_form);
if (!CachedFormNeedsUpdate(form, *cached_form)) {
// There is no data to return if there are no auto-fillable fields.
if (!cached_form->autofill_count())
return false;
// Return the cached form and matching field, if any.
*form_structure = cached_form;
*autofill_field = FindAutofillFillField(**form_structure, field);
return *autofill_field != nullptr;
}
}
// The form is new or updated, parse it and discard |cached_form|.
// i.e., |cached_form| is no longer valid after this call.
*form_structure = ParseForm(form, cached_form);
if (!*form_structure)
return false;
// Annotate the updated form with its predicted types.
driver()->SendAutofillTypePredictionsToRenderer({*form_structure});
// Update the renderer with the latest set of fields eligible for manual
// filling.
driver()->SendFieldsEligibleForManualFillingToRenderer(
FormStructure::FindFieldsEligibleForManualFilling({*form_structure}));
// There is no data to return if there are no auto-fillable fields.
if (!(*form_structure)->autofill_count())
return false;
// Find the AutofillField that corresponds to |field|.
*autofill_field = FindAutofillFillField(**form_structure, field);
return *autofill_field != nullptr;
}
std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
AutofillManager::CreateFormInteractionsUkmLogger() {
if (!unsafe_client())
return nullptr;
return std::make_unique<AutofillMetrics::FormInteractionsUkmLogger>(
unsafe_client()->GetUkmRecorder(), unsafe_client()->GetUkmSourceId());
}
size_t AutofillManager::FindCachedFormsBySignature(
FormSignature form_signature,
std::vector<FormStructure*>* form_structures) const {
size_t hits_num = 0;
for (const auto& p : form_structures_) {
if (p.second->form_signature() == form_signature) {
++hits_num;
if (form_structures)
form_structures->push_back(p.second.get());
}
}
return hits_num;
}
FormStructure* AutofillManager::FindCachedFormByRendererId(
FormGlobalId form_id) const {
auto it = form_structures_.find(form_id);
return it != form_structures_.end() ? it->second.get() : nullptr;
}
FormStructure* AutofillManager::ParseForm(const FormData& form,
const FormStructure* cached_form) {
if (form_structures_.size() >= kAutofillManagerMaxFormCacheSize) {
if (log_manager_) {
log_manager_->Log() << LoggingScope::kAbortParsing
<< LogMessage::kAbortParsingTooManyForms << form;
}
return nullptr;
}
auto form_structure = std::make_unique<FormStructure>(form);
form_structure->ParseFieldTypesFromAutocompleteAttributes();
if (!form_structure->ShouldBeParsed(log_manager_))
return nullptr;
if (cached_form) {
// We need to keep the server data if available. We need to use them while
// determining the heuristics.
form_structure->RetrieveFromCache(*cached_form,
/*should_keep_cached_value=*/true,
/*only_server_and_autofill_state=*/true);
if (observer_for_testing_)
observer_for_testing_->OnFormParsed();
if (form_structure.get()->value_from_dynamic_change_form())
value_from_dynamic_change_form_ = true;
}
form_structure->set_current_page_language(GetCurrentPageLanguage());
form_structure->DetermineHeuristicTypes(form_interactions_ukm_logger(),
log_manager_);
// Hold the parsed_form_structure we intend to return. We can use this to
// reference the form_signature when transferring ownership below.
FormStructure* parsed_form_structure = form_structure.get();
// Ownership is transferred to |form_structures_| which maintains it until
// the form is parsed again or the AutofillManager is destroyed.
//
// Note that this insert/update takes ownership of the new form structure
// and also destroys the previously cached form structure.
form_structures_[parsed_form_structure->global_id()] =
std::move(form_structure);
return parsed_form_structure;
}
void AutofillManager::Reset() {
query_result_delay_task_.Cancel();
form_structures_.clear();
form_interactions_ukm_logger_ = CreateFormInteractionsUkmLogger();
}
void AutofillManager::OnLoadedServerPredictions(
std::string response,
const std::vector<FormSignature>& queried_form_signatures) {
// Get the current valid FormStructures represented by
// |queried_form_signatures|.
std::vector<FormStructure*> queried_forms;
queried_forms.reserve(queried_form_signatures.size());
for (const auto& form_signature : queried_form_signatures) {
FindCachedFormsBySignature(form_signature, &queried_forms);
}
// Each form signature in |queried_form_signatures| is supposed to be unique,
// and therefore appear only once. This ensures that
// FindCachedFormsBySignature() produces an output without duplicates in the
// forms.
// TODO(crbug/1064709): |queried_forms| could be a set data structure; their
// order should be irrelevant.
DCHECK_EQ(queried_forms.size(),
std::set<FormStructure*>(queried_forms.begin(), queried_forms.end())
.size());
// If there are no current forms corresponding to the queried signatures, drop
// the query response.
if (queried_forms.empty())
return;
// Parse and store the server predictions.
FormStructure::ParseApiQueryResponse(
std::move(response), queried_forms, queried_form_signatures,
form_interactions_ukm_logger(), log_manager_);
// Will log quality metrics for each FormStructure based on the presence of
// autocomplete attributes, if available.
if (auto* logger = form_interactions_ukm_logger()) {
for (FormStructure* cur_form : queried_forms) {
cur_form->LogQualityMetricsBasedOnAutocomplete(logger);
}
}
// Send field type predictions to the renderer so that it can possibly
// annotate forms with the predicted types or add console warnings.
driver()->SendAutofillTypePredictionsToRenderer(queried_forms);
driver()->SendFieldsEligibleForManualFillingToRenderer(
FormStructure::FindFieldsEligibleForManualFilling(queried_forms));
LogAutofillTypePredictionsAvailable(log_manager_, queried_forms);
// TODO(crbug.com/1176816): Remove the test code after initial integration.
int delay = 0;
if (auto* cmd = base::CommandLine::ForCurrentProcess()) {
// This command line helps to simulate query result arriving after autofill
// is triggered and shall be used for manual test only.
std::string value = cmd->GetSwitchValueASCII(
"autofill-server-query-result-delay-in-seconds");
if (!base::StringToInt(value, &delay))
delay = 0;
}
if (delay > 0) {
query_result_delay_task_.Reset(
base::BindOnce(&AutofillManager::PropagateAutofillPredictionsToDriver,
base::Unretained(this)));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(query_result_delay_task_.callback(), queried_forms),
base::Seconds(delay));
} else {
PropagateAutofillPredictionsToDriver(queried_forms);
}
}
void AutofillManager::PropagateAutofillPredictionsToDriver(
const std::vector<FormStructure*>& queried_forms) {
// Forward form structures to the password generation manager to detect
// account creation forms.
driver()->PropagateAutofillPredictions(queried_forms);
}
void AutofillManager::OnServerRequestError(
FormSignature form_signature,
AutofillDownloadManager::RequestType request_type,
int http_error) {}
} // namespace autofill