Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Side by Side Diff: chrome/browser/autofill/autofill_manager.cc

Issue 8387016: Move some Autofill processing logic on form submit to a background thread. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Don't rely on any particular order of evaluation for the arguments to PostTaskAndReply Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autofill/autofill_manager.h" 5 #include "chrome/browser/autofill/autofill_manager.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <map> 10 #include <map>
11 #include <set> 11 #include <set>
12 #include <utility> 12 #include <utility>
13 13
14 #include "base/bind.h"
14 #include "base/command_line.h" 15 #include "base/command_line.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/string16.h" 17 #include "base/string16.h"
17 #include "base/string_util.h" 18 #include "base/string_util.h"
18 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
19 #include "chrome/browser/autocomplete_history_manager.h" 20 #include "chrome/browser/autocomplete_history_manager.h"
20 #include "chrome/browser/autofill/autofill_cc_infobar_delegate.h" 21 #include "chrome/browser/autofill/autofill_cc_infobar_delegate.h"
21 #include "chrome/browser/autofill/autofill_feedback_infobar_delegate.h" 22 #include "chrome/browser/autofill/autofill_feedback_infobar_delegate.h"
22 #include "chrome/browser/autofill/autofill_external_delegate.h" 23 #include "chrome/browser/autofill/autofill_external_delegate.h"
23 #include "chrome/browser/autofill/autofill_field.h" 24 #include "chrome/browser/autofill/autofill_field.h"
(...skipping 13 matching lines...) Expand all
37 #include "chrome/browser/ui/browser.h" 38 #include "chrome/browser/ui/browser.h"
38 #include "chrome/browser/ui/browser_list.h" 39 #include "chrome/browser/ui/browser_list.h"
39 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 40 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
40 #include "chrome/common/autofill_messages.h" 41 #include "chrome/common/autofill_messages.h"
41 #include "chrome/common/chrome_notification_types.h" 42 #include "chrome/common/chrome_notification_types.h"
42 #include "chrome/common/chrome_switches.h" 43 #include "chrome/common/chrome_switches.h"
43 #include "chrome/common/guid.h" 44 #include "chrome/common/guid.h"
44 #include "chrome/common/pref_names.h" 45 #include "chrome/common/pref_names.h"
45 #include "chrome/common/url_constants.h" 46 #include "chrome/common/url_constants.h"
46 #include "content/browser/renderer_host/render_view_host.h" 47 #include "content/browser/renderer_host/render_view_host.h"
48 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/notification_service.h" 49 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/notification_source.h" 50 #include "content/public/browser/notification_source.h"
49 #include "googleurl/src/gurl.h" 51 #include "googleurl/src/gurl.h"
50 #include "grit/generated_resources.h" 52 #include "grit/generated_resources.h"
51 #include "ipc/ipc_message_macros.h" 53 #include "ipc/ipc_message_macros.h"
52 #include "ui/base/l10n/l10n_util.h" 54 #include "ui/base/l10n/l10n_util.h"
53 #include "webkit/glue/form_data.h" 55 #include "webkit/glue/form_data.h"
54 #include "webkit/glue/form_data_predictions.h" 56 #include "webkit/glue/form_data_predictions.h"
55 #include "webkit/glue/form_field.h" 57 #include "webkit/glue/form_field.h"
56 58
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 } 122 }
121 } 123 }
122 124
123 return false; 125 return false;
124 } 126 }
125 127
126 bool FormIsHTTPS(const FormStructure& form) { 128 bool FormIsHTTPS(const FormStructure& form) {
127 return form.source_url().SchemeIs(chrome::kHttpsScheme); 129 return form.source_url().SchemeIs(chrome::kHttpsScheme);
128 } 130 }
129 131
132 // Uses the existing personal data in |profiles| and |credit_cards| to determine
133 // possible field types for the |submitted_form|. This is potentially
134 // expensive -- on the order of 50ms even for a small set of |stored_data|.
135 // Hence, it should not run on the UI thread -- to avoid locking up the UI --
136 // nor on the IO thread -- to avoid blocking IPC calls.
137 void DeterminePossibleFieldTypesForUpload(
138 const std::vector<AutofillProfile>& profiles,
139 const std::vector<CreditCard>& credit_cards,
140 FormStructure* submitted_form) {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
142
143 // For each field in the |submitted_form|, extract the value. Then for each
144 // profile or credit card, identify any stored types that match the value.
145 for (size_t i = 0; i < submitted_form->field_count(); ++i) {
146 AutofillField* field = submitted_form->field(i);
147 string16 value = CollapseWhitespace(field->value, false);
148
149 FieldTypeSet matching_types;
150 for (std::vector<AutofillProfile>::const_iterator it = profiles.begin();
151 it != profiles.end(); ++it) {
152 it->GetMatchingTypes(value, &matching_types);
153 }
154 for (std::vector<CreditCard>::const_iterator it = credit_cards.begin();
155 it != credit_cards.end(); ++it) {
156 it->GetMatchingTypes(value, &matching_types);
157 }
158
159 if (matching_types.empty())
160 matching_types.insert(UNKNOWN_TYPE);
161
162 field->set_possible_types(matching_types);
163 }
164 }
165
130 // Check for unidentified forms among those with the most query or upload 166 // Check for unidentified forms among those with the most query or upload
131 // requests. If found, present an infobar prompting the user to send Google 167 // requests. If found, present an infobar prompting the user to send Google
132 // Feedback identifying these forms. Only executes if the appropriate flag is 168 // Feedback identifying these forms. Only executes if the appropriate flag is
133 // set in about:flags. 169 // set in about:flags.
134 const char* kPopularFormSignatures[] = { 170 const char* kPopularFormSignatures[] = {
135 "10135289994685082173", 171 "10135289994685082173",
136 "7883844738557049416", 172 "7883844738557049416",
137 "14651966297402649464", 173 "14651966297402649464",
138 "17177862793067325164", 174 "17177862793067325164",
139 "15222964025577790589", 175 "15222964025577790589",
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 download_manager_(tab_contents->profile(), this), 248 download_manager_(tab_contents->profile(), this),
213 disable_download_manager_requests_(false), 249 disable_download_manager_requests_(false),
214 metric_logger_(new AutofillMetrics), 250 metric_logger_(new AutofillMetrics),
215 has_logged_autofill_enabled_(false), 251 has_logged_autofill_enabled_(false),
216 has_logged_address_suggestions_count_(false), 252 has_logged_address_suggestions_count_(false),
217 did_show_suggestions_(false), 253 did_show_suggestions_(false),
218 user_did_type_(false), 254 user_did_type_(false),
219 user_did_autofill_(false), 255 user_did_autofill_(false),
220 user_did_edit_autofilled_field_(false), 256 user_did_edit_autofilled_field_(false),
221 external_delegate_(NULL) { 257 external_delegate_(NULL) {
222 DCHECK(tab_contents);
223
224 // |personal_data_| is NULL when using TestTabContents. 258 // |personal_data_| is NULL when using TestTabContents.
225 personal_data_ = PersonalDataManagerFactory::GetForProfile( 259 personal_data_ = PersonalDataManagerFactory::GetForProfile(
226 tab_contents->profile()->GetOriginalProfile()); 260 tab_contents->profile()->GetOriginalProfile());
227 } 261 }
228 262
229 AutofillManager::~AutofillManager() { 263 AutofillManager::~AutofillManager() {
230 } 264 }
231 265
232 // static 266 // static
233 void AutofillManager::RegisterUserPrefs(PrefService* prefs) { 267 void AutofillManager::RegisterUserPrefs(PrefService* prefs) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidFillAutofillFormData, 309 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidFillAutofillFormData,
276 OnDidFillAutofillFormData) 310 OnDidFillAutofillFormData)
277 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidShowAutofillSuggestions, 311 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidShowAutofillSuggestions,
278 OnDidShowAutofillSuggestions) 312 OnDidShowAutofillSuggestions)
279 IPC_MESSAGE_UNHANDLED(handled = false) 313 IPC_MESSAGE_UNHANDLED(handled = false)
280 IPC_END_MESSAGE_MAP() 314 IPC_END_MESSAGE_MAP()
281 315
282 return handled; 316 return handled;
283 } 317 }
284 318
285 void AutofillManager::OnFormSubmitted(const FormData& form, 319 bool AutofillManager::OnFormSubmitted(const FormData& form,
286 const TimeTicks& timestamp) { 320 const TimeTicks& timestamp) {
287 // Let AutoComplete know as well. 321 // Let AutoComplete know as well.
288 tab_contents_wrapper_->autocomplete_history_manager()->OnFormSubmitted(form); 322 tab_contents_wrapper_->autocomplete_history_manager()->OnFormSubmitted(form);
289 323
290 if (!IsAutofillEnabled()) 324 if (!IsAutofillEnabled())
291 return; 325 return false;
292 326
293 if (tab_contents()->browser_context()->IsOffTheRecord()) 327 if (tab_contents()->browser_context()->IsOffTheRecord())
294 return; 328 return false;
295 329
296 // Don't save data that was submitted through JavaScript. 330 // Don't save data that was submitted through JavaScript.
297 if (!form.user_submitted) 331 if (!form.user_submitted)
298 return; 332 return false;
299 333
300 // Grab a copy of the form data. 334 // Grab a copy of the form data.
301 FormStructure submitted_form(form); 335 scoped_ptr<FormStructure> submitted_form(new FormStructure(form));
302 336
303 // Disregard forms that we wouldn't ever autofill in the first place. 337 // Disregard forms that we wouldn't ever autofill in the first place.
304 if (!submitted_form.ShouldBeParsed(true)) 338 if (!submitted_form->ShouldBeParsed(true))
305 return; 339 return false;
306 340
307 // Ignore forms not present in our cache. These are typically forms with 341 // Ignore forms not present in our cache. These are typically forms with
308 // wonky JavaScript that also makes them not auto-fillable. 342 // wonky JavaScript that also makes them not auto-fillable.
309 FormStructure* cached_submitted_form; 343 FormStructure* cached_submitted_form;
310 if (!FindCachedForm(form, &cached_submitted_form)) 344 if (!FindCachedForm(form, &cached_submitted_form))
311 return; 345 return false;
312 submitted_form.UpdateFromCache(*cached_submitted_form); 346
347 submitted_form->UpdateFromCache(*cached_submitted_form);
348 if (submitted_form->IsAutofillable(true))
349 ImportFormData(*submitted_form);
313 350
314 // Only upload server statistics and UMA metrics if at least some local data 351 // Only upload server statistics and UMA metrics if at least some local data
315 // is available to use as a baseline. 352 // is available to use as a baseline.
316 if (!personal_data_->profiles().empty() || 353 const std::vector<AutofillProfile*>& profiles = personal_data_->profiles();
317 !personal_data_->credit_cards().empty()) { 354 const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
318 DeterminePossibleFieldTypesForUpload(&submitted_form); 355 if (!profiles.empty() || !credit_cards.empty()) {
319 submitted_form.LogQualityMetrics(*metric_logger_, 356 // Copy the profile and credit card data, so that it can be accessed on a
320 forms_loaded_timestamp_, 357 // separate thread.
321 initial_interaction_timestamp_, 358 std::vector<AutofillProfile> copied_profiles;
322 timestamp); 359 copied_profiles.reserve(profiles.size());
360 for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin();
361 it != profiles.end(); ++it) {
362 copied_profiles.push_back(**it);
363 }
323 364
324 if (submitted_form.ShouldBeCrowdsourced()) 365 std::vector<CreditCard> copied_credit_cards;
325 UploadFormData(submitted_form); 366 copied_credit_cards.reserve(credit_cards.size());
367 for (std::vector<CreditCard*>::const_iterator it = credit_cards.begin();
368 it != credit_cards.end(); ++it) {
369 copied_credit_cards.push_back(**it);
370 }
371
372 // TODO(isherman): Ideally, we should not be using the FILE thread here.
373 // Per jar@, this is a good compromise for now, as we don't currently have a
374 // broad consensus on how to support such one-off background tasks.
375
376 // Note that ownership of |submitted_form| is passed to the second task,
377 // using |base::Owned|.
378 FormStructure* raw_submitted_form = submitted_form.get();
379 BrowserThread::PostTaskAndReply(
380 BrowserThread::FILE, FROM_HERE,
381 base::Bind(&DeterminePossibleFieldTypesForUpload,
382 copied_profiles,
383 copied_credit_cards,
384 raw_submitted_form),
385 base::Bind(&AutofillManager::UploadFormDataAsyncCallback,
386 this,
387 base::Owned(submitted_form.release()),
388 forms_loaded_timestamp_,
389 initial_interaction_timestamp_,
390 timestamp));
326 } 391 }
327 392
328 if (!submitted_form.IsAutofillable(true)) 393 return true;
329 return;
330
331 ImportFormData(submitted_form);
332 } 394 }
333 395
334 void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms, 396 void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
335 const TimeTicks& timestamp) { 397 const TimeTicks& timestamp) {
336 bool enabled = IsAutofillEnabled(); 398 bool enabled = IsAutofillEnabled();
337 if (!has_logged_autofill_enabled_) { 399 if (!has_logged_autofill_enabled_) {
338 metric_logger_->LogIsAutofillEnabledAtPageLoad(enabled); 400 metric_logger_->LogIsAutofillEnabledAtPageLoad(enabled);
339 has_logged_autofill_enabled_ = true; 401 has_logged_autofill_enabled_ = true;
340 } 402 }
341 403
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 // If the corresponding flag is set, annotate forms with the predicted types. 682 // If the corresponding flag is set, annotate forms with the predicted types.
621 SendAutofillTypePredictions(form_structures_.get()); 683 SendAutofillTypePredictions(form_structures_.get());
622 } 684 }
623 685
624 bool AutofillManager::IsAutofillEnabled() const { 686 bool AutofillManager::IsAutofillEnabled() const {
625 Profile* profile = Profile::FromBrowserContext( 687 Profile* profile = Profile::FromBrowserContext(
626 const_cast<AutofillManager*>(this)->tab_contents()->browser_context()); 688 const_cast<AutofillManager*>(this)->tab_contents()->browser_context());
627 return profile->GetPrefs()->GetBoolean(prefs::kAutofillEnabled); 689 return profile->GetPrefs()->GetBoolean(prefs::kAutofillEnabled);
628 } 690 }
629 691
630 void AutofillManager::DeterminePossibleFieldTypesForUpload(
631 FormStructure* submitted_form) {
632 // Combine all the profiles and credit cards stored in |personal_data_| into
633 // one vector for ease of iteration.
634 const std::vector<AutofillProfile*>& profiles = personal_data_->profiles();
635 const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
636 std::vector<FormGroup*> stored_data;
637 stored_data.insert(stored_data.end(), profiles.begin(), profiles.end());
638 stored_data.insert(stored_data.end(), credit_cards.begin(),
639 credit_cards.end());
640
641 // For each field in the |submitted_form|, extract the value. Then for each
642 // profile or credit card, identify any stored types that match the value.
643 for (size_t i = 0; i < submitted_form->field_count(); i++) {
644 AutofillField* field = submitted_form->field(i);
645 string16 value = CollapseWhitespace(field->value, false);
646 FieldTypeSet matching_types;
647 for (std::vector<FormGroup*>::const_iterator it = stored_data.begin();
648 it != stored_data.end(); ++it) {
649 (*it)->GetMatchingTypes(value, &matching_types);
650 }
651
652 if (matching_types.empty())
653 matching_types.insert(UNKNOWN_TYPE);
654
655 field->set_possible_types(matching_types);
656 }
657 }
658
659 void AutofillManager::SendAutofillTypePredictions( 692 void AutofillManager::SendAutofillTypePredictions(
660 const std::vector<FormStructure*>& forms) const { 693 const std::vector<FormStructure*>& forms) const {
661 if (!CommandLine::ForCurrentProcess()->HasSwitch( 694 if (!CommandLine::ForCurrentProcess()->HasSwitch(
662 switches::kShowAutofillTypePredictions)) 695 switches::kShowAutofillTypePredictions))
663 return; 696 return;
664 697
665 RenderViewHost* host = tab_contents()->render_view_host(); 698 RenderViewHost* host = tab_contents()->render_view_host();
666 if (!host) 699 if (!host)
667 return; 700 return;
668 701
(...skipping 15 matching lines...) Expand all
684 InfoBarTabHelper* infobar_helper = 717 InfoBarTabHelper* infobar_helper =
685 tab_contents_wrapper_->infobar_tab_helper(); 718 tab_contents_wrapper_->infobar_tab_helper();
686 infobar_helper->AddInfoBar( 719 infobar_helper->AddInfoBar(
687 new AutofillCCInfoBarDelegate(infobar_helper, 720 new AutofillCCInfoBarDelegate(infobar_helper,
688 scoped_credit_card.release(), 721 scoped_credit_card.release(),
689 personal_data_, 722 personal_data_,
690 metric_logger_.get())); 723 metric_logger_.get()));
691 } 724 }
692 } 725 }
693 726
727 // Note that |submitted_form| is passed as a pointer rather than as a reference
728 // so that we can get memory management right across threads. Note also that we
729 // explicitly pass in all the time stamps of interest, as the cached ones might
730 // get reset before this method executes.
731 void AutofillManager::UploadFormDataAsyncCallback(
732 const FormStructure* submitted_form,
733 const TimeTicks& load_time,
734 const TimeTicks& interaction_time,
735 const TimeTicks& submission_time) {
736 submitted_form->LogQualityMetrics(*metric_logger_,
737 load_time,
738 interaction_time,
739 submission_time);
740
741 if (submitted_form->ShouldBeCrowdsourced())
742 UploadFormData(*submitted_form);
743 }
744
694 void AutofillManager::UploadFormData(const FormStructure& submitted_form) { 745 void AutofillManager::UploadFormData(const FormStructure& submitted_form) {
695 if (disable_download_manager_requests_) 746 if (disable_download_manager_requests_)
696 return; 747 return;
697 748
698 // Check if the form is among the forms that were recently auto-filled. 749 // Check if the form is among the forms that were recently auto-filled.
699 bool was_autofilled = false; 750 bool was_autofilled = false;
700 std::string form_signature = submitted_form.FormSignature(); 751 std::string form_signature = submitted_form.FormSignature();
701 for (std::list<std::string>::const_iterator it = 752 for (std::list<std::string>::const_iterator it =
702 autofilled_form_signatures_.begin(); 753 autofilled_form_signatures_.begin();
703 it != autofilled_form_signatures_.end() && !was_autofilled; 754 it != autofilled_form_signatures_.end() && !was_autofilled;
(...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after
1225 *profile_guid = IDToGUID(profile_id); 1276 *profile_guid = IDToGUID(profile_id);
1226 } 1277 }
1227 1278
1228 void AutofillManager::UpdateInitialInteractionTimestamp( 1279 void AutofillManager::UpdateInitialInteractionTimestamp(
1229 const TimeTicks& interaction_timestamp) { 1280 const TimeTicks& interaction_timestamp) {
1230 if (initial_interaction_timestamp_.is_null() || 1281 if (initial_interaction_timestamp_.is_null() ||
1231 interaction_timestamp < initial_interaction_timestamp_) { 1282 interaction_timestamp < initial_interaction_timestamp_) {
1232 initial_interaction_timestamp_ = interaction_timestamp; 1283 initial_interaction_timestamp_ = interaction_timestamp;
1233 } 1284 }
1234 } 1285 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/autofill_manager.h ('k') | chrome/browser/autofill/autofill_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698