Autofill is a layered component. It has the following structure:
core/: Code shared by content/ and ios/.content/: Driver using the //content layer (all platforms except iOS).ios/: Driver using //ios (as opposed to //content).android/: Java code for Android.The following architecture diagram shows instances of Autofill's core objects. For simplicity, we only consider the case of Chrome Autofill on non-iOS platforms. The diagram is best read bottom-up because every Autofill flow starts with AutofillAgent extracting a form from the DOM.
┌────────────────────┐
┌─►PersonalDataManager │────────┬──────────────────┐
│ │1 per BrowserContext│ owns N│ owns N│
│ └────────────────────┘ ┌─▼─────────────┐ ┌─▼────────┐
│weak ref │AutofillProfile│ │CreditCard│
│ └───────────────┘ └──────────┘
│ ┌─────────────────┐
│ │FormDataImporter ◄─────────────────────┐
│ │1 per WebContents│ events│
│ └─▲───────────────┘ │
│ │ │
│ │ ┌────────────────────────┐ ┌─┴────────────────────┐
│ │ │AutofillExternalDelegate◄────────┤BrowserAutofillManager│
│ │ │1 per RenderFrameHost │ owns 1│1 per RenderFrameHost │
│ │ └──────────────────────┬─┘ └─▲───┬──────────────┬─┘
│ │ │events │ │ events│
│ │ ┌─────────────────┐ │ │ │votes │
│ ├─►VotesUploader ◄────┼────────────┼───┘ │
│ │ │1 per WebContents│ │ │ │
│ │ └─┬───────────────┘ └────────┐ │ │
│ │ │posts │ │ │
│ │ ┌─▼──────────────────────────┐ │ │ │
│ ├─►AutofillCrowdsourcingManager│ │ │ │ ┌──────────────┐
│ │ │1 per WebContents │ │ │ │ │FormStructure │
│ │ └─────────────────────▲──────┘ │ │ │ │1 per FormData│
│ │ │ │ │ └──┐ └─▲────────────┘
│ │owns 1 │ │ │events │ │sets types
│ ┌─┴──────────────────┐ │queries │ ┌─┴───────────────────┐ │ │owns N
└─┤ChromeAutofillClient│ └─────────┼─┤AutofillManager ├─┼───┘
│1 per WebContents │ │ │1 per RenderFrameHost│ │
└─┬──────────────────┘ │ └─▲─────────────────┬─┘ │
│owns 1 │ │ events│ │
│ └───┼────────────────►│◄──┘
│ │ │
│ ┌────────────┼─────────────────┼────────────┐
│ │owns 1 │events │ │
│ │ │owns 1 │ │
┌─▼────────────────────────┴─┐ ┌─┴─────────────────▼─┐ ┌─▼──────────────────┐
│ContentAutofillDriverFactory├────────►ContentAutofillDriver◄────────►AutofillDriverRouter│
│1 per WebContents │owns N │1 per RenderFrameHost│ events │1 per WebContents │
└────────────────────────────┘ └─▲─────────┬─────────┘ └────────────────────┘
│ │fill form and
Browser │ │other events
1 process │ │
────────────────────────────────────────┼─────────┼────────────────────────────────────────
Renderer │ │
N processes events, often with│ │
FormData objects │ │
┌─┴─────────▼─────┐ ┌─────────────────────┐
│AutofillAgent ├───────►form_autofill_util.cc│
│1 per RenderFrame│calls └─────────────────────┘
└─────────────────┘
To edit the diagram, copy-paste it to asciiflow.com.
A WebContents corresponds to a tab. A RenderFrameHost roughly corresponds to a frame or a document (but to neither exactly; they differ in whether or not they survive navigations; details are here and here). A BrowserContext corresponds to a Profile.
//chrome.AutofillManager and everything north of it, but AutofillDriverIOS* instead of ContentAutofill*, and a different but identically named AutofillAgent.AutofillManager and everything south of it, but AndroidAutofillClient instead of ChromeAutofillClient, and AndroidAutofillManager instead of BrowserAutofillManager.core/common/browser/autofill_client.h//android_webview/browser/aw_autofill_client.h (WebView implementation)//chrome/browser/ui/autofill/chrome_autofill_client.h (Chrome implementation)autofill_driver.h../../content/browser/content_autofill_driver.h (non-iOS implementation)../../ios/browser/autofill_driver_ios.h (iOS implementation)autofill_driver_router.hautofill_external_delegate.hautofill_manager.hbrowser_autofill_manager.h (Chrome specialization)//components/android_autofill/browser/android_autofill_manager.h (WebView specialization)crowdsourcing/autofill_crowdsourcing_manager.hdata_model/form_data_importer.hform_structure.hpersonal_data_manager.hproto/ (Autofill server)content/ios/There are some closely related directories in //chrome:
//chrome/browser/autofill//chrome/browser/ui/android/autofill//chrome/browser/ui/autofill//chrome/browser/ui/views/autofillThis is a cheatsheet to navigate Autofill. It is not necessarily exhaustive and may sacrifice a little bit of correctness in favor of simplicity.
AutofillAgentRenderFrame (frame).blink::WebAutofillClient to communicate with Blink.ContentAutofillDriverRenderFrameHost (frame), owned by ContentAutofillDriverFactory.AutofillDriver and mojom::AutofillDriverAutofillDriverIOS for iOSContentAutofillDriverFactoryWebContents (tab).ContentAutofillDriver and ensures that there is one Driver instance per renderer frame.AutofillDriverIOSFactory for iOSAutofillDriverRouterWebContents (tab).FormData.AutofillManager and BrowserAutofillManagerRenderFrameHost (frame), owned by AutofillDriver.BrowserAutofillManager extends the AutofillManager base class.BrowserAutofillManager has sibling AndroidAutofillManager which is responsible for Android Autofill for WebViews.ChromeAutofillClientWebContents (tab).BrowserAutofillManager to the OS specific logic.AutofillClient interface.AndroidAutofillClient, ChromeAutofillClientIOS and WebViewAutofillClientIOS.PersonalDataManagerBrowserContext (Chrome profile). In incognito mode, the original profile's instance is used. This enables filling even in incognito mode. Imports are disabled in incognito mode by the BrowserAutofillManager.AutofillTable - an SQLite database used to persist data across browser shutdown.AutofillTable's data in memory, making them available to the rest of Autofill.PersonalDataManager generally happen asynchronously. For details, see go/pdm-autofill-table-interface.AutocompleteHistoryManager.FormDataFormFieldData).blink::WebFormElementFormFieldDataglobal_id() gives a globally unique and non-changing identifier of a field in the renderer process.blink::WebFormControlElementFormStructure - corresponds to a FormDataFormFieldData objectsAutofillField - corresponds to a FormFieldDataFormFieldData and extends it byFormGlobalId is a pair of a LocalFrameToken and a FormRendererId, which uniquely identify the frame and the form element in that frame.FieldGlobalId is a pair of a LocalFrameToken and a FieldRendererId.FormSignature is a 64 bit hash value of the form URL (target URL or location of the embedding website as a fallback) and normalized field names.FieldSignature is a 32 bit hash value of the field name (name attribute, falling back to id attribute of the form control) and type (text, search, password, tel, ...)components/autofill/core/browser/form_parsing/.FormField::ParseFormFields is the global entry point for parsing fields with heuristics.ParseSingleFields).components/autofill/core/browser/form_parsing/regex_patterns.h and components/autofill/core/browser/form_parsing/*/*regex_patterns.json.AutofillCrowdsourcingManager is responsible for downloading field classifications and uploading type votes.
Crowd sourcing is applied (for lookups and voting) for forms of any size but the server can handle small forms differently, see http://cs/IsSmallForm%20file:autofill.
Crowd sourcing trumps local heuristics.
For testing purposes, crowd sourcing can be overridden manually by command line parameter:
chrome --enable-features=AutofillOverridePredictions:spec/1_2_4-7_8_9
This creates two manual overrides that supersede server predictions as follows:
NAME_MIDDLE).EMAIL_ADDRESS). For more detail, see the documentation of ServerPredictionOverrides.ParseAutocompleteAttribute.off).Predicted types are represented as FieldTypes and types derived from the autocomplete attribute are represented as HtmlFieldTypes.
AutofillDriverRouter flattens each tree of forms by merging the fields of the FormData nodes into the root FormData, and routes events between the nodes' drivers to the root's driver and vice versa.AutofillAgent only sees renderer forms, AutofillManager only sees browser forms.Several important subsets of FieldTypes exist:
AutofillProfile::kDatabaseStoredTypes.See go/autofill-new-fieldtypes-in-data-model-dd.
components/autofill/core/browser/data_model/components/autofill/core/browser/data_model/autofill_structured_address.h and components/autofill/core/browser/data_model/autofill_structured_address_name.h.AddressComponent::ParseValueAndAssignSubcomponents().ParseValueAndAssignSubcomponentsByRegularExpressions()ParseValueAndAssignSubcomponentsByFallbackMethod()GetParseRegularExpressionsByRelevance().AddressComponent::FormatValueFromSubcomponents().GetBestFormatString(), in particular StreetAddress::GetBestFormatString().AddressComponent::WipeInvalidStructure().The following situations are considered form submissions by Autofill and end up at AutofillManager::OnFormSubmitted() with a submission source and an assessment whether the form submission should be considered successful (meaning that the website accepted the submitted values, not that the HTTP request succeeded):
FormTracker::WillSubmitForm()).SubmissionSource::FORM_SUBMISSION.FormTracker::DidStartNavigation()) - only if the frame has a last_interacted_form_ or form-less element that the user interacted with.SubmissionSource::PROBABLY_FORM_SUBMITTED.FormTracker::DidFinishSameDocumentNavigation()), the last interacted form is/becomes unfocusable or removed. The former condition is tested via WebNode::IsFocusable() and considers various styles (e.g. “display: none” on the node or a parent, “visibility: hidden”) and attributes (e.g. “inert”, tabindex=“-1”, “disabled”) which prevent focusability.SubmissionSource::SAME_DOCUMENT_NAVIGATION.AutofillAgent::AjaxSucceeded()), the last interacted form is/becomes unfocusable or removed.SubmissionSource::XHR_SUCCEEDED if the form is already inaccessible or removed and the XHR succeeds.FormTracker::WillDetach())SubmissionSource::FRAME_DETACHED.Autofill votes are theoretically uploaded
when a form is submitted (BrowserAutofillManager::OnFormSubmittedImpl()).
In this case observed_submission=true is passed to BrowserAutofillManager::MaybeStartVoteUploadProcess.
when a the user removes focus from a form (this could happen because the user clicks on a custom autofill dropdown rendered by the website or if the user just clicks on the background). (BrowserAutofillManager::OnFocusOnNonFormFieldImpl() -> BrowserAutofillManager::ProcessPendingFormForUpload()).
observed_submission=false is passed.
when a the form changes (the structure, not the values) and we notice it (BrowserAutofillManager::UpdatePendingForm() -> BrowserAutofillManager::ProcessPendingFormForUpload()).
observed_submission=false is passed.
In practice we allow only one vote upload per (form x submission source) every kAutofillUploadThrottlingPeriodInDays days.
In case observed_submission == true, the votes are generated on a background thread and then passed to the AutofillCrowdsourcingManager.
In case observed_submission == false, the votes are not directly passed to the AutofillCrowdsourcingManager. Instead they are cached until the cache is flushed. This enables us to override previous votes in case the user focuses and removes focus from a form multiple times while editing the fields' values. The cache is flushed on form submission.
As the votes generation is asynchronous, it is not guaranteed that the results are available by the time the upload cache is flushed. In this case, votes are only uploaded on the next navigation.