diff --git a/DEPS b/DEPS
index 47def3f9..593a119 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'bfd28fa684ee3c9efcfc3bbe6bae4f9464212ef2',
+  'v8_revision': '144ff1bd42847cd3016044051c6cadd28d2230da',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc b/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc
index b1cc322..3be4556c 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim.cc
@@ -65,7 +65,8 @@
 
   data = new PartnerBookmarksShim(
       Profile::FromBrowserContext(browser_context)->GetPrefs());
-  browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, data);
+  browser_context->SetUserData(kPartnerBookmarksShimUserDataKey,
+                               base::WrapUnique(data));
   data->ReloadNodeMapping();
   return data;
 }
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim.h b/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
index e0d3e53..b43cb638 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
@@ -33,6 +33,8 @@
 // Note that node->GetTitle() returns an original (unmodified) title.
 class PartnerBookmarksShim : public base::SupportsUserData::Data {
  public:
+  ~PartnerBookmarksShim() override;
+
   // Returns an instance of the shim for a given |browser_context|.
   static PartnerBookmarksShim* BuildForBrowserContext(
       content::BrowserContext* browser_context);
@@ -126,7 +128,6 @@
 
  private:
   explicit PartnerBookmarksShim(PrefService* prefs);
-  ~PartnerBookmarksShim() override;
 
   const bookmarks::BookmarkNode* GetNodeByID(
       const bookmarks::BookmarkNode* parent,
diff --git a/chrome/browser/android/download/chrome_download_delegate.h b/chrome/browser/android/download/chrome_download_delegate.h
index 9e0347b..d1a6e69 100644
--- a/chrome/browser/android/download/chrome_download_delegate.h
+++ b/chrome/browser/android/download/chrome_download_delegate.h
@@ -11,6 +11,8 @@
 class ChromeDownloadDelegate
     : public content::WebContentsUserData<ChromeDownloadDelegate> {
  public:
+  ~ChromeDownloadDelegate() override;
+
   // Returns true iff this request resulted in the tab creating the download
   // to close.
   static bool EnqueueDownloadManagerRequest(jobject chrome_download_delegate,
@@ -33,7 +35,6 @@
  private:
   explicit ChromeDownloadDelegate(content::WebContents* contents);
   friend class content::WebContentsUserData<ChromeDownloadDelegate>;
-  ~ChromeDownloadDelegate() override;
 
   // A reference to the Java ChromeDownloadDelegate object.
   jobject java_ref_;
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index b933c69..b1d8dd3b5 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -620,7 +620,7 @@
         determined_conflict_action_(
             downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    download_item->SetUserData(kKey, this);
+    download_item->SetUserData(kKey, base::WrapUnique(this));
   }
 
   ~ExtensionDownloadsEventRouterData() override {
@@ -954,7 +954,7 @@
     const std::string& name)
   : id_(id),
     name_(name) {
-  item->SetUserData(kKey, this);
+  item->SetUserData(kKey, base::WrapUnique(this));
 }
 
 DownloadsDownloadFunction::DownloadsDownloadFunction() {}
diff --git a/chrome/browser/extensions/api/tab_capture/offscreen_tab.h b/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
index 1df9a346..7d42cd4 100644
--- a/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
+++ b/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
@@ -36,7 +36,7 @@
 //
 // This class operates exclusively on the UI thread and so is not thread-safe.
 class OffscreenTabsOwner
-    : protected content::WebContentsUserData<OffscreenTabsOwner> {
+    : public content::WebContentsUserData<OffscreenTabsOwner> {
  public:
   ~OffscreenTabsOwner() final;
 
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.h b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
index 11ab88c..898dd61 100644
--- a/chrome/browser/extensions/chrome_extension_web_contents_observer.h
+++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
@@ -26,12 +26,14 @@
 class ChromeExtensionWebContentsObserver
     : public ExtensionWebContentsObserver,
       public content::WebContentsUserData<ChromeExtensionWebContentsObserver> {
+ public:
+  ~ChromeExtensionWebContentsObserver() override;
+
  private:
   friend class content::WebContentsUserData<ChromeExtensionWebContentsObserver>;
 
   explicit ChromeExtensionWebContentsObserver(
       content::WebContents* web_contents);
-  ~ChromeExtensionWebContentsObserver() override;
 
   // ExtensionWebContentsObserver:
   void InitializeRenderFrame(
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index ec0f8111..bdc92d7 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/threading/thread.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -184,8 +185,8 @@
 
     bool defer = false;
     if (throttle) {
-      request->SetUserData(nullptr,
-                           new ThrottleDelegate(request.get(), throttle));
+      request->SetUserData(
+          nullptr, base::MakeUnique<ThrottleDelegate>(request.get(), throttle));
 
       throttle->WillStartRequest(&defer);
     }
@@ -358,7 +359,8 @@
   ResourceThrottle* throttle =
       listener_->CreateResourceThrottle(url, content::RESOURCE_TYPE_MAIN_FRAME);
   ASSERT_TRUE(throttle);
-  request->SetUserData(nullptr, new ThrottleDelegate(request.get(), throttle));
+  request->SetUserData(
+      nullptr, base::MakeUnique<ThrottleDelegate>(request.get(), throttle));
 
   ASSERT_FALSE(request->is_pending());
 
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index 75320e06..3e7ff15 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -496,12 +496,12 @@
     if (version_required.IsValid()) {
       approval->minimum_version.reset(new base::Version(version_required));
     }
-    download_item_->SetUserData(kApprovalKey, approval.release());
+    download_item_->SetUserData(kApprovalKey, std::move(approval));
   } else {
     // It is for the main module of the extension. We should use the provided
     // |approval_|.
     if (approval_)
-      download_item_->SetUserData(kApprovalKey, approval_.release());
+      download_item_->SetUserData(kApprovalKey, std::move(approval_));
   }
 
   if (!download_started_) {
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
index 32bbdd9..a9cede0f 100644
--- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
@@ -78,6 +78,7 @@
   if (profile_to_edit_) {
     PopulateProfile(profile_to_edit_);
     state()->GetPersonalDataManager()->UpdateProfile(*profile_to_edit_);
+    state()->profile_comparator()->Invalidate(*profile_to_edit_);
   } else {
     std::unique_ptr<autofill::AutofillProfile> profile =
         base::MakeUnique<autofill::AutofillProfile>();
diff --git a/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc
index b33d48a..c8e6070 100644
--- a/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/order_summary_view_controller_browsertest.cc
@@ -59,7 +59,7 @@
       DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW);
 
   // Michigan address is selected and has standard shipping.
-  std::vector<base::string16> shipping_address_labels = GetThreeLineLabelValues(
+  std::vector<base::string16> shipping_address_labels = GetProfileLabelValues(
       DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION);
   EXPECT_EQ(base::ASCIIToUTF16("Jane A. Smith"), shipping_address_labels[0]);
   EXPECT_EQ(
@@ -95,7 +95,7 @@
       DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW);
 
   // California address is selected and has free shipping.
-  shipping_address_labels = GetThreeLineLabelValues(
+  shipping_address_labels = GetProfileLabelValues(
       DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION);
   EXPECT_EQ(base::ASCIIToUTF16("John H. Doe"), shipping_address_labels[0]);
   EXPECT_EQ(base::ASCIIToUTF16(
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index 513e143..4f0383b5 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -428,7 +428,7 @@
 }
 
 std::vector<base::string16>
-PaymentRequestBrowserTestBase::GetThreeLineLabelValues(
+PaymentRequestBrowserTestBase::GetProfileLabelValues(
     DialogViewID parent_view_id) {
   std::vector<base::string16> line_labels;
   views::View* parent_view =
@@ -436,15 +436,19 @@
   EXPECT_TRUE(parent_view);
 
   views::View* view = parent_view->GetViewByID(
-      static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_1));
+      static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_1));
   if (view)
     line_labels.push_back(static_cast<views::Label*>(view)->text());
   view = parent_view->GetViewByID(
-      static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_2));
+      static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_2));
   if (view)
     line_labels.push_back(static_cast<views::Label*>(view)->text());
   view = parent_view->GetViewByID(
-      static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_3));
+      static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_3));
+  if (view)
+    line_labels.push_back(static_cast<views::Label*>(view)->text());
+  view = parent_view->GetViewByID(
+      static_cast<int>(DialogViewID::PROFILE_LABEL_ERROR));
   if (view)
     line_labels.push_back(static_cast<views::Label*>(view)->text());
 
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
index 2ecb66c..1b328f6 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -148,8 +148,8 @@
   void ClickOnChildInListViewAndWait(int child_index,
                                      int total_num_children,
                                      DialogViewID list_view_id);
-  // Returns "three-line label" values under |parent_view|.
-  std::vector<base::string16> GetThreeLineLabelValues(
+  // Returns profile label values under |parent_view|.
+  std::vector<base::string16> GetProfileLabelValues(
       DialogViewID parent_view_id);
   // Returns the shipping option labels under |parent_view_id|.
   std::vector<base::string16> GetShippingOptionLabelValues(
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
index 55ef6331..cce2f80 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
@@ -45,10 +45,11 @@
   SHIPPING_OPTION_DESCRIPTION,
   SHIPPING_OPTION_AMOUNT,
 
-  // Used in "three line labels" to annotate each Label of the grouping.
-  THREE_LINE_LABEL_LINE_1,
-  THREE_LINE_LABEL_LINE_2,
-  THREE_LINE_LABEL_LINE_3,
+  // Used in profile labels to annotate each line of the grouping.
+  PROFILE_LABEL_LINE_1,
+  PROFILE_LABEL_LINE_2,
+  PROFILE_LABEL_LINE_3,
+  PROFILE_LABEL_ERROR,
 
   // The following are views contained within the Payment Method Sheet.
   CONTACT_INFO_SHEET_LIST_VIEW,
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index 62cc31e..cbdb5d8 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -19,6 +19,7 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/payments/core/payment_options_provider.h"
+#include "components/payments/core/payments_profile_comparator.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -27,6 +28,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/vector_icons/vector_icons.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_frame_view.h"
@@ -63,10 +65,15 @@
   return profile.ConstructInferredLabel(fields, fields.size(), locale);
 }
 
-std::unique_ptr<views::View> GetThreeLineLabel(AddressStyleType type,
-                                               const base::string16& s1,
-                                               const base::string16& s2,
-                                               const base::string16& s3) {
+// |s1|, |s2|, and |s3| are lines identifying the profile. |s1| is the
+// "headline" which may be emphasized depending on |type|. |error| is a
+// message indicating errors that need to be resolved before using this
+// profile.
+std::unique_ptr<views::View> GetProfileLabel(AddressStyleType type,
+                                             const base::string16& s1,
+                                             const base::string16& s2,
+                                             const base::string16& s3,
+                                             const base::string16& error) {
   std::unique_ptr<views::View> container = base::MakeUnique<views::View>();
   std::unique_ptr<views::BoxLayout> layout =
       base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical, 0, 0, 0);
@@ -80,26 +87,33 @@
       const gfx::FontList& font_list = label->font_list();
       label->SetFontList(font_list.DeriveWithWeight(gfx::Font::Weight::BOLD));
     }
-    label->set_id(static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_1));
+    label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_1));
     label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     container->AddChildView(label.release());
   }
 
   if (!s2.empty()) {
     std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(s2);
-    label->set_id(static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_2));
+    label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_2));
     label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     container->AddChildView(label.release());
   }
 
   if (!s3.empty()) {
     std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(s3);
-    label->set_id(static_cast<int>(DialogViewID::THREE_LINE_LABEL_LINE_3));
+    label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_LINE_3));
     label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     container->AddChildView(label.release());
   }
 
