Bug 1474140: Don't load FormAutofillUtils.jsm at content process startup. r?MattN draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 07 Jul 2018 17:49:34 -0700
changeset 815393 e924a61d9a3fcba02c5daacad60429bf4de015bd
parent 815392 281f9ec8b9b7ba84babf387923501245f0247fc2
child 815394 3eae23ab252c5554a6d271435abb765853a16201
child 816227 979f6bf273f9f380c80219d24d7aa334d0d0e8a7
push id115507
push usermaglione.k@gmail.com
push dateSun, 08 Jul 2018 00:50:10 +0000
reviewersMattN
bugs1474140
milestone63.0a1
Bug 1474140: Don't load FormAutofillUtils.jsm at content process startup. r?MattN MozReview-Commit-ID: 2bOyTPU9QbX
browser/base/content/test/performance/browser_startup_content.js
browser/components/payments/content/paymentDialogFrameScript.js
browser/extensions/formautofill/FormAutofill.jsm
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillDoorhanger.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/FormAutofillHeuristics.jsm
browser/extensions/formautofill/FormAutofillParent.jsm
browser/extensions/formautofill/FormAutofillPreferences.jsm
browser/extensions/formautofill/FormAutofillStorage.jsm
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
browser/extensions/formautofill/bootstrap.js
browser/extensions/formautofill/content/FormAutofillFrameScript.js
browser/extensions/formautofill/content/editAddress.xhtml
browser/extensions/formautofill/content/editDialog.js
browser/extensions/formautofill/content/manageDialog.js
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -44,18 +44,18 @@ const whitelist = {
     // Logging related
     "resource://gre/modules/Log.jsm",
 
     // Session store
     "resource:///modules/sessionstore/ContentSessionStore.jsm",
     "resource://gre/modules/sessionstore/SessionHistory.jsm",
 
     // Forms and passwords
+    "resource://formautofill/FormAutofill.jsm",
     "resource://formautofill/FormAutofillContent.jsm",
-    "resource://formautofill/FormAutofillUtils.jsm",
 
     // Browser front-end
     "resource:///modules/ContentLinkHandler.jsm",
     "resource:///modules/ContentMetaHandler.jsm",
     "resource:///modules/PageStyleHandler.jsm",
     "resource:///modules/LightweightThemeChildListener.jsm",
     "resource://gre/modules/BrowserUtils.jsm",
     "resource://gre/modules/E10SUtils.jsm",
--- a/browser/components/payments/content/paymentDialogFrameScript.js
+++ b/browser/components/payments/content/paymentDialogFrameScript.js
@@ -17,16 +17,18 @@
 
 "use strict";
 
 /* eslint-env mozilla/frame-script */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
+ChromeUtils.defineModuleGetter(this, "FormAutofill",
+                               "resource://formautofill/FormAutofill.jsm");
 ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
                                "resource://formautofill/FormAutofillUtils.jsm");
 
 let PaymentFrameScript = {
   init() {
     XPCOMUtils.defineLazyGetter(this, "log", () => {
       let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
       return new ConsoleAPI({
@@ -63,18 +65,18 @@ let PaymentFrameScript = {
   },
 
   /**
    * Expose privileged utility functions to the unprivileged page.
    */
   exposeUtilityFunctions() {
     let waivedContent = Cu.waiveXrays(content);
     let PaymentDialogUtils = {
-      DEFAULT_REGION: FormAutofillUtils.DEFAULT_REGION,
-      supportedCountries: FormAutofillUtils.supportedCountries,
+      DEFAULT_REGION: FormAutofill.DEFAULT_REGION,
+      supportedCountries: FormAutofill.supportedCountries,
 
       getAddressLabel(address) {
         return FormAutofillUtils.getAddressLabel(address);
       },
 
       isCCNumber(value) {
         return FormAutofillUtils.isCCNumber(value);
       },
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/FormAutofill.jsm
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["FormAutofill"];
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const ADDRESSES_FIRST_TIME_USE_PREF = "extensions.formautofill.firstTimeUse";
+const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available";
+const CREDITCARDS_USED_STATUS_PREF = "extensions.formautofill.creditCards.used";
+const DEFAULT_REGION_PREF = "browser.search.region";
+const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
+const ENABLED_AUTOFILL_CREDITCARDS_PREF = "extensions.formautofill.creditCards.enabled";
+const SUPPORTED_COUNTRIES_PREF = "extensions.formautofill.supportedCountries";
+
+XPCOMUtils.defineLazyPreferenceGetter(this, "logLevel", "extensions.formautofill.loglevel",
+                                      "Warn");
+
+// A logging helper for debug logging to avoid creating Console objects
+// or triggering expensive JS -> C++ calls when debug logging is not
+// enabled.
+//
+// Console objects, even natively-implemented ones, can consume a lot of
+// memory, and since this code may run in every content process, that
+// memory can add up quickly. And, even when debug-level messages are
+// being ignored, console.debug() calls can be expensive.
+//
+// This helper avoids both of those problems by never touching the
+// console object unless debug logging is enabled.
+function debug() {
+  if (logLevel == "debug") {
+    this.log.debug(...arguments);
+  }
+}
+
+var FormAutofill = {
+  ENABLED_AUTOFILL_ADDRESSES_PREF,
+  ENABLED_AUTOFILL_CREDITCARDS_PREF,
+  ADDRESSES_FIRST_TIME_USE_PREF,
+  CREDITCARDS_USED_STATUS_PREF,
+
+  get isAutofillEnabled() { return FormAutofill.isAutofillAddressesEnabled || this.isAutofillCreditCardsEnabled; },
+  get isAutofillCreditCardsEnabled() { return FormAutofill.isAutofillCreditCardsAvailable && FormAutofill._isAutofillCreditCardsEnabled; },
+
+  defineLazyLogGetter(scope, logPrefix) {
+    scope.debug = debug;
+
+    XPCOMUtils.defineLazyGetter(scope, "log", () => {
+      let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+      return new ConsoleAPI({
+        maxLogLevelPref: "extensions.formautofill.loglevel",
+        prefix: logPrefix,
+      });
+    });
+  },
+};
+
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "DEFAULT_REGION", DEFAULT_REGION_PREF, "US");
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "isAutofillAddressesEnabled", ENABLED_AUTOFILL_ADDRESSES_PREF);
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "isAutofillCreditCardsAvailable", AUTOFILL_CREDITCARDS_AVAILABLE_PREF);
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "_isAutofillCreditCardsEnabled", ENABLED_AUTOFILL_CREDITCARDS_PREF);
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "isAutofillAddressesFirstTimeUse", ADDRESSES_FIRST_TIME_USE_PREF);
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "AutofillCreditCardsUsedStatus", CREDITCARDS_USED_STATUS_PREF);
+XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
+                                      "supportedCountries", SUPPORTED_COUNTRIES_PREF, null, null,
+                                      val => val.split(","));
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -12,35 +12,43 @@
 
 var EXPORTED_SYMBOLS = ["FormAutofillContent"];
 
 const Cm = Components.manager;
 
 ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AddressResult",
                                "resource://formautofill/ProfileAutoCompleteResult.jsm");
 ChromeUtils.defineModuleGetter(this, "CreditCardResult",
                                "resource://formautofill/ProfileAutoCompleteResult.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofill",
+                               "resource://formautofill/FormAutofill.jsm");
 ChromeUtils.defineModuleGetter(this, "FormAutofillHandler",
                                "resource://formautofill/FormAutofillHandler.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "FormLikeFactory",
                                "resource://gre/modules/FormLikeFactory.jsm");
 ChromeUtils.defineModuleGetter(this, "InsecurePasswordUtils",
                                "resource://gre/modules/InsecurePasswordUtils.jsm");
 
 const formFillController = Cc["@mozilla.org/satchel/form-fill-controller;1"]
                              .getService(Ci.nsIFormFillController);
 const autocompleteController = Cc["@mozilla.org/autocomplete/controller;1"]
                              .getService(Ci.nsIAutoCompleteController);
 