-  // TODO(anthonyvd): add the error label
+  if (!error.empty()) {
+    std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(error);
+    label->set_id(static_cast<int>(DialogViewID::PROFILE_LABEL_ERROR));
+    label->SetFontList(label->GetDefaultFontList().DeriveWithSizeDelta(-1));
+    label->SetEnabledColor(label->GetNativeTheme()->GetSystemColor(
+        ui::NativeTheme::kColorId_LinkEnabled));
+    container->AddChildView(label.release());
+  }
 
   return container;
 }
@@ -231,7 +245,9 @@
 std::unique_ptr<views::View> GetShippingAddressLabel(
     AddressStyleType type,
     const std::string& locale,
-    const autofill::AutofillProfile& profile) {
+    const autofill::AutofillProfile& profile,
+    const PaymentOptionsProvider& options,
+    const PaymentsProfileComparator& comp) {
   base::string16 name =
       profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), locale);
 
@@ -240,7 +256,9 @@
   base::string16 phone = profile.GetInfo(
       autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), locale);
 
-  return GetThreeLineLabel(type, name, address, phone);
+  base::string16 error = comp.GetStringForMissingShippingFields(profile);
+
+  return GetProfileLabel(type, name, address, phone, error);
 }
 
 // TODO(anthonyvd): unit test the label layout.
@@ -248,7 +266,8 @@
     AddressStyleType type,
     const std::string& locale,
     const autofill::AutofillProfile& profile,
-    const PaymentOptionsProvider& options) {
+    const PaymentOptionsProvider& options,
+    const PaymentsProfileComparator& comp) {
   base::string16 name =
       options.request_payer_name()
           ? profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), locale)
@@ -267,7 +286,9 @@
                             locale)
           : base::string16();
 
-  return GetThreeLineLabel(type, name, phone, email);
+  base::string16 error = comp.GetStringForMissingContactFields(profile);
+
+  return GetProfileLabel(type, name, phone, email, error);
 }
 
 std::unique_ptr<views::Border> CreatePaymentRequestRowBorder() {
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.h b/chrome/browser/ui/views/payments/payment_request_views_util.h
index 92515391..5821f18c 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.h
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.h
@@ -26,6 +26,7 @@
 namespace payments {
 
 class PaymentOptionsProvider;
+class PaymentsProfileComparator;
 enum class PaymentShippingType;
 
 constexpr int kPaymentRequestRowHorizontalInsets = 16;
@@ -81,7 +82,9 @@
 std::unique_ptr<views::View> GetShippingAddressLabel(
     AddressStyleType type,
     const std::string& locale,
-    const autofill::AutofillProfile& profile);
+    const autofill::AutofillProfile& profile,
+    const PaymentOptionsProvider& options,
+    const PaymentsProfileComparator& comp);
 
 // Extracts and formats descriptive text from the given |profile| to represent
 // the contact info in the context specified by |type|. Includes/excludes name,
@@ -90,7 +93,8 @@
     AddressStyleType type,
     const std::string& locale,
     const autofill::AutofillProfile& profile,
-    const PaymentOptionsProvider& options);
+    const PaymentOptionsProvider& options,
+    const PaymentsProfileComparator& comp);
 
 // Creates a views::Border object that can paint the gray horizontal ruler used
 // as a separator between items in the Payment Request dialog.
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 32a1d22..e413ea9 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -600,10 +600,11 @@
   } else {
     auto* profile = state()->selected_shipping_profile();
 
-    return profile ? GetShippingAddressLabel(AddressStyleType::SUMMARY,
-                                             state()->GetApplicationLocale(),
-                                             *profile)
-                   : base::MakeUnique<views::Label>(base::string16());
+    return profile
+               ? GetShippingAddressLabel(
+                     AddressStyleType::SUMMARY, state()->GetApplicationLocale(),
+                     *profile, *spec(), *(state()->profile_comparator()))
+               : base::MakeUnique<views::Label>(base::string16());
   }
 }
 
@@ -736,10 +737,11 @@
 std::unique_ptr<views::View>
 PaymentSheetViewController::CreateContactInfoSectionContent() {
   autofill::AutofillProfile* profile = state()->selected_contact_profile();
-  return profile ? payments::GetContactInfoLabel(
-                       AddressStyleType::SUMMARY,
-                       state()->GetApplicationLocale(), *profile, *spec())
-                 : base::MakeUnique<views::Label>(base::string16());
+  return profile
+             ? payments::GetContactInfoLabel(
+                   AddressStyleType::SUMMARY, state()->GetApplicationLocale(),
+                   *profile, *spec(), *(state()->profile_comparator()))
+             : base::MakeUnique<views::Label>(base::string16());
 }
 
 // Creates the Contact Info row, which contains a "Contact info" label; the
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.cc b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
index 4ff1043..bf552f5 100644
--- a/chrome/browser/ui/views/payments/profile_list_view_controller.cc
+++ b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
@@ -11,6 +11,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/payments/content/payment_request_spec.h"
 #include "components/payments/content/payment_request_state.h"
+#include "components/payments/core/payments_profile_comparator.h"
 #include "components/payments/core/strings_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -75,9 +76,7 @@
   }
 
   bool CanBeSelected() const override {
-    // TODO(crbug.com/709454): Check for profile completeness. Currently a giant
-    // hack to test the UI.
-    return !profile_->GetRawInfo(autofill::ADDRESS_HOME_ZIP).empty();
+    return parent_view_->IsValidProfile(*profile_);
   }
 
   void PerformSelectionFallback() override {
@@ -108,7 +107,8 @@
   std::unique_ptr<views::View> GetLabel(
       autofill::AutofillProfile* profile) override {
     return GetShippingAddressLabel(AddressStyleType::DETAILED,
-                                   state()->GetApplicationLocale(), *profile);
+                                   state()->GetApplicationLocale(), *profile,
+                                   *spec(), *(state()->profile_comparator()));
   }
 
   void SelectProfile(autofill::AutofillProfile* profile) override {
@@ -130,6 +130,10 @@
     return state()->selected_shipping_profile();
   }
 
+  bool IsValidProfile(const autofill::AutofillProfile& profile) override {
+    return state()->profile_comparator()->IsShippingComplete(&profile);
+  }
+
   std::vector<autofill::AutofillProfile*> GetProfiles() override {
     return state()->shipping_profiles();
   }
@@ -175,7 +179,7 @@
       autofill::AutofillProfile* profile) override {
     return GetContactInfoLabel(AddressStyleType::DETAILED,
                                state()->GetApplicationLocale(), *profile,
-                               *spec());
+                               *spec(), *(state()->profile_comparator()));
   }
 
   void SelectProfile(autofill::AutofillProfile* profile) override {
@@ -190,6 +194,10 @@
     return state()->selected_contact_profile();
   }
 
+  bool IsValidProfile(const autofill::AutofillProfile& profile) override {
+    return state()->profile_comparator()->IsContactInfoComplete(&profile);
+  }
+
   std::vector<autofill::AutofillProfile*> GetProfiles() override {
     return state()->contact_profiles();
   }
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.h b/chrome/browser/ui/views/payments/profile_list_view_controller.h
index 7e1af22..1f1705a 100644
--- a/chrome/browser/ui/views/payments/profile_list_view_controller.h
+++ b/chrome/browser/ui/views/payments/profile_list_view_controller.h
@@ -65,6 +65,8 @@
 
   virtual autofill::AutofillProfile* GetSelectedProfile() = 0;
 
+  virtual bool IsValidProfile(const autofill::AutofillProfile& profile) = 0;
+
  protected:
   // Does not take ownership of the arguments, which should outlive this object.
   ProfileListViewController(PaymentRequestSpec* spec,
diff --git a/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc b/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc
index 1a868b56..19d1039 100644
--- a/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc
@@ -26,6 +26,7 @@
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/payments/content/payment_request_state.h"
+#include "components/payments/core/payments_profile_comparator.h"
 #include "components/strings/grit/components_strings.h"
 #include "third_party/libaddressinput/messages.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -129,6 +130,7 @@
     DCHECK(success);
     profile_to_edit_->set_origin(autofill::kSettingsOrigin);
     state()->GetPersonalDataManager()->UpdateProfile(*profile_to_edit_);
+    state()->profile_comparator()->Invalidate(*profile_to_edit_);
     std::move(on_edited_).Run();
     on_added_.Reset();
   }
diff --git a/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
index 9764dca..f5fe1dc0 100644
--- a/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
@@ -52,7 +52,7 @@
       DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW);
 
   // Michigan address is selected and has standard shipping.
-  std::vector<base::string16> shipping_address_labels = GetThreeLineLabelValues(
+  std::vector<base::string16> shipping_address_labels = GetProfileLabelValues(
       DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION);
   EXPECT_EQ(base::ASCIIToUTF16("Jane A. Smith"), shipping_address_labels[0]);
   EXPECT_EQ(
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
index d655542..6d53266 100644
--- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
@@ -4,12 +4,14 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
 
+#include <cmath>
 #include <string>
 #include <utility>
 
 #include "ash/system/devicetype_utils.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/sys_info.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/browser_process.h"
@@ -46,11 +48,47 @@
 constexpr char kJsApiSkipMigration[] = "skipMigration";
 constexpr char kJsApiRequestRestart[] = "requestRestart";
 
+// UMA names.
+constexpr char kUmaNameFirstScreen[] = "Cryptohome.MigrationUI.FirstScreen";
+constexpr char kUmaNameUserChoice[] = "Cryptohome.MigrationUI.UserChoice";
+constexpr char kUmaNameConsumedBatteryPercent[] =
+    "Cryptohome.MigrationUI.ConsumedBatteryPercent";
+
+// This enum must match the numbering for Cryptohome.MigrationUI.FirstScreen in
+// histograms.xml. Do not reorder or remove items, only add new items before
+// FIRST_SCREEN_MAX.
+enum class FirstScreen {
+  FIRST_SCREEN_READY = 0,
+  FIRST_SCREEN_RESUME = 1,
+  FIRST_SCREEN_LOW_STORAGE = 2,
+  FIRST_SCREEN_COUNT
+};
+
+// This enum must match the numbering for Cryptohome.MigrationUI.UserChoice in
+// histograms.xml. Do not reorder or remove items, only add new items before
+// FIRST_SCREEN_MAX.
+enum class UserChoice {
+  USER_CHOICE_UPDATE = 0,
+  USER_CHOICE_SKIP = 1,
+  USER_CHOICE_COUNT
+};
+
 bool IsTestingUI() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       chromeos::switches::kTestEncryptionMigrationUI);
 }
 