-const {ADDRESSES_COLLECTION_NAME, CREDITCARDS_COLLECTION_NAME, FIELD_STATES} = FormAutofillUtils;
+XPCOMUtils.defineLazyGetter(this, "ADDRESSES_COLLECTION_NAME",
+                            () => FormAutofillUtils.ADDRESSES_COLLECTION_NAME);
+XPCOMUtils.defineLazyGetter(this, "CREDITCARDS_COLLECTION_NAME",
+                            () => FormAutofillUtils.CREDITCARDS_COLLECTION_NAME);
+XPCOMUtils.defineLazyGetter(this, "FIELD_STATES",
+                            () => FormAutofillUtils.FIELD_STATES);
 
 // Register/unregister a constructor as a factory.
 function AutocompleteFactory() {}
 AutocompleteFactory.prototype = {
   register(targetConstructor) {
     let proto = targetConstructor.prototype;
     this._classID = proto.classID;
 
@@ -70,17 +78,17 @@ AutocompleteFactory.prototype = {
 
 
 /**
  * @constructor
  *
  * @implements {nsIAutoCompleteSearch}
  */
 function AutofillProfileAutoCompleteSearch() {
-  FormAutofillUtils.defineLazyLogGetter(this, "AutofillProfileAutoCompleteSearch");
+  FormAutofill.defineLazyLogGetter(this, "AutofillProfileAutoCompleteSearch");
 }
 AutofillProfileAutoCompleteSearch.prototype = {
   classID: Components.ID("4f9f1e4c-7f2c-439e-9c9e-566b68bc187d"),
   contractID: "@mozilla.org/autocomplete/search;1?name=autofill-profiles",
   classDescription: "AutofillProfileAutoCompleteSearch",
   QueryInterface: ChromeUtils.generateQI([Ci.nsIAutoCompleteSearch]),
 
   // Begin nsIAutoCompleteSearch implementation
@@ -100,18 +108,18 @@ AutofillProfileAutoCompleteSearch.protot
 
     this.debug("startSearch: for", searchString, "with input", activeInput);
 
     let isAddressField = FormAutofillUtils.isAddressField(activeFieldDetail.fieldName);
     let isInputAutofilled = activeFieldDetail.state == FIELD_STATES.AUTO_FILLED;
     let allFieldNames = activeSection.allFieldNames;
     let filledRecordGUID = activeSection.filledRecordGUID;
     let searchPermitted = isAddressField ?
-                          FormAutofillUtils.isAutofillAddressesEnabled :
-                          FormAutofillUtils.isAutofillCreditCardsEnabled;
+                          FormAutofill.isAutofillAddressesEnabled :
+                          FormAutofill.isAutofillCreditCardsEnabled;
     let AutocompleteResult = isAddressField ? AddressResult : CreditCardResult;
     let pendingSearchResult = null;
 
     ProfileAutocomplete.lastProfileAutoCompleteFocusedInput = activeInput;
     // Fallback to form-history if ...
     //   - specified autofill feature is pref off.
     //   - no profile can fill the currently-focused input.
     //   - the current form has already been populated.
@@ -216,17 +224,17 @@ let ProfileAutocomplete = {
   _registered: false,
   _factory: null,
 
   ensureRegistered() {
     if (this._registered) {
       return;
     }
 
-    FormAutofillUtils.defineLazyLogGetter(this, "ProfileAutocomplete");
+    FormAutofill.defineLazyLogGetter(this, "ProfileAutocomplete");
     this.debug("ensureRegistered");
     this._factory = new AutocompleteFactory();
     this._factory.register(AutofillProfileAutoCompleteSearch);
     this._registered = true;
 
     Services.obs.addObserver(this, "autocomplete-will-enter-text");
   },
 
@@ -337,29 +345,29 @@ var FormAutofillContent = {
 
   /**
    * @type {Object} The object where to store the active items, e.g. element,
    * handler, section, and field detail.
    */
   _activeItems: {},
 
   init() {
-    FormAutofillUtils.defineLazyLogGetter(this, "FormAutofillContent");
+    FormAutofill.defineLazyLogGetter(this, "FormAutofillContent");
 
     Services.cpmm.addMessageListener("FormAutofill:enabledStatus", this);
     Services.cpmm.addMessageListener("FormAutofill:savedFieldNames", this);
     Services.obs.addObserver(this, "earlyformsubmit");
 
     let autofillEnabled = Services.cpmm.initialProcessData.autofillEnabled;
     // If storage hasn't be initialized yet autofillEnabled is undefined but we need to ensure
     // autocomplete is registered before the focusin so register it in this case as long as the
     // pref is true.
     let shouldEnableAutofill = autofillEnabled === undefined &&
-                               (FormAutofillUtils.isAutofillAddressesEnabled ||
-                               FormAutofillUtils.isAutofillCreditCardsEnabled);
+                               (FormAutofill.isAutofillAddressesEnabled ||
+                               FormAutofill.isAutofillCreditCardsEnabled);
     if (autofillEnabled || shouldEnableAutofill) {
       ProfileAutocomplete.ensureRegistered();
     }
 
     this.savedFieldNames =
       Services.cpmm.initialProcessData.autofillSavedFieldNames;
   },
 
@@ -385,17 +393,17 @@ var FormAutofillContent = {
    * @param {HTMLElement} formElement Root element which receives earlyformsubmit event.
    * @param {Object} domWin Content window
    * @returns {boolean} Should always return true so form submission isn't canceled.
    */
   notify(formElement, domWin) {
     try {
       this.debug("Notifying form early submission");
 
-      if (!FormAutofillUtils.isAutofillEnabled) {
+      if (!FormAutofill.isAutofillEnabled) {
         this.debug("Form Autofill is disabled");
         return true;
       }
 
       if (domWin && PrivateBrowsingUtils.isContentWindowPrivate(domWin)) {
         this.debug("Ignoring submission in a private window");
         return true;
       }
--- a/browser/extensions/formautofill/FormAutofillDoorhanger.jsm
+++ b/browser/extensions/formautofill/FormAutofillDoorhanger.jsm
@@ -11,20 +11,21 @@
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["FormAutofillDoorhanger"];
 
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 const GetStringFromName = FormAutofillUtils.stringBundle.GetStringFromName;
 const formatStringFromName = FormAutofillUtils.stringBundle.formatStringFromName;
 const brandShortName = FormAutofillUtils.brandBundle.GetStringFromName("brandShortName");
 let changeAutofillOptsKey = "changeAutofillOptions";
 let autofillOptsKey = "autofillOptionsLink";
 let autofillSecurityOptionsKey = "autofillSecurityOptionsLink";
 if (AppConstants.platform == "macosx") {
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -10,25 +10,27 @@
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["FormAutofillHandler"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "FormAutofillHeuristics",
                                "resource://formautofill/FormAutofillHeuristics.jsm");
 ChromeUtils.defineModuleGetter(this, "FormLikeFactory",
                                "resource://gre/modules/FormLikeFactory.jsm");
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 const {FIELD_STATES} = FormAutofillUtils;
 
 class FormAutofillSection {
   constructor(fieldDetails, winUtils) {
     this.fieldDetails = fieldDetails;
     this.filledRecordGUID = null;
     this.winUtils = winUtils;
@@ -547,17 +549,17 @@ class FormAutofillAddressSection extends
     this._cacheValue.oneLineStreetAddress = null;
   }
 
   isValidSection() {
     return this.fieldDetails.length >= FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD;
   }
 
   isEnabled() {
-    return FormAutofillUtils.isAutofillAddressesEnabled;
+    return FormAutofill.isAutofillAddressesEnabled;
   }
 
   isRecordCreatable(record) {
     let hasName = 0;
     let length = 0;
     for (let key of Object.keys(record)) {
       if (!record[key]) {
         continue;
@@ -765,17 +767,17 @@ class FormAutofillCreditCardSection exte
           break;
       }
     }
 
     return hasCCNumber && (ccNumberReason == "autocomplete" || hasExpiryDate || hasCCName);
   }
 
   isEnabled() {
-    return FormAutofillUtils.isAutofillCreditCardsEnabled;
+    return FormAutofill.isAutofillCreditCardsEnabled;
   }
 
   isRecordCreatable(record) {
     return record["cc-number"] && FormAutofillUtils.isCCNumber(record["cc-number"]);
   }
 
   creditCardExpDateTransformer(profile) {
     if (!profile["cc-exp"]) {
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -7,20 +7,22 @@
  */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["FormAutofillHeuristics", "LabelUtils"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 const PREF_HEURISTICS_ENABLED = "extensions.formautofill.heuristics.enabled";
 const PREF_SECTION_ENABLED = "extensions.formautofill.section.enabled";
 const DEFAULT_SECTION_NAME = "-moz-section-default";
 
 /**
  * A scanner for traversing all elements in a form and retrieving the field
  * detail with FormAutofillHeuristics.getInfo function. It also provides a
@@ -796,32 +798,32 @@ this.FormAutofillHeuristics = {
     }
     return this._regexpList[this._regExpTableHashValue(b0, b1, b2)] || null;
   },
 
   _getRegExpList(isAutoCompleteOff, elementTagName) {
     let isSelectElem = elementTagName == "SELECT";
     let regExpListCache = this._getRegExpListCache(
       isAutoCompleteOff,
-      FormAutofillUtils.isAutofillCreditCardsAvailable,
+      FormAutofill.isAutofillCreditCardsAvailable,
       isSelectElem
     );
     if (regExpListCache) {
       return regExpListCache;
     }
     const FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF = [
       "cc-name",
       "cc-number",
       "cc-exp-month",
       "cc-exp-year",
       "cc-exp",
     ];
     let regexps = isAutoCompleteOff ? FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF : Object.keys(this.RULES);
 
-    if (!FormAutofillUtils.isAutofillCreditCardsAvailable) {
+    if (!FormAutofill.isAutofillCreditCardsAvailable) {
       regexps = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
     }
 
     if (isSelectElem) {
       const FIELDNAMES_FOR_SELECT_ELEMENT = [
         "address-level1",
         "address-level2",
         "country",
@@ -830,17 +832,17 @@ this.FormAutofillHeuristics = {
         "cc-exp",
       ];
       regexps = regexps.filter(name => FIELDNAMES_FOR_SELECT_ELEMENT.includes(name));
     }
 
     this._setRegExpListCache(
       regexps,
       isAutoCompleteOff,
-      FormAutofillUtils.isAutofillCreditCardsAvailable,
+      FormAutofill.isAutofillCreditCardsAvailable,
       isSelectElem
     );
 
     return regexps;
   },
 
   getInfo(element) {
     let info = element.getAutocompleteInfo();
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -29,32 +29,36 @@
 
 // We expose a singleton from this module. Some tests may import the
 // constructor via a backstage pass.
 var EXPORTED_SYMBOLS = ["formAutofillParent"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
   CreditCard: "resource://gre/modules/CreditCard.jsm",
   FormAutofillPreferences: "resource://formautofill/FormAutofillPreferences.jsm",
   FormAutofillDoorhanger: "resource://formautofill/FormAutofillDoorhanger.jsm",
+  FormAutofillUtils: "resource://formautofill/FormAutofillUtils.jsm",
   MasterPassword: "resource://formautofill/MasterPassword.jsm",
 });
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 const {
   ENABLED_AUTOFILL_ADDRESSES_PREF,
   ENABLED_AUTOFILL_CREDITCARDS_PREF,
+} = FormAutofill;
+
+const {
   CREDITCARDS_COLLECTION_NAME,
 } = FormAutofillUtils;
 
 function FormAutofillParent() {
   // Lazily load the storage JSM to avoid disk I/O until absolutely needed.
   // Once storage is loaded we need to update saved field names and inform content processes.
   XPCOMUtils.defineLazyGetter(this, "formAutofillStorage", () => {
     let {formAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
@@ -109,17 +113,17 @@ FormAutofillParent.prototype = {
     Services.ppmm.addMessageListener("FormAutofill:OpenPreferences", this);
     Services.mm.addMessageListener("FormAutofill:OnFormSubmit", this);
 
     // Observing the pref and storage changes
     Services.prefs.addObserver(ENABLED_AUTOFILL_ADDRESSES_PREF, this);
     Services.obs.addObserver(this, "formautofill-storage-changed");
 
     // Only listen to credit card related messages if it is available
-    if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+    if (FormAutofill.isAutofillCreditCardsAvailable) {
       Services.ppmm.addMessageListener("FormAutofill:SaveCreditCard", this);
       Services.ppmm.addMessageListener("FormAutofill:RemoveCreditCards", this);
       Services.ppmm.addMessageListener("FormAutofill:GetDecryptedString", this);
       Services.prefs.addObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
     }
   },
 
   observe(subject, topic, data) {
@@ -273,17 +277,17 @@ FormAutofillParent.prototype = {
 
     Services.ppmm.removeMessageListener("FormAutofill:InitStorage", this);
     Services.ppmm.removeMessageListener("FormAutofill:GetRecords", this);
     Services.ppmm.removeMessageListener("FormAutofill:SaveAddress", this);
     Services.ppmm.removeMessageListener("FormAutofill:RemoveAddresses", this);
     Services.obs.removeObserver(this, "sync-pane-loaded");
     Services.prefs.removeObserver(ENABLED_AUTOFILL_ADDRESSES_PREF, this);
 
-    if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+    if (FormAutofill.isAutofillCreditCardsAvailable) {
       Services.ppmm.removeMessageListener("FormAutofill:SaveCreditCard", this);
       Services.ppmm.removeMessageListener("FormAutofill:RemoveCreditCards", this);
       Services.ppmm.removeMessageListener("FormAutofill:GetDecryptedString", this);
       Services.prefs.removeObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
     }
   },
 
   /**
@@ -426,18 +430,18 @@ FormAutofillParent.prototype = {
       let changedGUIDs = this.formAutofillStorage.addresses.mergeToStorage(address.record);
       if (!changedGUIDs.length) {
         changedGUIDs.push(this.formAutofillStorage.addresses.add(address.record));
       }
       changedGUIDs.forEach(guid => this.formAutofillStorage.addresses.notifyUsed(guid));
       this._recordFormFillingTime("address", "manual", timeStartedFillingMS);
 
       // Show first time use doorhanger
-      if (FormAutofillUtils.isAutofillAddressesFirstTimeUse) {
-        Services.prefs.setBoolPref(FormAutofillUtils.ADDRESSES_FIRST_TIME_USE_PREF, false);
+      if (FormAutofill.isAutofillAddressesFirstTimeUse) {
+        Services.prefs.setBoolPref(FormAutofill.ADDRESSES_FIRST_TIME_USE_PREF, false);
         showDoorhanger = async () => {
           const description = FormAutofillUtils.getAddressLabel(address.record);
           const state = await FormAutofillDoorhanger.show(target, "firstTimeUse", description);
           if (state !== "open-pref") {
             return;
           }
 
           target.ownerGlobal.openPreferences("privacy-address-autofill",
@@ -450,18 +454,18 @@ FormAutofillParent.prototype = {
     }
     return showDoorhanger;
   },
 
   _onCreditCardSubmit(creditCard, target, timeStartedFillingMS) {
     // Updates the used status for shield/heartbeat to recognize users who have
     // used Credit Card Autofill.
     let setUsedStatus = status => {
-      if (FormAutofillUtils.AutofillCreditCardsUsedStatus < status) {
-        Services.prefs.setIntPref(FormAutofillUtils.CREDITCARDS_USED_STATUS_PREF, status);
+      if (FormAutofill.AutofillCreditCardsUsedStatus < status) {
+        Services.prefs.setIntPref(FormAutofill.CREDITCARDS_USED_STATUS_PREF, status);
       }
     };
 
     // We'll show the credit card doorhanger if:
     //   - User applys autofill and changed
     //   - User fills form manually and the filling data is not duplicated to storage
     if (creditCard.guid) {
       // Indicate that the user has used Credit Card Autofill to fill in a form.
@@ -511,17 +515,17 @@ FormAutofillParent.prototype = {
       return false;
     }
 
     // Indicate that the user has seen the doorhanger.
     setUsedStatus(2);
 
     return async () => {
       // Suppress the pending doorhanger from showing up if user disabled credit card in previous doorhanger.
-      if (!FormAutofillUtils.isAutofillCreditCardsEnabled) {
+      if (!FormAutofill.isAutofillCreditCardsEnabled) {
         return;
       }
 
       const card = new CreditCard({
         number: creditCard.record["cc-number"] || creditCard.record["cc-number-decrypted"],
         encryptedNumber: creditCard.record["cc-number-encrypted"],
         name: creditCard.record["cc-name"],
       });
--- a/browser/extensions/formautofill/FormAutofillPreferences.jsm
+++ b/browser/extensions/formautofill/FormAutofillPreferences.jsm
@@ -14,31 +14,32 @@ var EXPORTED_SYMBOLS = ["FormAutofillPre
 // users who disable/enable the address autofill feature.
 const BUNDLE_URI = "chrome://formautofill/locale/formautofill.properties";
 const MANAGE_ADDRESSES_URL = "chrome://formautofill/content/manageAddresses.xhtml";
 const MANAGE_CREDITCARDS_URL = "chrome://formautofill/content/manageCreditCards.xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
 
 const {
   ENABLED_AUTOFILL_ADDRESSES_PREF,
   ENABLED_AUTOFILL_CREDITCARDS_PREF,
   MANAGE_ADDRESSES_KEYWORDS,
   EDIT_ADDRESS_KEYWORDS,
   MANAGE_CREDITCARDS_KEYWORDS,
   EDIT_CREDITCARD_KEYWORDS,
 } = FormAutofillUtils;
 // Add credit card enabled flag in telemetry environment for recording the number of
 // users who disable/enable the credit card autofill feature.
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 function FormAutofillPreferences() {
   this.bundle = Services.strings.createBundle(BUNDLE_URI);
 }
 
 FormAutofillPreferences.prototype = {
   /**
    * Create the Form Autofill preference group.
@@ -99,17 +100,17 @@ FormAutofillPreferences.prototype = {
 
     addressAutofillLearnMore.setAttribute("href", learnMoreURL);
 
     // Add preferences search support
     savedAddressesBtn.setAttribute("searchkeywords", MANAGE_ADDRESSES_KEYWORDS.concat(EDIT_ADDRESS_KEYWORDS)
                                                        .map(key => this.bundle.GetStringFromName(key)).join("\n"));
 
     // Manually set the checked state
-    if (FormAutofillUtils.isAutofillAddressesEnabled) {
+    if (FormAutofill.isAutofillAddressesEnabled) {
       addressAutofillCheckbox.setAttribute("checked", true);
     }
 
     addressAutofillCheckboxGroup.align = "center";
     addressAutofillCheckboxGroup.flex = 1;
     addressAutofillCheckboxLabel.flex = 1;
 
     formAutofillGroup.appendChild(addressAutofill);
@@ -123,17 +124,17 @@ FormAutofillPreferences.prototype = {
 
     this.refs = {
       formAutofillGroup,
       addressAutofillCheckbox,
       addressAutofillCheckboxLabel,
       savedAddressesBtn,
     };
 
-    if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+    if (FormAutofill.isAutofillCreditCardsAvailable) {
       let creditCardAutofill = document.createElementNS(XUL_NS, "hbox");
       let creditCardAutofillCheckboxGroup = document.createElementNS(XUL_NS, "hbox");
       let creditCardAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
       let creditCardAutofillCheckboxLabel = document.createElementNS(XUL_NS, "label");
       let creditCardAutofillCheckboxLabelSpacer = document.createElementNS(XUL_NS, "spacer");
       let creditCardAutofillLearnMore = document.createElementNS(XUL_NS, "label");
       let savedCreditCardsBtn = document.createElementNS(XUL_NS, "button");
       savedCreditCardsBtn.className = "accessory-button";
@@ -154,17 +155,17 @@ FormAutofillPreferences.prototype = {
 
       creditCardAutofillLearnMore.setAttribute("href", learnMoreURL);
 
       // Add preferences search support
       savedCreditCardsBtn.setAttribute("searchkeywords", MANAGE_CREDITCARDS_KEYWORDS.concat(EDIT_CREDITCARD_KEYWORDS)
                                                            .map(key => this.bundle.GetStringFromName(key)).join("\n"));
 
       // Manually set the checked state
-      if (FormAutofillUtils.isAutofillCreditCardsEnabled) {
+      if (FormAutofill.isAutofillCreditCardsEnabled) {
         creditCardAutofillCheckbox.setAttribute("checked", true);
       }
 
       creditCardAutofillCheckboxGroup.align = "center";
       creditCardAutofillCheckboxGroup.flex = 1;
       creditCardAutofillCheckboxLabel.flex = 1;
 
       formAutofillGroup.appendChild(creditCardAutofill);
@@ -203,21 +204,21 @@ FormAutofillPreferences.prototype = {
           target.ownerGlobal.gSubDialog.open(MANAGE_CREDITCARDS_URL);
         }
         break;
       }
       case "click": {
         let target = event.target;
 
         if (target == this.refs.addressAutofillCheckboxLabel) {
-          let pref = FormAutofillUtils.isAutofillAddressesEnabled;
+          let pref = FormAutofill.isAutofillAddressesEnabled;
           Services.prefs.setBoolPref(ENABLED_AUTOFILL_ADDRESSES_PREF, !pref);
           this.refs.addressAutofillCheckbox.checked = !pref;
         } else if (target == this.refs.creditCardAutofillCheckboxLabel) {
-          let pref = FormAutofillUtils.isAutofillCreditCardsEnabled;
+          let pref = FormAutofill.isAutofillCreditCardsEnabled;
           Services.prefs.setBoolPref(ENABLED_AUTOFILL_CREDITCARDS_PREF, !pref);
           this.refs.creditCardAutofillCheckbox.checked = !pref;
         }
         break;
       }
     }
   },
 
--- a/browser/extensions/formautofill/FormAutofillStorage.jsm
+++ b/browser/extensions/formautofill/FormAutofillStorage.jsm
@@ -125,24 +125,26 @@
 // We expose a singleton from this module. Some tests may import the
 // constructor via a backstage pass.
 this.EXPORTED_SYMBOLS = ["formAutofillStorage"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/osfile.jsm");
 
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 
 ChromeUtils.defineModuleGetter(this, "CreditCard",
                                "resource://gre/modules/CreditCard.jsm");
 ChromeUtils.defineModuleGetter(this, "JSONFile",
                                "resource://gre/modules/JSONFile.jsm");
 ChromeUtils.defineModuleGetter(this, "FormAutofillNameUtils",
                                "resource://formautofill/FormAutofillNameUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "MasterPassword",
                                "resource://formautofill/MasterPassword.jsm");
 ChromeUtils.defineModuleGetter(this, "PhoneNumber",
                                "resource://formautofill/phonenumberutils/PhoneNumber.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
@@ -244,17 +246,17 @@ class AutofillRecords {
    * @param {Array.<string>} validFields
    *        A list containing non-metadata field names.
    * @param {Array.<string>} validComputedFields
    *        A list containing computed field names.
    * @param {number} schemaVersion
    *        The schema version for the new record.
    */
   constructor(store, collectionName, validFields, validComputedFields, schemaVersion) {
-    FormAutofillUtils.defineLazyLogGetter(this, "AutofillRecords:" + collectionName);
+    FormAutofill.defineLazyLogGetter(this, "AutofillRecords:" + collectionName);
 
     this.VALID_FIELDS = validFields;
     this.VALID_COMPUTED_FIELDS = validComputedFields;
 
     this._store = store;
     this._collectionName = collectionName;
     this._schemaVersion = schemaVersion;
 
@@ -1226,17 +1228,17 @@ class AutofillRecords {
 }
 
 class Addresses extends AutofillRecords {
   constructor(store) {
     super(store, "addresses", VALID_ADDRESS_FIELDS, VALID_ADDRESS_COMPUTED_FIELDS, ADDRESS_SCHEMA_VERSION);
   }
 
   _recordReadProcessor(address) {
-    if (address.country && !FormAutofillUtils.supportedCountries.includes(address.country)) {
+    if (address.country && !FormAutofill.supportedCountries.includes(address.country)) {
       delete address.country;
       delete address["country-name"];
     }
   }
 
   computeFields(address) {
     // NOTE: Remember to bump the schema version number if any of the existing
     //       computing algorithm changes. (No need to bump when just adding new
@@ -1291,17 +1293,17 @@ class Addresses extends AutofillRecords 
         address["country-name"] = "";
       }
       hasNewComputedFields = true;
     }
 
     // Compute tel
     if (!("tel-national" in address)) {
       if (address.tel) {
-        let tel = PhoneNumber.Parse(address.tel, address.country || FormAutofillUtils.DEFAULT_REGION);
+        let tel = PhoneNumber.Parse(address.tel, address.country || FormAutofill.DEFAULT_REGION);
         if (tel) {
           if (tel.countryCode) {
             address["tel-country-code"] = tel.countryCode;
           }
           if (tel.nationalNumber) {
             address["tel-national"] = tel.nationalNumber;
           }
 
@@ -1380,34 +1382,36 @@ class Addresses extends AutofillRecords 
       country = address.country.toUpperCase();
     } else if (address["country-name"]) {
       country = FormAutofillUtils.identifyCountryCode(address["country-name"]);
     }
 
     // Only values included in the region list will be saved.
     let hasLocalizedName = false;
     try {
-      let localizedName = Services.intl.getRegionDisplayNames(undefined, [country]);
-      hasLocalizedName = localizedName != country;
+      if (country) {
+        let localizedName = Services.intl.getRegionDisplayNames(undefined, [country]);
+        hasLocalizedName = localizedName != country;
+      }
     } catch (e) {}
 
     if (country && hasLocalizedName) {
       address.country = country;
     } else {
       delete address.country;
     }
 
     delete address["country-name"];
   }
 
   _normalizeTel(address) {
     if (address.tel || TEL_COMPONENTS.some(c => !!address[c])) {
       FormAutofillUtils.compressTel(address);
 
-      let possibleRegion = address.country || FormAutofillUtils.DEFAULT_REGION;
+      let possibleRegion = address.country || FormAutofill.DEFAULT_REGION;
       let tel = PhoneNumber.Parse(address.tel, possibleRegion);
 
       if (tel && tel.internationalNumber) {
         // Force to save numbers in E.164 format if parse success.
         address.tel = tel.internationalNumber;
       }
     }
     TEL_COMPONENTS.forEach(c => delete address[c]);
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -7,23 +7,16 @@
 var EXPORTED_SYMBOLS = ["FormAutofillUtils", "AddressDataLoader"];
 
 const ADDRESS_METADATA_PATH = "resource://formautofill/addressmetadata/";
 const ADDRESS_REFERENCES = "addressReferences.js";
 const ADDRESS_REFERENCES_EXT = "addressReferencesExt.js";
 
 const ADDRESSES_COLLECTION_NAME = "addresses";
 const CREDITCARDS_COLLECTION_NAME = "creditCards";
-const ADDRESSES_FIRST_TIME_USE_PREF = "extensions.formautofill.firstTimeUse";
-const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
-const CREDITCARDS_USED_STATUS_PREF = "extensions.formautofill.creditCards.used";
-const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available";
-const ENABLED_AUTOFILL_CREDITCARDS_PREF = "extensions.formautofill.creditCards.enabled";
-const DEFAULT_REGION_PREF = "browser.search.region";
-const SUPPORTED_COUNTRIES_PREF = "extensions.formautofill.supportedCountries";
 const MANAGE_ADDRESSES_KEYWORDS = ["manageAddressesTitle", "addNewAddressTitle"];
 const EDIT_ADDRESS_KEYWORDS = [
   "givenName", "additionalName", "familyName", "organization2", "streetAddress",
   "state", "province", "city", "country", "zip", "postalCode", "email", "tel",
 ];
 const MANAGE_CREDITCARDS_KEYWORDS = ["manageCreditCardsTitle", "addNewCreditCardTitle", "showCreditCardsBtnLabel"];
 const EDIT_CREDITCARD_KEYWORDS = ["cardNumber", "nameOnCard", "cardExpires"];
 const FIELD_STATES = {
@@ -37,39 +30,20 @@ const SECTION_TYPES = {
 };
 
 // The maximum length of data to be saved in a single field for preventing DoS
 // attacks that fill the user's hard drive(s).
 const MAX_FIELD_VALUE_LENGTH = 200;
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 ChromeUtils.defineModuleGetter(this, "CreditCard",
   "resource://gre/modules/CreditCard.jsm");
 
-XPCOMUtils.defineLazyPreferenceGetter(this, "logLevel", "extensions.formautofill.loglevel",
-                                      "Warn");
-
-// A logging helper for debug logging to avoid creating Console objects
-// or triggering expensive JS -> C++ calls when debug logging is not
-// enabled.
-//
-// Console objects, even natively-implemented ones, can consume a lot of
-// memory, and since this code may run in every content process, that
-// memory can add up quickly. And, even when debug-level messages are
-// being ignored, console.debug() calls can be expensive.
-//
-// This helper avoids both of those problems by never touching the
-// console object unless debug logging is enabled.
-function debug() {
-  if (logLevel == "debug") {
-    this.log.debug(...arguments);
-  }
-}
-
 let AddressDataLoader = {
   // Status of address data loading. We'll load all the countries with basic level 1
   // information while requesting conutry information, and set country to true.
   // Level 1 Set is for recording which country's level 1/level 2 data is loaded,
   // since we only load this when getCountryAddressData called with level 1 parameter.
   _dataLoaded: {
     country: false,
     level1: new Set(),
@@ -184,25 +158,19 @@ let AddressDataLoader = {
       locales = list.map(key => this._parse(this._addressData[`${defaultLocale.id}--${key}`]));
     }
     return {defaultLocale, locales};
   },
 };
 
 this.FormAutofillUtils = {
   get AUTOFILL_FIELDS_THRESHOLD() { return 3; },
-  get isAutofillEnabled() { return this.isAutofillAddressesEnabled || this.isAutofillCreditCardsEnabled; },
-  get isAutofillCreditCardsEnabled() { return this.isAutofillCreditCardsAvailable && this._isAutofillCreditCardsEnabled; },
 
   ADDRESSES_COLLECTION_NAME,
   CREDITCARDS_COLLECTION_NAME,
-  ENABLED_AUTOFILL_ADDRESSES_PREF,
-  ENABLED_AUTOFILL_CREDITCARDS_PREF,
-  ADDRESSES_FIRST_TIME_USE_PREF,
-  CREDITCARDS_USED_STATUS_PREF,
   MANAGE_ADDRESSES_KEYWORDS,
   EDIT_ADDRESS_KEYWORDS,
   MANAGE_CREDITCARDS_KEYWORDS,
   EDIT_CREDITCARD_KEYWORDS,
   MAX_FIELD_VALUE_LENGTH,
   FIELD_STATES,
   SECTION_TYPES,
 
@@ -352,28 +320,16 @@ this.FormAutofillUtils = {
 
     for (let field in address) {
       if (field != "tel" && this.getCategoryFromFieldName(field) == "tel") {
         delete address[field];
       }
     }
   },
 
-  defineLazyLogGetter(scope, logPrefix) {
-    scope.debug = debug;
-
-    XPCOMUtils.defineLazyGetter(scope, "log", () => {
-      let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
-      return new ConsoleAPI({
-        maxLogLevelPref: "extensions.formautofill.loglevel",
-        prefix: logPrefix,
-      });
-    });
-  },
-
   autofillFieldSelector(doc) {
     return doc.querySelectorAll("input, select");
   },
 
   ALLOWED_TYPES: ["text", "email", "tel", "number", "month"],
   isFieldEligibleForAutofill(element) {
     let tagName = element.tagName;
     if (tagName == "INPUT") {
@@ -391,35 +347,35 @@ this.FormAutofillUtils = {
   loadDataFromScript(url, sandbox = {}) {
     Services.scriptloader.loadSubScript(url, sandbox, "utf-8");
     return sandbox;
   },
 
   /**
    * Get country address data and fallback to US if not found.
    * See AddressDataLoader._loadData for more details of addressData structure.
-   * @param {string} [country=FormAutofillUtils.DEFAULT_REGION]
+   * @param {string} [country=FormAutofill.DEFAULT_REGION]
    *        The country code for requesting specific country's metadata. It'll be
    *        default region if parameter is not set.
    * @param {string} [level1=null]
    *        Retrun address level 1/level 2 metadata if parameter is set.
    * @returns {object|null}
    *          Return metadata of specific region with default locale and other supported
    *          locales. We need to return a deafult country metadata for layout format
    *          and collator, but for sub-region metadata we'll just return null if not found.
    */
-  getCountryAddressRawData(country = FormAutofillUtils.DEFAULT_REGION, level1 = null) {
+  getCountryAddressRawData(country = FormAutofill.DEFAULT_REGION, level1 = null) {
     let metadata = AddressDataLoader.getData(country, level1);
     if (!metadata) {
       if (level1) {
         return null;
       }
       // Fallback to default region if we couldn't get data from given country.
-      if (country != FormAutofillUtils.DEFAULT_REGION) {
-        metadata = AddressDataLoader.getData(FormAutofillUtils.DEFAULT_REGION);
+      if (country != FormAutofill.DEFAULT_REGION) {
+        metadata = AddressDataLoader.getData(FormAutofill.DEFAULT_REGION);
       }
     }
 
     // TODO: Now we fallback to US if we couldn't get data from default region,
     //       but it could be removed in bug 1423464 if it's not necessary.
     if (!metadata) {
       metadata = AddressDataLoader.getData("US");
     }
@@ -520,17 +476,17 @@ this.FormAutofillUtils = {
    * Use alternative country name list to identify a country code from a
    * specified country name.
    * @param   {string} countryName A country name to be identified
    * @param   {string} [countrySpecified] A country code indicating that we only
    *                                      search its alternative names if specified.
    * @returns {string} The matching country code.
    */
   identifyCountryCode(countryName, countrySpecified) {
-    let countries = countrySpecified ? [countrySpecified] : this.supportedCountries;
+    let countries = countrySpecified ? [countrySpecified] : FormAutofill.supportedCountries;
 
     for (let country of countries) {
       let collators = this.getCollators(country);
 
       let metadata = this.getCountryAddressData(country);
       let alternativeCountryNames = metadata.alternative_names || [metadata.name];
       let reAlternativeCountryNames = this._reAlternativeCountryNames[country];
       if (!reAlternativeCountryNames) {
@@ -846,33 +802,17 @@ this.FormAutofillUtils = {
     elements = root.querySelectorAll("[data-localization-region]");
     for (let element of elements) {
       this.localizeAttributeForElement(element, "data-localization-region");
     }
   },
 };
 
 this.log = null;
-this.FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+this.FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 XPCOMUtils.defineLazyGetter(FormAutofillUtils, "stringBundle", function() {
   return Services.strings.createBundle("chrome://formautofill/locale/formautofill.properties");
 });
 
 XPCOMUtils.defineLazyGetter(FormAutofillUtils, "brandBundle", function() {
   return Services.strings.createBundle("chrome://branding/locale/brand.properties");
 });
-
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "DEFAULT_REGION", DEFAULT_REGION_PREF, "US");
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "isAutofillAddressesEnabled", ENABLED_AUTOFILL_ADDRESSES_PREF);
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "isAutofillCreditCardsAvailable", AUTOFILL_CREDITCARDS_AVAILABLE_PREF);
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "_isAutofillCreditCardsEnabled", ENABLED_AUTOFILL_CREDITCARDS_PREF);
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "isAutofillAddressesFirstTimeUse", ADDRESSES_FIRST_TIME_USE_PREF);
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "AutofillCreditCardsUsedStatus", CREDITCARDS_USED_STATUS_PREF);
-XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "supportedCountries", SUPPORTED_COUNTRIES_PREF, null, null,
-                                      val => val.split(","));
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -5,24 +5,26 @@
 /* exported AddressResult, CreditCardResult */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["AddressResult", "CreditCardResult"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "CreditCard",
   "resource://gre/modules/CreditCard.jsm");
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "insecureWarningEnabled", "security.insecure_field_warning.contextual.enabled");
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
+FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 class ProfileAutoCompleteResult {
   constructor(searchString, focusedFieldName, allFieldNames, matchingProfiles, {
     resultCode = null,
     isSecure = true,
     isInputAutofilled = false,
   }) {
     log.debug("Constructing new ProfileAutoCompleteResult:", [...arguments]);
--- a/browser/extensions/formautofill/bootstrap.js
+++ b/browser/extensions/formautofill/bootstrap.js
@@ -10,20 +10,20 @@ const STYLESHEET_URI = "chrome://formaut
 const CACHED_STYLESHEETS = new WeakMap();
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
 ChromeUtils.defineModuleGetter(this, "AddonManagerPrivate",
                                "resource://gre/modules/AddonManager.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofill",
+                               "resource://formautofill/FormAutofill.jsm");
 ChromeUtils.defineModuleGetter(this, "formAutofillParent",
                                "resource://formautofill/FormAutofillParent.jsm");
-ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
-                               "resource://formautofill/FormAutofillUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "resProto",
                                    "@mozilla.org/network/protocol;1?name=resource",
                                    "nsISubstitutingProtocolHandler");
 
 const RESOURCE_HOST = "formautofill";
 
 function insertStyleSheet(domWindow, url) {
@@ -111,17 +111,17 @@ function startup(data) {
   // support -- otherwise it'll return an empty string.
   Services.prefs.setBoolPref("dom.forms.autocomplete.formautofill", true);
   Services.telemetry.scalarSet("formautofill.availability", true);
 
   // This pref determines whether the "addresses"/"creditcards" sync engine is
   // available (ie, whether it is shown in any UI etc) - it *does not* determine
   // whether the engine is actually enabled or not.
   Services.prefs.setBoolPref("services.sync.engine.addresses.available", true);
-  if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+  if (FormAutofill.isAutofillCreditCardsAvailable) {
     Services.prefs.setBoolPref("services.sync.engine.creditcards.available", true);
   } else {
     Services.prefs.clearUserPref("services.sync.engine.creditcards.available");
   }
 
   // Listen for the autocomplete popup message to lazily append our stylesheet related to the popup.
   Services.mm.addMessageListener("FormAutoComplete:MaybeOpenPopup", onMaybeOpenPopup);
 
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -6,17 +6,20 @@
  * Form Autofill frame script.
  */
 
 "use strict";
 
 /* eslint-env mozilla/frame-script */
 
 ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofill",
+                               "resource://formautofill/FormAutofill.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 
 /**
  * Handles content's interactions for the frame.
  *
  * NOTE: Declares it by "var" to make it accessible in unit tests.
  */
 var FormAutofillFrameScript = {
   _nextHandleElement: null,
@@ -45,17 +48,17 @@ var FormAutofillFrameScript = {
     addEventListener("focusin", this);
     addMessageListener("FormAutofill:PreviewProfile", this);
     addMessageListener("FormAutofill:ClearForm", this);
     addMessageListener("FormAutoComplete:PopupClosed", this);
     addMessageListener("FormAutoComplete:PopupOpened", this);
   },
 
   handleEvent(evt) {
-    if (!evt.isTrusted || !FormAutofillUtils.isAutofillEnabled) {
+    if (!evt.isTrusted || !FormAutofill.isAutofillEnabled) {
       return;
     }
     FormAutofillContent.updateActiveInput();
 
     let element = evt.target;
     if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
       return;
     }
@@ -72,17 +75,17 @@ var FormAutofillFrameScript = {
       }
       this._alreadyDOMContentLoaded = true;
     }
 
     this._doIdentifyAutofillFields();
   },
 
   receiveMessage(message) {
-    if (!FormAutofillUtils.isAutofillEnabled) {
+    if (!FormAutofill.isAutofillEnabled) {
       return;
     }
 
     const doc = content.document;
     const {chromeEventHandler} = doc.ownerGlobal.getInterface(Ci.nsIDocShell);
 
     switch (message.name) {
       case "FormAutofill:PreviewProfile": {
--- a/browser/extensions/formautofill/content/editAddress.xhtml
+++ b/browser/extensions/formautofill/content/editAddress.xhtml
@@ -74,18 +74,20 @@
     <button id="cancel" data-localization="cancelBtnLabel"/>
     <button id="save" disabled="disabled" data-localization="saveBtnLabel"/>
   </div>
   <script type="application/javascript"><![CDATA[
     "use strict";
 
     let {
       DEFAULT_REGION,
+      supportedCountries,
+    } = FormAutofill;
+    let {
       getFormFormat,
-      supportedCountries,
     } = FormAutofillUtils;
     let record = window.arguments && window.arguments[0];
     let novalidate = window.arguments && window.arguments[1] == "novalidate";
 
     /* import-globals-from autofillEditForms.js */
     let fieldContainer = new EditAddress({
       form: document.getElementById("form"),
     }, record, {
--- a/browser/extensions/formautofill/content/editDialog.js
+++ b/browser/extensions/formautofill/content/editDialog.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* exported EditAddressDialog, EditCreditCardDialog */
 /* eslint-disable mozilla/balanced-listeners */ // Not relevant since the document gets unloaded.
 
 "use strict";
 
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "formAutofillStorage",
                                "resource://formautofill/FormAutofillStorage.jsm");
 ChromeUtils.defineModuleGetter(this, "MasterPassword",
                                "resource://formautofill/MasterPassword.jsm");
 
 class AutofillEditDialog {
--- a/browser/extensions/formautofill/content/manageDialog.js
+++ b/browser/extensions/formautofill/content/manageDialog.js
@@ -6,27 +6,29 @@
 
 "use strict";
 
 const EDIT_ADDRESS_URL = "chrome://formautofill/content/editAddress.xhtml";
 const EDIT_CREDIT_CARD_URL = "chrome://formautofill/content/editCreditCard.xhtml";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
+ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
 
 ChromeUtils.defineModuleGetter(this, "CreditCard",
                                "resource://gre/modules/CreditCard.jsm");
 ChromeUtils.defineModuleGetter(this, "formAutofillStorage",
                                "resource://formautofill/FormAutofillStorage.jsm");
+ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
+                               "resource://formautofill/FormAutofillUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "MasterPassword",
                                "resource://formautofill/MasterPassword.jsm");
 
 this.log = null;
-FormAutofillUtils.defineLazyLogGetter(this, "manageAddresses");
+FormAutofill.defineLazyLogGetter(this, "manageAddresses");
 
 class ManageRecords {
   constructor(subStorageName, elements) {
     this._storageInitPromise = formAutofillStorage.initialize();
     this._subStorageName = subStorageName;
     this._elements = elements;
     this._newRequest = false;
     this._isLoadingRecords = false;