+// Wrapper functions for histogram macros to avoid duplication of expanded code.
+void RecordFirstScreen(FirstScreen first_screen) {
+  UMA_HISTOGRAM_ENUMERATION(kUmaNameFirstScreen, static_cast<int>(first_screen),
+                            static_cast<int>(FirstScreen::FIRST_SCREEN_COUNT));
+}
+
+void RecordUserChoice(UserChoice user_choice) {
+  UMA_HISTOGRAM_ENUMERATION(kUmaNameUserChoice, static_cast<int>(user_choice),
+                            static_cast<int>(UserChoice::USER_CHOICE_COUNT));
+}
+
 }  // namespace
 
 namespace chromeos {
@@ -187,10 +225,12 @@
 }
 
 void EncryptionMigrationScreenHandler::HandleStartMigration() {
+  RecordUserChoice(UserChoice::USER_CHOICE_UPDATE);
   WaitBatteryAndMigrate();
 }
 
 void EncryptionMigrationScreenHandler::HandleSkipMigration() {
+  RecordUserChoice(UserChoice::USER_CHOICE_SKIP);
   // If the user skips migration, we mount the cryptohome without performing the
   // migration by reusing UserContext and LoginPerformer which were used in the
   // previous attempt and dropping |is_forcing_dircrypto| flag in UserContext.
@@ -239,11 +279,14 @@
 void EncryptionMigrationScreenHandler::OnGetAvailableStorage(int64_t size) {
   if (size >= kMinimumAvailableStorage || IsTestingUI()) {
     if (should_resume_) {
+      RecordFirstScreen(FirstScreen::FIRST_SCREEN_RESUME);
       WaitBatteryAndMigrate();
     } else {
+      RecordFirstScreen(FirstScreen::FIRST_SCREEN_READY);
       UpdateUIState(UIState::READY);
     }
   } else {
+    RecordFirstScreen(FirstScreen::FIRST_SCREEN_LOW_STORAGE);
     CallJS("setAvailableSpaceInString", ui::FormatBytes(size));
     CallJS("setNecessarySpaceInString",
            ui::FormatBytes(kMinimumAvailableStorage));
@@ -264,6 +307,7 @@
 
 void EncryptionMigrationScreenHandler::StartMigration() {
   UpdateUIState(UIState::MIGRATING);
+  initial_battery_percent_ = current_battery_percent_;
 
   // Mount the existing eCryptfs vault to a temporary location for migration.
   cryptohome::MountParameters mount(false);
@@ -362,6 +406,14 @@
       CallJS("setMigrationProgress", static_cast<double>(current) / total);
       break;
     case cryptohome::DIRCRYPTO_MIGRATION_SUCCESS:
+      // If the battery level decreased during migration, record the consumed
+      // battery level.
+      if (current_battery_percent_ < initial_battery_percent_) {
+        UMA_HISTOGRAM_PERCENTAGE(
+            kUmaNameConsumedBatteryPercent,
+            static_cast<int>(std::round(initial_battery_percent_ -
+                                        current_battery_percent_)));
+      }
       // Restart immediately after successful migration.
       DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
       break;
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
index e65979e..26bbd9a8 100644
--- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
@@ -113,6 +113,9 @@
   // sufficient.
   bool should_migrate_on_enough_battery_ = false;
 
+  // The battery level at the timing that the migration starts.
+  double initial_battery_percent_ = 0.0;
+
   std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   base::WeakPtrFactory<EncryptionMigrationScreenHandler> weak_ptr_factory_;
diff --git a/components/autofill/core/browser/autofill_profile_comparator.h b/components/autofill/core/browser/autofill_profile_comparator.h
index 4b69d184..8222c53 100644
--- a/components/autofill/core/browser/autofill_profile_comparator.h
+++ b/components/autofill/core/browser/autofill_profile_comparator.h
@@ -215,6 +215,8 @@
                      const AutofillProfile& p2,
                      NameInfo* info) const;
 
+  const std::string app_locale() const { return app_locale_; }
+
  private:
   l10n::CaseInsensitiveCompare case_insensitive_compare_;
   std::unique_ptr<icu::Transliterator> transliterator_;
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index afa3213..c43f691 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -17,8 +17,8 @@
 #include "components/payments/content/payment_response_helper.h"
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/payment_instrument.h"
+#include "components/payments/core/payment_request_data_util.h"
 #include "components/payments/core/payment_request_delegate.h"
-#include "components/payments/core/profile_util.h"
 
 namespace payments {
 
@@ -37,7 +37,8 @@
       selected_shipping_profile_(nullptr),
       selected_contact_profile_(nullptr),
       selected_instrument_(nullptr),
-      payment_request_delegate_(payment_request_delegate) {
+      payment_request_delegate_(payment_request_delegate),
+      profile_comparator_(app_locale, *spec) {
   PopulateProfileCache();
   SetDefaultProfileSelections();
   spec_->AddObserver(this);
@@ -163,10 +164,8 @@
   // Start the normalization of the shipping address.
   // Use the country code from the profile if it is set, otherwise infer it
   // from the |app_locale_|.
-  std::string country_code = base::UTF16ToUTF8(
-      selected_shipping_profile_->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
-  if (!autofill::data_util::IsValidCountryCode(country_code))
-    country_code = autofill::AutofillCountry::CountryCodeForLocale(app_locale_);
+  std::string country_code = data_util::GetCountryCodeWithFallback(
+      selected_shipping_profile_, app_locale_);
   payment_request_delegate_->GetAddressNormalizer()->StartAddressNormalization(
       *selected_shipping_profile_, country_code, /*timeout_seconds=*/2, this);
 }
@@ -218,8 +217,8 @@
                    return p.get();
                  });
 
-  contact_profiles_ = profile_util::FilterProfilesForContact(
-      raw_profiles_for_filtering, GetApplicationLocale(), *spec_);
+  contact_profiles_ = profile_comparator()->FilterProfilesForContact(
+      raw_profiles_for_filtering);
 
   // Create the list of available instruments.
   const std::vector<autofill::CreditCard*>& cards =
@@ -274,15 +273,13 @@
 }
 
 bool PaymentRequestState::ArePaymentOptionsSatisfied() {
-  // TODO(mathp): Have a measure of shipping address completeness.
-  if (spec_->request_shipping() && selected_shipping_profile_ == nullptr)
-    return false;
-
   if (is_waiting_for_merchant_validation_)
     return false;
 
-  profile_util::PaymentsProfileComparator comparator(app_locale_, *spec_);
-  return comparator.IsContactInfoComplete(selected_contact_profile_);
+  if (!profile_comparator()->IsShippingComplete(selected_shipping_profile_))
+    return false;
+
+  return profile_comparator()->IsContactInfoComplete(selected_contact_profile_);
 }
 
 }  // namespace payments
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h
index 9749ca45..ece3bc0 100644
--- a/components/payments/content/payment_request_state.h
+++ b/components/payments/content/payment_request_state.h
@@ -14,6 +14,7 @@
 #include "components/payments/content/payment_request_spec.h"
 #include "components/payments/content/payment_response_helper.h"
 #include "components/payments/core/address_normalizer.h"
+#include "components/payments/core/payments_profile_comparator.h"
 #include "components/payments/mojom/payment_request.mojom.h"
 
 namespace autofill {
@@ -157,6 +158,10 @@
 
   Delegate* delegate() { return delegate_; }
 
+  PaymentsProfileComparator* profile_comparator() {
+    return &profile_comparator_;
+  }
+
  private:
   // Fetches the Autofill Profiles for this user from the PersonalDataManager,
   // and stores copies of them, owned by this PaymentRequestState, in
@@ -211,6 +216,8 @@
 
   std::unique_ptr<PaymentResponseHelper> response_helper_;
 
+  PaymentsProfileComparator profile_comparator_;
+
   base::ObserverList<Observer> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequestState);
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn
index 291a885..8d94990 100644
--- a/components/payments/core/BUILD.gn
+++ b/components/payments/core/BUILD.gn
@@ -25,8 +25,8 @@
     "payment_request_data_util.cc",
     "payment_request_data_util.h",
     "payment_request_delegate.h",
-    "profile_util.cc",
-    "profile_util.h",
+    "payments_profile_comparator.cc",
+    "payments_profile_comparator.h",
     "strings_util.cc",
     "strings_util.h",
   ]
@@ -74,7 +74,7 @@
     "payment_address_unittest.cc",
     "payment_method_data_unittest.cc",
     "payment_request_data_util_unittest.cc",
-    "profile_util_unittest.cc",
+    "payments_profile_comparator_unittest.cc",
   ]
 
   deps = [
diff --git a/components/payments/core/payment_request_data_util.cc b/components/payments/core/payment_request_data_util.cc
index 3fd13c9..87ad961 100644
--- a/components/payments/core/payment_request_data_util.cc
+++ b/components/payments/core/payment_request_data_util.cc
@@ -7,6 +7,8 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -162,5 +164,14 @@
                            PhoneNumberUtil::PhoneNumberFormat::E164);
 }
 
+std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile,
+                                       const std::string& app_locale) {
+  std::string country_code =
+      base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
+  if (!autofill::data_util::IsValidCountryCode(country_code))
+    country_code = autofill::AutofillCountry::CountryCodeForLocale(app_locale);
+  return country_code;
+}
+
 }  // namespace data_util
 }  // namespace payments
diff --git a/components/payments/core/payment_request_data_util.h b/components/payments/core/payment_request_data_util.h
index 984fc8b..29593f6 100644
--- a/components/payments/core/payment_request_data_util.h
+++ b/components/payments/core/payment_request_data_util.h
@@ -66,6 +66,12 @@
 std::string FormatPhoneForResponse(const std::string& phone_number,
                                    const std::string& country_code);
 
+// Returns a country code to be used when validating this profile. If the
+// profile has a valid country code set, it is returned. If not, a country code
+// associated with |app_locale| is used as a fallback.
+std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile,
+                                       const std::string& app_locale);
+
 }  // namespace data_util
 }  // namespace payments
 
diff --git a/components/payments/core/payments_profile_comparator.cc b/components/payments/core/payments_profile_comparator.cc
new file mode 100644
index 0000000..832e005
--- /dev/null
+++ b/components/payments/core/payments_profile_comparator.cc
@@ -0,0 +1,251 @@
+// 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/payments/core/payments_profile_comparator.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/address_i18n.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/validation.h"
+#include "components/payments/core/payment_options_provider.h"
+#include "components/payments/core/payment_request_data_util.h"
+#include "components/strings/grit/components_strings.h"
+#include "third_party/libaddressinput/chromium/addressinput_util.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace payments {
+
+PaymentsProfileComparator::PaymentsProfileComparator(
+    const std::string& app_locale,
+    const PaymentOptionsProvider& options)
+    : autofill::AutofillProfileComparator(app_locale), options_(options) {}
+
+PaymentsProfileComparator::~PaymentsProfileComparator() {}
+
+PaymentsProfileComparator::ProfileFields
+PaymentsProfileComparator::GetMissingProfileFields(
+    const autofill::AutofillProfile* profile) const {
+  if (!profile)
+    return kName | kPhone | kEmail | kAddress;
+
+  if (!cache_.count(profile->guid())) {
+    cache_[profile->guid()] = ComputeMissingFields(*profile);
+  } else {
+    // Cache hit. In debug mode, recompute and check that invalidation has
+    // occurred where necessary.
+    DCHECK_EQ(cache_[profile->guid()], ComputeMissingFields(*profile))
+        << "Profiles must be invalidated when their contents change.";
+  }
+
+  return cache_[profile->guid()];
+}
+
+std::vector<autofill::AutofillProfile*>
+PaymentsProfileComparator::FilterProfilesForContact(
+    const std::vector<autofill::AutofillProfile*>& profiles) const {
+  // We will be removing profiles, so we operate on a copy.
+  std::vector<autofill::AutofillProfile*> processed = profiles;
+
+  // Stable sort, since profiles are expected to be passed in frecency order.
+  std::stable_sort(
+      processed.begin(), processed.end(),
+      std::bind(&PaymentsProfileComparator::IsContactMoreComplete, this,
+                std::placeholders::_1, std::placeholders::_2));
+
+  auto it = processed.begin();
+  while (it != processed.end()) {
+    if (GetContactCompletenessScore(*it) == 0) {
+      // Since profiles are sorted by completeness, this and any further
+      // profiles can be discarded.
+      processed.erase(it, processed.end());
+      break;
+    }
+
+    // Attempt to find a matching element in the vector before the current.
+    // This is quadratic, but the number of elements is generally small
+    // (< 10), so a more complicated algorithm would be overkill.
+    if (std::find_if(processed.begin(), it,
+                     [&](autofill::AutofillProfile* prior) {
+                       return IsContactEqualOrSuperset(*prior, **it);
+                     }) != it) {
+      // Remove the subset profile. |it| will point to the next element after
+      // erasure.
+      it = processed.erase(it);
+    } else {
+      it++;
+    }
+  }
+
+  return processed;
+}
+
+bool PaymentsProfileComparator::IsContactEqualOrSuperset(
+    const autofill::AutofillProfile& super,
+    const autofill::AutofillProfile& sub) const {
+  if (options_.request_payer_name()) {
+    if (sub.HasInfo(autofill::NAME_FULL) &&
+        !super.HasInfo(autofill::NAME_FULL)) {
+      return false;
+    }
+    if (!HaveMergeableNames(super, sub))
+      return false;
+  }
+  if (options_.request_payer_phone()) {
+    if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) &&
+        !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) {
+      return false;
+    }
+    if (!HaveMergeablePhoneNumbers(super, sub))
+      return false;
+  }
+  if (options_.request_payer_email()) {
+    if (sub.HasInfo(autofill::EMAIL_ADDRESS) &&
+        !super.HasInfo(autofill::EMAIL_ADDRESS)) {
+      return false;
+    }
+    if (!HaveMergeableEmailAddresses(super, sub))
+      return false;
+  }
+  return true;
+}
+
+int PaymentsProfileComparator::GetContactCompletenessScore(
+    const autofill::AutofillProfile* profile) const {
+  if (!profile)
+    return 0;
+
+  // Create a bitmask of the fields that are both present and required.
+  ProfileFields present =
+      ~GetMissingProfileFields(profile) & GetRequiredProfileFieldsForContact();
+
+  // Count how many are set.
+  return !!(present & kName) + !!(present & kPhone) + !!(present & kEmail);
+}
+
+bool PaymentsProfileComparator::IsContactInfoComplete(
+    const autofill::AutofillProfile* profile) const {
+  // Mask the fields that are missing with those that are requried. If any bits
+  // are set (i.e., the result is nonzero), then contact info is incomplete.
+  return !(GetMissingProfileFields(profile) &
+           GetRequiredProfileFieldsForContact());
+}
+
+bool PaymentsProfileComparator::IsContactMoreComplete(
+    const autofill::AutofillProfile* p1,
+    const autofill::AutofillProfile* p2) const {
+  return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2);
+}
+
+base::string16 PaymentsProfileComparator::GetStringForMissingContactFields(
+    const autofill::AutofillProfile& profile) const {
+  return GetStringForMissingFields(GetMissingProfileFields(&profile) &
+                                   GetRequiredProfileFieldsForContact());
+}
+
+bool PaymentsProfileComparator::IsShippingComplete(
+    const autofill::AutofillProfile* profile) const {
+  // Mask the fields that are missing with those that are requried. If any bits
+  // are set (i.e., the result is nonzero), then shipping is incomplete.
+  return !(GetMissingProfileFields(profile) &
+           GetRequiredProfileFieldsForShipping());
+}
+
+base::string16 PaymentsProfileComparator::GetStringForMissingShippingFields(
+    const autofill::AutofillProfile& profile) const {
+  return GetStringForMissingFields(GetMissingProfileFields(&profile) &
+                                   GetRequiredProfileFieldsForShipping());
+}
+
+void PaymentsProfileComparator::Invalidate(
+    const autofill::AutofillProfile& profile) {
+  cache_.erase(profile.guid());
+}
+
+PaymentsProfileComparator::ProfileFields
+PaymentsProfileComparator::ComputeMissingFields(
+    const autofill::AutofillProfile& profile) const {
+  ProfileFields missing = 0;
+
+  if (!profile.HasInfo(autofill::NAME_FULL))
+    missing |= kName;
+
+  // Determine the country code to use when validating the phone number. Use
+  // the profile's country if it has one, or the code for the app locale
+  // otherwise. Note that international format numbers will always work--this
+  // is just the region that will be used to check if the number is
+  // potentially in a local format.
+  std::string country =
+      data_util::GetCountryCodeWithFallback(&profile, app_locale());
+
+  base::string16 phone = profile.GetInfo(
+      autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), app_locale());
+  if (!autofill::IsValidPhoneNumber(phone, country))
+    missing |= kPhone;
+
+  base::string16 email = profile.GetInfo(
+      autofill::AutofillType(autofill::EMAIL_ADDRESS), app_locale());
+  if (!autofill::IsValidEmailAddress(email))
+    missing |= kEmail;
+
+  if (!AreRequiredAddressFieldsPresent(profile))
+    missing |= kAddress;
+
+  return missing;
+}
+
+PaymentsProfileComparator::ProfileFields
+PaymentsProfileComparator::GetRequiredProfileFieldsForContact() const {
+  ProfileFields required = 0;
+  if (options_.request_payer_name())
+    required |= kName;
+  if (options_.request_payer_phone())
+    required |= kPhone;
+  if (options_.request_payer_email())
+    required |= kEmail;
+  return required;
+}
+
+PaymentsProfileComparator::ProfileFields
+PaymentsProfileComparator::GetRequiredProfileFieldsForShipping() const {
+  return options_.request_shipping() ? (kAddress | kName | kPhone) : 0;
+}
+
+base::string16 PaymentsProfileComparator::GetStringForMissingFields(
+    PaymentsProfileComparator::ProfileFields fields) const {
+  switch (fields) {
+    case 0:
+      // No bits are set, so no fields are missing.
+      return base::string16();
+    case kName:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED);
+    case kPhone:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED);
+    case kEmail:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_EMAIL_REQUIRED);
+    case kAddress:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS);
+    default:
+      // Either multiple bits are set (likely) or one bit that doesn't
+      // correspond to a named constant is set (shouldn't happen). Return a
+      // generic "More information" message.
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED);
+  }
+}
+
+bool PaymentsProfileComparator::AreRequiredAddressFieldsPresent(
+    const autofill::AutofillProfile& profile) const {
+  std::unique_ptr<::i18n::addressinput::AddressData> data =
+      autofill::i18n::CreateAddressDataFromAutofillProfile(profile,
+                                                           app_locale());
+
+  return autofill::addressinput::HasAllRequiredFields(*data);
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payments_profile_comparator.h b/components/payments/core/payments_profile_comparator.h
new file mode 100644
index 0000000..2c8b934a
--- /dev/null
+++ b/components/payments/core/payments_profile_comparator.h
@@ -0,0 +1,112 @@
+// 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.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENTS_PROFILE_COMPARATOR_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENTS_PROFILE_COMPARATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "components/autofill/core/browser/autofill_profile_comparator.h"
+
+// Utility functions used for processing and filtering address profiles
+// (AutofillProfile).
+
+namespace autofill {
+class AutofillProfile;
+}  // namespace autofill
+
+namespace payments {
+
+class PaymentOptionsProvider;
+
+// Helper class which evaluates profiles for similarity and completeness.
+// Profiles are evaluated once for completeness, and the result is cached,
+// meaning one instance of this class should be used per-request to avoid
+// redoing expensive validation checks.
+// Note that, if a profile is modified and saved during the course of the
+// PaymentRequest, it is important to call the Invalidate method to ensure
+// it is properly evaluated.
+class PaymentsProfileComparator : public autofill::AutofillProfileComparator {
+ public:
+  // Bitmask of potentially-required fields used in evaluating completeness.
+  using ProfileFields = uint32_t;
+  const static ProfileFields kName = 1 << 0;
+  const static ProfileFields kPhone = 1 << 1;
+  const static ProfileFields kEmail = 1 << 2;
+  const static ProfileFields kAddress = 1 << 3;
+
+  PaymentsProfileComparator(const std::string& app_locale,
+                            const PaymentOptionsProvider& options);
+  ~PaymentsProfileComparator();
+
+  // Returns a bitmask indicating which fields (or groups of fields) on this
+  // profile are not complete and valid.
+  ProfileFields GetMissingProfileFields(
+      const autofill::AutofillProfile* profile) const;
+
+  // Returns profiles for contact info, ordered by completeness and
+  // deduplicated. |profiles| should be passed in order of frecency, and this
+  // order will be preserved among equally-complete profiles. Deduplication here
+  // means that profiles returned are excluded if they are a subset of a more
+  // complete or more frecent profile. Completeness here refers only to the
+  // presence of the fields requested per the request_payer_* fields in
+  // |options|.
+  std::vector<autofill::AutofillProfile*> FilterProfilesForContact(
+      const std::vector<autofill::AutofillProfile*>& profiles) const;
+
+  // Returns true iff all of the contact info in |sub| also appears in |super|.
+  // Only operates on fields requested in |options|.
+  bool IsContactEqualOrSuperset(const autofill::AutofillProfile& super,
+                                const autofill::AutofillProfile& sub) const;
+
+  // Returns the number of contact fields requested in |options| which are
+  // nonempty in |profile|.
+  int GetContactCompletenessScore(
+      const autofill::AutofillProfile* profile) const;
+
+  // Returns true iff every contact field requested in |options| is nonempty in
+  // |profile|.
+  bool IsContactInfoComplete(const autofill::AutofillProfile* profile) const;
+
+  // Comparison function suitable for sorting profiles by contact completeness
+  // score with std::sort.
+  bool IsContactMoreComplete(const autofill::AutofillProfile* p1,
+                             const autofill::AutofillProfile* p2) const;
+
+  // Returns a localized string to be displayed in UI indicating what action,
+  // if any, must be taken for the given profile to be used as contact info.
+  base::string16 GetStringForMissingContactFields(
+      const autofill::AutofillProfile& profile) const;
+
+  // Returns true iff every field needed to use |profile| as a shipping address
+  // is populated.
+  bool IsShippingComplete(const autofill::AutofillProfile* profile) const;
+
+  // Returns a localized string to be displayed in UI indicating what action,
+  // if any, must be taken for the given profile to be used as a shipping
+  // address.
+  base::string16 GetStringForMissingShippingFields(
+      const autofill::AutofillProfile& profile) const;
+
+  // Clears the cached evaluation result for |profile|. Must be called when a
+  // profile is modified and saved during the course of a PaymentRequest.
+  void Invalidate(const autofill::AutofillProfile& profile);
+
+ private:
+  ProfileFields ComputeMissingFields(
+      const autofill::AutofillProfile& profile) const;
+  ProfileFields GetRequiredProfileFieldsForContact() const;
+  ProfileFields GetRequiredProfileFieldsForShipping() const;
+  base::string16 GetStringForMissingFields(ProfileFields fields) const;
+  bool AreRequiredAddressFieldsPresent(
+      const autofill::AutofillProfile& profile) const;
+  mutable std::map<std::string, ProfileFields> cache_;
+  const PaymentOptionsProvider& options_;
+};
+
+}  // namespace payments
+
+#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENTS_PROFILE_COMPARATOR_H_
\ No newline at end of file
diff --git a/components/payments/core/payments_profile_comparator_unittest.cc b/components/payments/core/payments_profile_comparator_unittest.cc
new file mode 100644
index 0000000..ac0691e
--- /dev/null
+++ b/components/payments/core/payments_profile_comparator_unittest.cc
@@ -0,0 +1,367 @@
+// 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/payments/core/payments_profile_comparator.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/payments/core/payment_options_provider.h"
+#include "components/strings/grit/components_strings.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using autofill::AutofillProfile;
+
+namespace payments {
+
+constexpr uint32_t kRequestPayerName = 1 << 0;
+constexpr uint32_t kRequestPayerEmail = 1 << 1;
+constexpr uint32_t kRequestPayerPhone = 1 << 2;
+constexpr uint32_t kRequestShipping = 1 << 3;
+
+class MockPaymentOptionsProvider : public PaymentOptionsProvider {
+ public:
+  MockPaymentOptionsProvider(uint32_t options) : options_(options) {}
+
+  ~MockPaymentOptionsProvider() override {}
+  bool request_payer_name() const override {
+    return options_ & kRequestPayerName;
+  }
+  bool request_payer_email() const override {
+    return options_ & kRequestPayerEmail;
+  }
+  bool request_payer_phone() const override {
+    return options_ & kRequestPayerPhone;
+  }
+  bool request_shipping() const override { return options_ & kRequestShipping; }
+  PaymentShippingType shipping_type() const override {
+    return PaymentShippingType::SHIPPING;
+  }
+
+ private:
+  uint32_t options_;
+};
+
+AutofillProfile CreateProfileWithContactInfo(const char* name,
+                                             const char* email,
+                                             const char* phone) {
+  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  autofill::test::SetProfileInfo(&profile, name, "", "", email, "", "", "", "",
+                                 "", "", "", phone);
+  return profile;
+}
+
+AutofillProfile CreateProfileWithCompleteAddress(const char* name,
+                                                 const char* phone) {
+  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  autofill::test::SetProfileInfo(&profile, name, "", "", "", "", "123 Fake St.",
+                                 "", "Fakesville", "MN", "54000", "US", phone);
+  return profile;
+}
+
+AutofillProfile CreateProfileWithPartialAddress(const char* name,
+                                                const char* phone) {
+  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  autofill::test::SetProfileInfo(&profile, name, "", "", "", "", "123 Fake St.",
+                                 "", "", "", "54000", "", phone);
+  return profile;
+}
+
+TEST(PaymentRequestProfileUtilTest, FilterProfilesForContact) {
+  // These profiles are subset/equal, so only the first complete one is
+  // included.
+  AutofillProfile exclude_1 =
+      CreateProfileWithContactInfo("Homer", "", "6515553226");
+
+  AutofillProfile exclude_2 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+
+  AutofillProfile include_1 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+
+  AutofillProfile exclude_3 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+
+  // This profile is different, so it should also be included. Since it is
+  // less complete than |include_1|, it will appear after.
+  AutofillProfile include_2 =
+      CreateProfileWithContactInfo("Marge", "marge@simpson.net", "");
+
+  // This profile is different, so it should also be included. Since it is
+  // equally complete with |include_1|, it will appear before |include_2|, but
+  // after |include_1| since order is preserved amongst profiles of equal
+  // completeness.
+  AutofillProfile include_3 = CreateProfileWithContactInfo(
+      "Bart", "eatmyshorts@simpson.net", "6515553226");
+
+  std::vector<AutofillProfile*> profiles = {&exclude_1, &exclude_2, &include_1,
+                                            &exclude_3, &include_2, &include_3};
+
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail |
+                                      kRequestPayerPhone);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  std::vector<AutofillProfile*> filtered =
+      comp.FilterProfilesForContact(profiles);
+
+  ASSERT_EQ(3u, filtered.size());
+  EXPECT_EQ(&include_1, filtered[0]);
+  EXPECT_EQ(&include_3, filtered[1]);
+  EXPECT_EQ(&include_2, filtered[2]);
+
+  // Repeat the filter using a provider set to only request phone numbers.
+  // Under these rules, since all profiles have the same (or no) phone number,
+  // we should only see the first profile with a phone number, |exclude_1|.
+  MockPaymentOptionsProvider phone_only_provider(kRequestPayerPhone);
+  PaymentsProfileComparator phone_only_comp("en-US", phone_only_provider);
+  std::vector<AutofillProfile*> filtered_phones =
+      phone_only_comp.FilterProfilesForContact(profiles);
+  ASSERT_EQ(1u, filtered_phones.size());
+  EXPECT_EQ(&exclude_1, filtered_phones[0]);
+}
+
+TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset) {
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail |
+                                      kRequestPayerPhone);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  AutofillProfile p1 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+
+  // Candidate subset profile is equal.
+  AutofillProfile p2 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2));
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1));
+
+  // Candidate subset profile has non-matching fields.
+  AutofillProfile p3 = CreateProfileWithContactInfo(
+      "Homer", "homer@springfieldnuclear.gov", "6515553226");
+  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p1, p3));
+  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p3, p1));
+
+  // Candidate subset profile is equal, except for missing fields.
+  AutofillProfile p4 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4));
+  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p4, p1));
+
+  // One field is common, but each has a field which the other is missing.
+  AutofillProfile p5 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+  AutofillProfile p6 = CreateProfileWithContactInfo("Homer", "", "6515553226");
+  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p5, p6));
+  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p6, p5));
+}
+
+TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset_WithFieldIgnored) {
+  // Discrepancies in email should be ignored throughout this test.
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  AutofillProfile p1 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+
+  // Candidate subset profile is equal.
+  AutofillProfile p2 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2));
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1));
+
+  // Email fields don't match, but profiles are still equal.
+  AutofillProfile p3 = CreateProfileWithContactInfo(
+      "Homer", "homer@springfieldnuclear.gov", "6515553226");
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p3));
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p3, p1));
+
+  // Profile without an email is mutual subset of profile with an email.
+  AutofillProfile p4 = CreateProfileWithContactInfo("Homer", "", "6515553226");
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4));
+  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p4, p1));
+}
+
+TEST(PaymentRequestProfileUtilTest, GetContactCompletenessScore) {
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  // Two completeness points: One each for name and phone number, but not email
+  // as it was not requested.
+  AutofillProfile p1 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  EXPECT_EQ(2, comp.GetContactCompletenessScore(&p1));
+
+  // One completeness point for name, no points for phone number (missing) or
+  // email (not requested).
+  AutofillProfile p2 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+  EXPECT_EQ(1, comp.GetContactCompletenessScore(&p2));
+
+  // No completeness points, as the only field present was not requested.
+  AutofillProfile p3 =
+      CreateProfileWithContactInfo("", "homer@simpson.net", "");
+  EXPECT_EQ(0, comp.GetContactCompletenessScore(&p3));
+
+  // Null profile returns 0.
+  EXPECT_EQ(0, comp.GetContactCompletenessScore(nullptr));
+}
+
+TEST(PaymentRequestProfileUtilTest, IsContactInfoComplete) {
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  // If name and email are present, return true regardless of the (ignored)
+  // phone value.
+  AutofillProfile p1 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  AutofillProfile p2 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+
+  EXPECT_TRUE(comp.IsContactInfoComplete(&p1));
+  EXPECT_TRUE(comp.IsContactInfoComplete(&p2));
+
+  // If name is not present, return false regardless of the (ignored)
+  // phone value.
+  AutofillProfile p3 =
+      CreateProfileWithContactInfo("", "homer@simpson.net", "6515553226");
+  AutofillProfile p4 =
+      CreateProfileWithContactInfo("", "homer@simpson.net", "");
+
+  EXPECT_FALSE(comp.IsContactInfoComplete(&p3));
+  EXPECT_FALSE(comp.IsContactInfoComplete(&p4));
+
+  // If no fields are requested, any profile (even empty or null) is complete.
+  MockPaymentOptionsProvider empty_provider(0);
+  PaymentsProfileComparator empty_comp("en-US", empty_provider);
+
+  AutofillProfile p5 = CreateProfileWithContactInfo("", "", "");
+
+  EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p1));
+  EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p5));
+  EXPECT_TRUE(empty_comp.IsContactInfoComplete(nullptr));
+}
+
+TEST(PaymentRequestProfileUtilTest, IsShippingComplete) {
+  MockPaymentOptionsProvider provider(kRequestShipping);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  // True if name, phone, and address are all populated.
+  AutofillProfile p1 = CreateProfileWithCompleteAddress("Homer", "6515553226");
+  EXPECT_TRUE(comp.IsShippingComplete(&p1));
+
+  // False if address is partially populated.
+  AutofillProfile p2 = CreateProfileWithPartialAddress("Homer", "6515553226");
+  EXPECT_FALSE(comp.IsShippingComplete(&p2));
+
+  // False if name isn't populated.
+  AutofillProfile p3 = CreateProfileWithCompleteAddress("", "6515553226");
+  EXPECT_FALSE(comp.IsShippingComplete(&p3));
+
+  // False if phone isn't populated.
+  AutofillProfile p4 = CreateProfileWithCompleteAddress("Homer", "");
+  EXPECT_FALSE(comp.IsShippingComplete(&p4));
+
+  // False if only contact info (no address fields) is populated.
+  AutofillProfile p5 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  EXPECT_FALSE(comp.IsShippingComplete(&p5));
+
+  MockPaymentOptionsProvider provider_no_shipping(0);
+  PaymentsProfileComparator comp_no_shipping("en-US", provider_no_shipping);
+  // nullptr is handled correctly: false if shipping requested, true if not.
+  EXPECT_FALSE(comp.IsShippingComplete(nullptr));
+  EXPECT_TRUE(comp_no_shipping.IsShippingComplete(nullptr));
+}
+
+TEST(PaymentRequestProfileUtilTest, GetStringForMissingContactFields) {
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone |
+                                      kRequestPayerEmail | kRequestShipping);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  // No error message for complete profile.
+  AutofillProfile p1 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  EXPECT_TRUE(comp.GetStringForMissingContactFields(p1).empty());
+
+  MockPaymentOptionsProvider provider_no_email(
+      kRequestPayerName | kRequestPayerPhone | kRequestShipping);
+  PaymentsProfileComparator comp_no_email("en-US", provider_no_email);
+
+  // No error message if missing field wasn't required.
+  AutofillProfile p2 = CreateProfileWithContactInfo("Homer", "", "6515553226");
+  EXPECT_TRUE(comp_no_email.GetStringForMissingContactFields(p2).empty());
+
+  // Error message for email address if email address is missing and required.
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_EMAIL_REQUIRED),
+            comp.GetStringForMissingContactFields(p2));
+
+  // Error message for phone number if phone is missing and required.
+  AutofillProfile p3 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED),
+            comp.GetStringForMissingContactFields(p3));
+
+  // Error message for name if name is missing and required.
+  AutofillProfile p4 =
+      CreateProfileWithContactInfo("", "homer@simpson.net", "6515553226");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED),
+            comp.GetStringForMissingContactFields(p4));
+
+  // Generic error message if multiple fields missing.
+  AutofillProfile p5 =
+      CreateProfileWithContactInfo("", "homer@simpson.net", "");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED),
+            comp.GetStringForMissingContactFields(p5));
+}
+
+TEST(PaymentRequestProfileUtilTest, GetStringForMissingShippingFields) {
+  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone |
+                                      kRequestPayerEmail | kRequestShipping);
+  PaymentsProfileComparator comp("en-US", provider);
+
+  // No error message for complete profile.
+  AutofillProfile p1 = CreateProfileWithCompleteAddress("Homer", "6515553226");
+  EXPECT_TRUE(comp.GetStringForMissingShippingFields(p1).empty());
+
+  // Error message for shipping if shipping requested and not present.
+  AutofillProfile p2 =
+      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "6515553226");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS),
+            comp.GetStringForMissingShippingFields(p2));
+
+  // Error message for shipping if shipping requested and only partially
+  // complete.
+  AutofillProfile p3 = CreateProfileWithPartialAddress("Homer", "6515553226");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS),
+            comp.GetStringForMissingShippingFields(p3));
+
+  // Error message for name if name requested and missing.
+  AutofillProfile p4 = CreateProfileWithCompleteAddress("", "6515553226");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED),
+            comp.GetStringForMissingShippingFields(p4));
+
+  // Error message for phone if phone requested and missing.
+  AutofillProfile p5 = CreateProfileWithCompleteAddress("Homer", "");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED),
+            comp.GetStringForMissingShippingFields(p5));
+
+  // Generic error message if multiple fields missing.
+  AutofillProfile p6 = CreateProfileWithContactInfo("", "", "");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED),
+            comp.GetStringForMissingShippingFields(p6));
+
+  MockPaymentOptionsProvider provider_no_shipping(
+      kRequestPayerName | kRequestPayerPhone | kRequestPayerEmail);
+  PaymentsProfileComparator comp_no_shipping("en-US", provider_no_shipping);
+
+  // No error message if everything is missing but shipping wasn't requested.
+  EXPECT_TRUE(comp_no_shipping.GetStringForMissingShippingFields(p6).empty());
+}
+
+}  // namespace payments
diff --git a/components/payments/core/profile_util.cc b/components/payments/core/profile_util.cc
deleted file mode 100644
index c1149c8..0000000
--- a/components/payments/core/profile_util.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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/payments/core/profile_util.h"
-
-#include <algorithm>
-
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "components/payments/core/payment_options_provider.h"
-
-namespace payments {
-namespace profile_util {
-
-std::vector<autofill::AutofillProfile*> FilterProfilesForContact(
-    const std::vector<autofill::AutofillProfile*>& profiles,
-    const std::string& app_locale,
-    const PaymentOptionsProvider& options) {
-  // We will be removing profiles, so we operate on a copy.
-  std::vector<autofill::AutofillProfile*> processed = profiles;
-
-  PaymentsProfileComparator comparator(app_locale, options);
-
-  // Stable sort, since profiles are expected to be passed in frecency order.
-  std::stable_sort(
-      processed.begin(), processed.end(),
-      std::bind(&PaymentsProfileComparator::IsContactMoreComplete, &comparator,
-                std::placeholders::_1, std::placeholders::_2));
-
-  auto it = processed.begin();
-  while (it != processed.end()) {
-    if (comparator.GetContactCompletenessScore(*it) == 0) {
-      // Since profiles are sorted by completeness, this and any further
-      // profiles can be discarded.
-      processed.erase(it, processed.end());
-      break;
-    }
-
-    // Attempt to find a matching element in the vector before the current.
-    // This is quadratic, but the number of elements is generally small
-    // (< 10), so a more complicated algorithm would be overkill.
-    if (std::find_if(processed.begin(), it,
-                     [&](autofill::AutofillProfile* prior) {
-                       return comparator.IsContactEqualOrSuperset(*prior, **it);
-                     }) != it) {
-      // Remove the subset profile. |it| will point to the next element after
-      // erasure.
-      it = processed.erase(it);
-    } else {
-      it++;
-    }
-  }
-
-  return processed;
-}
-
-PaymentsProfileComparator::PaymentsProfileComparator(
-    const std::string& app_locale,
-    const PaymentOptionsProvider& options)
-    : autofill::AutofillProfileComparator(app_locale), options_(options) {}
-
-PaymentsProfileComparator::~PaymentsProfileComparator() {}
-
-bool PaymentsProfileComparator::IsContactEqualOrSuperset(
-    const autofill::AutofillProfile& super,
-    const autofill::AutofillProfile& sub) {
-  if (options_.request_payer_name()) {
-    if (sub.HasInfo(autofill::NAME_FULL) &&
-        !super.HasInfo(autofill::NAME_FULL)) {
-      return false;
-    }
-    if (!HaveMergeableNames(super, sub))
-      return false;
-  }
-  if (options_.request_payer_phone()) {
-    if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) &&
-        !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) {
-      return false;
-    }
-    if (!HaveMergeablePhoneNumbers(super, sub))
-      return false;
-  }
-  if (options_.request_payer_email()) {
-    if (sub.HasInfo(autofill::EMAIL_ADDRESS) &&
-        !super.HasInfo(autofill::EMAIL_ADDRESS)) {
-      return false;
-    }
-    if (!HaveMergeableEmailAddresses(super, sub))
-      return false;
-  }
-  return true;
-}
-
-int PaymentsProfileComparator::GetContactCompletenessScore(
-    const autofill::AutofillProfile* profile) {
-  if (!profile)
-    return 0;
-
-  return (options_.request_payer_name() &&
-          profile->HasInfo(autofill::NAME_FULL)) +
-         (options_.request_payer_phone() &&
-          profile->HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) +
-         (options_.request_payer_email() &&
-          profile->HasInfo(autofill::EMAIL_ADDRESS));
-}
-
-bool PaymentsProfileComparator::IsContactInfoComplete(
-    const autofill::AutofillProfile* profile) {
-  int desired_score = options_.request_payer_name() +
-                      options_.request_payer_phone() +
-                      options_.request_payer_email();
-  return GetContactCompletenessScore(profile) == desired_score;
-}
-
-bool PaymentsProfileComparator::IsContactMoreComplete(
-    const autofill::AutofillProfile* p1,
-    const autofill::AutofillProfile* p2) {
-  return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2);
-}
-
-}  // namespace profile_util
-}  // namespace payments
diff --git a/components/payments/core/profile_util.h b/components/payments/core/profile_util.h
deleted file mode 100644
index 6693fe8..0000000
--- a/components/payments/core/profile_util.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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.
-
-#ifndef COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_
-#define COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_
-
-#include <string>
-#include <vector>
-
-#include "components/autofill/core/browser/autofill_profile_comparator.h"
-
-// Utility functions used for processing and filtering address profiles
-// (AutofillProfile).
-
-namespace autofill {
-class AutofillProfile;
-}  // namespace autofill
-
-namespace payments {
-
-class PaymentOptionsProvider;
-
-namespace profile_util {
-
-// Returns profiles for contact info, ordered by completeness and deduplicated.
-// |profiles| should be passed in order of frecency, and this order will be
-// preserved among equally-complete profiles. Deduplication here means that
-// profiles returned are excluded if they are a subset of a more complete or
-// more frecent profile. Completeness here refers only to the presence of the
-// fields requested per the request_payer_* fields in |options|.
-std::vector<autofill::AutofillProfile*> FilterProfilesForContact(
-    const std::vector<autofill::AutofillProfile*>& profiles,
-    const std::string& app_locale,
-    const PaymentOptionsProvider& options);
-
-// Helper class which evaluates profiles for similarity and completeness.
-class PaymentsProfileComparator : public autofill::AutofillProfileComparator {
- public:
-  PaymentsProfileComparator(const std::string& app_locale,
-                            const PaymentOptionsProvider& options);
-  ~PaymentsProfileComparator();
-
-  // Returns true iff all of the contact info in |sub| also appears in |super|.
-  // Only operates on fields requested in |options|.
-  bool IsContactEqualOrSuperset(const autofill::AutofillProfile& super,
-                                const autofill::AutofillProfile& sub);
-
-  // Returns the number of contact fields requested in |options| which are
-  // nonempty in |profile|.
-  int GetContactCompletenessScore(const autofill::AutofillProfile* profile);
-
-  // Returns true iff every contact field requested in |options| is nonempty in
-  // |profile|.
-  bool IsContactInfoComplete(const autofill::AutofillProfile* profile);
-
-  // Comparison function suitable for sorting profiles by contact completeness
-  // score with std::sort.
-  bool IsContactMoreComplete(const autofill::AutofillProfile* p1,
-                             const autofill::AutofillProfile* p2);
-
- private:
-  const PaymentOptionsProvider& options_;
-};
-
-}  // namespace profile_util
-}  // namespace payments
-
-#endif  // COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_
\ No newline at end of file
diff --git a/components/payments/core/profile_util_unittest.cc b/components/payments/core/profile_util_unittest.cc
deleted file mode 100644
index 5ff1d7e..0000000
--- a/components/payments/core/profile_util_unittest.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-// 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/payments/core/profile_util.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/guid.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/payments/core/payment_options_provider.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using autofill::AutofillProfile;
-
-namespace payments {
-namespace profile_util {
-
-constexpr uint32_t kRequestPayerName = 1 << 0;
-constexpr uint32_t kRequestPayerEmail = 1 << 1;
-constexpr uint32_t kRequestPayerPhone = 1 << 2;
-constexpr uint32_t kRequestShipping = 1 << 3;
-
-class MockPaymentOptionsProvider : public PaymentOptionsProvider {
- public:
-  MockPaymentOptionsProvider(uint32_t options) : options_(options) {}
-
-  ~MockPaymentOptionsProvider() override {}
-  bool request_payer_name() const override {
-    return options_ & kRequestPayerName;
-  }
-  bool request_payer_email() const override {
-    return options_ & kRequestPayerEmail;
-  }
-  bool request_payer_phone() const override {
-    return options_ & kRequestPayerPhone;
-  }
-  bool request_shipping() const override { return options_ & kRequestShipping; }
-  PaymentShippingType shipping_type() const override {
-    return PaymentShippingType::SHIPPING;
-  }
-
- private:
-  uint32_t options_;
-};
-
-AutofillProfile CreateProfileWithContactInfo(const char* name,
-                                             const char* email,
-                                             const char* phone) {
-  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
-  autofill::test::SetProfileInfo(&profile, name, "", "", email, "", "", "", "",
-                                 "", "", "", phone);
-  return profile;
-}
-
-TEST(PaymentRequestProfileUtilTest, FilterProfilesForContact) {
-  // These profiles are subset/equal, so only the first complete one is
-  // included.
-  AutofillProfile exclude_1 =
-      CreateProfileWithContactInfo("Homer", "", "5551234567");
-
-  AutofillProfile exclude_2 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
-
-  AutofillProfile include_1 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-
-  AutofillProfile exclude_3 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-
-  // This profile is different, so it should also be included. Since it is
-  // less complete than |include_1|, it will appear after.
-  AutofillProfile include_2 =
-      CreateProfileWithContactInfo("Marge", "marge@simpson.net", "");
-
-  // This profile is different, so it should also be included. Since it is
-  // equally complete with |include_1|, it will appear before |include_2|, but
-  // after |include_1| since order is preserved amongst profiles of equal
-  // completeness.
-  AutofillProfile include_3 = CreateProfileWithContactInfo(
-      "Bart", "eatmyshorts@simpson.net", "5551234567");
-
-  std::vector<AutofillProfile*> profiles = {&exclude_1, &exclude_2, &include_1,
-                                            &exclude_3, &include_2, &include_3};
-
-  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail |
-                                      kRequestPayerPhone);
-  std::vector<AutofillProfile*> filtered =
-      FilterProfilesForContact(profiles, "en-US", provider);
-
-  ASSERT_EQ(3u, filtered.size());
-  EXPECT_EQ(&include_1, filtered[0]);
-  EXPECT_EQ(&include_3, filtered[1]);
-  EXPECT_EQ(&include_2, filtered[2]);
-
-  // Repeat the filter using a provider set to only request phone numbers.
-  // Under these rules, since all profiles have the same (or no) phone number,
-  // we should only see the first profile with a phone number, |exclude_1|.
-  MockPaymentOptionsProvider phone_only_provider(kRequestPayerPhone);
-  std::vector<AutofillProfile*> filtered_phones =
-      FilterProfilesForContact(profiles, "en-US", phone_only_provider);
-  ASSERT_EQ(1u, filtered_phones.size());
-  EXPECT_EQ(&exclude_1, filtered_phones[0]);
-}
-
-TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset) {
-  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail |
-                                      kRequestPayerPhone);
-  PaymentsProfileComparator comp("en-US", provider);
-
-  AutofillProfile p1 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-
-  // Candidate subset profile is equal.
-  AutofillProfile p2 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2));
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1));
-
-  // Candidate subset profile has non-matching fields.
-  AutofillProfile p3 = CreateProfileWithContactInfo(
-      "Homer", "homer@springfieldnuclear.gov", "5551234567");
-  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p1, p3));
-  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p3, p1));
-
-  // Candidate subset profile is equal, except for missing fields.
-  AutofillProfile p4 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4));
-  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p4, p1));
-
-  // One field is common, but each has a field which the other is missing.
-  AutofillProfile p5 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
-  AutofillProfile p6 = CreateProfileWithContactInfo("Homer", "", "5551234567");
-  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p5, p6));
-  EXPECT_FALSE(comp.IsContactEqualOrSuperset(p6, p5));
-}
-
-TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset_WithFieldIgnored) {
-  // Discrepancies in email should be ignored throughout this test.
-  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone);
-  PaymentsProfileComparator comp("en-US", provider);
-
-  AutofillProfile p1 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-
-  // Candidate subset profile is equal.
-  AutofillProfile p2 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2));
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1));
-
-  // Email fields don't match, but profiles are still equal.
-  AutofillProfile p3 = CreateProfileWithContactInfo(
-      "Homer", "homer@springfieldnuclear.gov", "5551234567");
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p3));
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p3, p1));
-
-  // Profile without an email is mutual subset of profile with an email.
-  AutofillProfile p4 = CreateProfileWithContactInfo("Homer", "", "5551234567");
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4));
-  EXPECT_TRUE(comp.IsContactEqualOrSuperset(p4, p1));
-}
-
-TEST(PaymentRequestProfileUtilTest, GetContactCompletenessScore) {
-  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone);
-  PaymentsProfileComparator comp("en-US", provider);
-
-  // Two completeness points: One each for name and phone number, but not email
-  // as it was not requested.
-  AutofillProfile p1 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-  EXPECT_EQ(2, comp.GetContactCompletenessScore(&p1));
-
-  // One completeness point for name, no points for phone number (missing) or
-  // email (not requested).
-  AutofillProfile p2 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
-  EXPECT_EQ(1, comp.GetContactCompletenessScore(&p2));
-
-  // No completeness points, as the only field present was not requested.
-  AutofillProfile p3 =
-      CreateProfileWithContactInfo("", "homer@simpson.net", "");
-  EXPECT_EQ(0, comp.GetContactCompletenessScore(&p3));
-
-  // Null profile returns 0.
-  EXPECT_EQ(0, comp.GetContactCompletenessScore(nullptr));
-}
-
-TEST(PaymentRequestProfileUtilTest, IsContactInfoComplete) {
-  MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail);
-  PaymentsProfileComparator comp("en-US", provider);
-
-  // If name and email are present, return true regardless of the (ignored)
-  // phone value.
-  AutofillProfile p1 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
-  AutofillProfile p2 =
-      CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
-
-  EXPECT_TRUE(comp.IsContactInfoComplete(&p1));
-  EXPECT_TRUE(comp.IsContactInfoComplete(&p2));
-
-  // If name is not present, return false regardless of the (ignored)
-  // phone value.
-  AutofillProfile p3 =
-      CreateProfileWithContactInfo("", "homer@simpson.net", "5551234567");
-  AutofillProfile p4 =
-      CreateProfileWithContactInfo("", "homer@simpson.net", "");
-
-  EXPECT_FALSE(comp.IsContactInfoComplete(&p3));
-  EXPECT_FALSE(comp.IsContactInfoComplete(&p4));
-
-  // If no fields are requested, any profile (even empty or null) is complete.
-  MockPaymentOptionsProvider empty_provider(0);
-  PaymentsProfileComparator empty_comp("en-US", empty_provider);
-
-  AutofillProfile p5 = CreateProfileWithContactInfo("", "", "");
-
-  EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p1));
-  EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p5));
-  EXPECT_TRUE(empty_comp.IsContactInfoComplete(nullptr));
-}
-
-}  // namespace profile_util
-}  // namespace payments
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm
index 3b9fe0a..784c86a 100644
--- a/ios/chrome/browser/payments/payment_request.mm
+++ b/ios/chrome/browser/payments/payment_request.mm
@@ -11,7 +11,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/payments/core/payment_request_data_util.h"
-#include "components/payments/core/profile_util.h"
+#include "components/payments/core/payments_profile_comparator.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/web/public/payments/payment_request.h"
 
@@ -98,17 +98,20 @@
     contact_profiles_.push_back(&profile_cache_.back());
   }
 
+  payments::PaymentsProfileComparator comparator(
+      GetApplicationContext()->GetApplicationLocale(), *this);
+
   // TODO(crbug.com/602666): Implement deduplication and prioritization rules
   // for shipping profiles.
 
-  contact_profiles_ = payments::profile_util::FilterProfilesForContact(
-      contact_profiles_, GetApplicationContext()->GetApplicationLocale(),
-      *this);
+  contact_profiles_ = comparator.FilterProfilesForContact(contact_profiles_);
 
   if (!shipping_profiles_.empty())
     selected_shipping_profile_ = shipping_profiles_[0];
-  if (!contact_profiles_.empty())
+  if (!contact_profiles_.empty() &&
+      comparator.IsContactInfoComplete(contact_profiles_[0])) {
     selected_contact_profile_ = contact_profiles_[0];
+  }
 }
 
 void PaymentRequest::PopulateCreditCardCache() {
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 959fc43..9ceb4b53 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -6666,6 +6666,13 @@
   SendSensitiveInputVisibility();
 }
 
+CoreProbeSink* Document::GetProbeSink() {
+  LocalFrame* frame = GetFrame();
+  if (!frame && TemplateDocumentHost())
+    frame = TemplateDocumentHost()->GetFrame();
+  return probe::ToCoreProbeSink(frame);
+}
+
 DEFINE_TRACE(Document) {
   visitor->Trace(imports_controller_);
   visitor->Trace(doc_type_);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 177068b..3875843 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -1318,6 +1318,8 @@
   void IncrementPasswordCount();
   void DecrementPasswordCount();
 
+  CoreProbeSink* GetProbeSink() final;
+
  protected:
   Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
 
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h
index 0929c3e..d8b0f58 100644
--- a/third_party/WebKit/Source/core/dom/ExecutionContext.h
+++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -43,14 +43,15 @@
 
 namespace blink {
 
-class SuspendableObject;
 class ConsoleMessage;
+class CoreProbeSink;
 class DOMTimerCoordinator;
 class ErrorEvent;
 class EventQueue;
 class EventTarget;
 class ExecutionContextTask;
 class LocalDOMWindow;
+class SuspendableObject;
 class PublicURLManager;
 class SecurityOrigin;
 class ScriptState;
@@ -181,6 +182,8 @@
   void SetReferrerPolicy(ReferrerPolicy);
   virtual ReferrerPolicy GetReferrerPolicy() const { return referrer_policy_; }
 
+  virtual CoreProbeSink* GetProbeSink() { return nullptr; }
+
  protected:
   ExecutionContext();
   virtual ~ExecutionContext();
diff --git a/third_party/WebKit/Source/core/probe/CoreProbes.cpp b/third_party/WebKit/Source/core/probe/CoreProbes.cpp
index 40fcaf9..fb0477c 100644
--- a/third_party/WebKit/Source/core/probe/CoreProbes.cpp
+++ b/third_party/WebKit/Source/core/probe/CoreProbes.cpp
@@ -41,11 +41,8 @@
 #include "core/inspector/InspectorTraceEvents.h"
 #include "core/inspector/MainThreadDebugger.h"
 #include "core/inspector/ThreadDebugger.h"
-#include "core/inspector/WorkerInspectorController.h"
 #include "core/page/Page.h"
-#include "core/workers/MainThreadWorkletGlobalScope.h"
 #include "core/workers/WorkerGlobalScope.h"
-#include "core/workers/WorkerThread.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/loader/fetch/FetchInitiatorInfo.h"
 
@@ -139,22 +136,5 @@
   DidReceiveResourceResponseButCanceled(frame, loader, identifier, r, resource);
 }
 
-CoreProbeSink* ToCoreProbeSink(WorkerGlobalScope* worker_global_scope) {
-  if (!worker_global_scope)
-    return nullptr;
-  if (WorkerInspectorController* controller =
-          worker_global_scope->GetThread()->GetWorkerInspectorController())
-    return controller->InstrumentingAgents();
-  return nullptr;
-}
-
-CoreProbeSink* ToCoreProbeSinkForNonDocumentContext(ExecutionContext* context) {
-  if (context->IsWorkerGlobalScope())
-    return ToCoreProbeSink(ToWorkerGlobalScope(context));
-  if (context->IsMainThreadWorkletGlobalScope())
-    return ToCoreProbeSink(ToMainThreadWorkletGlobalScope(context)->GetFrame());
-  return nullptr;
-}
-
 }  // namespace probe
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/probe/CoreProbes.h b/third_party/WebKit/Source/core/probe/CoreProbes.h
index c9971199..6a7e26f 100644
--- a/third_party/WebKit/Source/core/probe/CoreProbes.h
+++ b/third_party/WebKit/Source/core/probe/CoreProbes.h
@@ -45,7 +45,6 @@
 class CoreProbeSink;
 class Resource;
 class ThreadDebugger;
-class WorkerGlobalScope;
 
 namespace probe {
 
@@ -66,19 +65,12 @@
 };
 
 // Called from generated instrumentation code.
-CORE_EXPORT CoreProbeSink* ToCoreProbeSink(WorkerGlobalScope*);
-CORE_EXPORT CoreProbeSink* ToCoreProbeSinkForNonDocumentContext(
-    ExecutionContext*);
-
 inline CoreProbeSink* ToCoreProbeSink(LocalFrame* frame) {
   return frame ? frame->InstrumentingAgents() : nullptr;
 }
 
 inline CoreProbeSink* ToCoreProbeSink(Document& document) {
-  LocalFrame* frame = document.GetFrame();
-  if (!frame && document.TemplateDocumentHost())
-    frame = document.TemplateDocumentHost()->GetFrame();
-  return ToCoreProbeSink(frame);
+  return document.GetProbeSink();
 }
 
 inline CoreProbeSink* ToCoreProbeSink(Document* document) {
@@ -86,10 +78,7 @@
 }
 
 inline CoreProbeSink* ToCoreProbeSink(ExecutionContext* context) {
-  if (!context)
-    return nullptr;
-  return context->IsDocument() ? ToCoreProbeSink(*ToDocument(context))
-                               : ToCoreProbeSinkForNonDocumentContext(context);
+  return context ? context->GetProbeSink() : nullptr;
 }
 
 inline CoreProbeSink* ToCoreProbeSink(Node* node) {
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp
index f39eb045..c91165cf 100644
--- a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.cpp
@@ -11,6 +11,7 @@
 #include "core/frame/FrameConsole.h"
 #include "core/frame/LocalFrame.h"
 #include "core/inspector/MainThreadDebugger.h"
+#include "core/probe/CoreProbes.h"
 
 namespace blink {
 
@@ -124,6 +125,10 @@
   MainThreadDebugger::Instance()->ExceptionThrown(this, event);
 }
 
+CoreProbeSink* MainThreadWorkletGlobalScope::GetProbeSink() {
+  return probe::ToCoreProbeSink(GetFrame());
+}
+
 DEFINE_TRACE(MainThreadWorkletGlobalScope) {
   visitor->Trace(loader_map_);
   WorkletGlobalScope::Trace(visitor);
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h
index 8e5552df..6c7887bd 100644
--- a/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/MainThreadWorkletGlobalScope.h
@@ -53,6 +53,7 @@
   // ExecutionContext
   void AddConsoleMessage(ConsoleMessage*) final;
   void ExceptionThrown(ErrorEvent*) final;
+  CoreProbeSink* GetProbeSink() final;
 
   DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index 467e46c..a15ff06 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -39,6 +39,7 @@
 #include "core/frame/DOMTimerCoordinator.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/ConsoleMessageStorage.h"
+#include "core/inspector/WorkerInspectorController.h"
 #include "core/inspector/WorkerThreadDebugger.h"
 #include "core/loader/WorkerFetchContext.h"
 #include "core/loader/WorkerThreadableLoader.h"
@@ -283,6 +284,13 @@
   return event_queue_.Get();
 }
 
+CoreProbeSink* WorkerGlobalScope::GetProbeSink() {
+  if (WorkerInspectorController* controller =
+          GetThread()->GetWorkerInspectorController())
+    return controller->InstrumentingAgents();
+  return nullptr;
+}
+
 bool WorkerGlobalScope::IsSecureContext(String& error_message) const {
   // Until there are APIs that are available in workers and that
   // require a privileged context test that checks ancestors, just do
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index d419218..de61519 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -135,6 +135,8 @@
   WorkerEventQueue* GetEventQueue() const final;
   bool IsSecureContext(String& error_message) const override;
 
+  CoreProbeSink* GetProbeSink() final;
+
   // EventTarget
   ExecutionContext* GetExecutionContext() const final;
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index e14472e3..d849f9e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -9545,6 +9545,35 @@
   </summary>
 </histogram>
 
+<histogram name="Cryptohome.MigrationUI.ConsumedBatteryPercent" units="%">
+  <owner>fukino@chromium.org</owner>
+  <summary>
+    The amount of consumed battery level during cryptohome encryption migration.
+    This is logged when the battery level decreases during migration, and the
+    data is used to check if the minimum battery level required to start
+    migration is appropriate.
+  </summary>
+</histogram>
+
+<histogram name="Cryptohome.MigrationUI.FirstScreen"
+    enum="MigrationUIFirstScreen">
+  <owner>fukino@chromium.org</owner>
+  <summary>
+    The first screen in the encryption migration UI, which is shown when a user
+    attempts to log in to the system and old encryption (eCryptfs) is detected.
+  </summary>
+</histogram>
+
+<histogram name="Cryptohome.MigrationUI.UserChoice"
+    enum="MigrationUIUserChoice">
+  <owner>fukino@chromium.org</owner>
+  <summary>
+    User's choice when the system is ready to migrate encryption. The user can
+    start migration or skip it. It is used to know how many users have skipped
+    migration.
+  </summary>
+</histogram>
+
 <histogram name="Cryptohome.TimeToCompleteDircryptoMigration" units="ms">
   <owner>dspaid@chromium.org</owner>
   <summary>
@@ -105917,6 +105946,17 @@
   <int value="2" label="IPsec"/>
 </enum>
 
+<enum name="MigrationUIFirstScreen" type="int">
+  <int value="0" label="Ready"/>
+  <int value="1" label="Resume"/>
+  <int value="2" label="LowStorage"/>
+</enum>
+
+<enum name="MigrationUIUserChoice" type="int">
+  <int value="0" label="Update"/>
+  <int value="1" label="Skip"/>
+</enum>
+
 <enum name="MissingStartType" type="int">
   <int value="0" label="Nothing missing"/>
   <int value="1" label="Start missing"/>