diff --git a/DEPS b/DEPS
index 6a1eb4b..0c5fa908 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '001e72263fee570f3a4398d58f9222c9d2c4926a',
+  'skia_revision': '0aa492d0f47d7becbd87c582a61591bdf2d17fa7',
   # 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': 'b7509b51117e3301d494a89add3175ec6d8d381d',
+  'v8_revision': '1c7f221317ca99e415b23c0202d41bb986c6c69a',
   # 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.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'ffbc0d9a08f8443e67965f03dc0ae427c7f8d145',
+  'pdfium_revision': '61a3cb81a298640ec65fc019926a3a46b8cf8617',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6fc5e4196940629dc5227a4bfdeb6db9879bbe3c',
+  'catapult_revision': '26f2e66be57ee956fec3f6535edd60fec853e58e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
index 830e573..a74a004 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
@@ -202,7 +202,7 @@
         switch (viewType) {
             case PROMO_HEADER_VIEW:
                 ViewHolder promoView = mPromoHeaderManager.createHolder(parent);
-                MarginResizer.createWithViewAdapter(promoView.itemView,
+                MarginResizer.createAndAttach(promoView.itemView,
                         mDelegate.getSelectableListLayout().getUiConfig(),
                         parent.getResources().getDimensionPixelSize(
                                 R.dimen.signin_and_sync_view_padding),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
index 68905ab..0e6ce56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -337,7 +337,7 @@
     protected DateViewHolder createDateViewHolder(ViewGroup parent) {
         DateViewHolder viewHolder = super.createDateViewHolder(parent);
         if (mUiConfig != null) {
-            MarginResizer.createWithViewAdapter(viewHolder.itemView, mUiConfig,
+            MarginResizer.createAndAttach(viewHolder.itemView, mUiConfig,
                     parent.getResources().getDimensionPixelSize(R.dimen.list_item_default_margin),
                     SelectableListLayout.getDefaultListItemLateralShadowSizePx(
                             parent.getResources()));
@@ -374,7 +374,7 @@
             mSpaceDisplay = new SpaceDisplay(parent, this);
             registerAdapterDataObserver(mSpaceDisplay);
             if (mUiConfig != null) {
-                MarginResizer.createWithViewAdapter(mSpaceDisplay.getView(), mUiConfig,
+                MarginResizer.createAndAttach(mSpaceDisplay.getView(), mUiConfig,
                         parent.getResources().getDimensionPixelSize(
                                 R.dimen.list_item_default_margin),
                         SelectableListLayout.getDefaultListItemLateralShadowSizePx(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
index e66d00d4..005e639 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
@@ -312,7 +312,7 @@
             }
         });
         mClearBrowsingDataButtonContainer = (FrameLayout) mClearBrowsingDataButton.getParent();
-        MarginResizer.createWithViewAdapter(mClearBrowsingDataButtonContainer,
+        MarginResizer.createAndAttach(mClearBrowsingDataButtonContainer,
                 mHistoryManager.getSelectableListLayout().getUiConfig(),
                 SelectableListLayout.getDefaultListItemLateralMarginPx(resources), 0);
         updateClearBrowsingDataButtonVisibility();
@@ -322,7 +322,7 @@
         mSignedInNotSyncedTextView = (TextView) v.findViewById(R.id.signed_in_not_synced);
         setPrivacyDisclaimerText(mSignedInNotSyncedTextView,
                 R.string.android_history_no_synced_results, LEARN_MORE_LINK);
-        MarginResizer.createWithViewAdapter(mSignedInNotSyncedTextView,
+        MarginResizer.createAndAttach(mSignedInNotSyncedTextView,
                 mHistoryManager.getSelectableListLayout().getUiConfig(),
                 getDefaultTextMargin(resources),
                 SelectableListLayout.getDefaultListItemLateralShadowSizePx(resources));
@@ -330,7 +330,7 @@
         mSignedInSyncedTextView = (TextView) v.findViewById(R.id.signed_in_synced);
         setPrivacyDisclaimerText(mSignedInSyncedTextView,
                 R.string.android_history_has_synced_results, LEARN_MORE_LINK);
-        MarginResizer.createWithViewAdapter(mSignedInSyncedTextView,
+        MarginResizer.createAndAttach(mSignedInSyncedTextView,
                 mHistoryManager.getSelectableListLayout().getUiConfig(),
                 getDefaultTextMargin(resources),
                 SelectableListLayout.getDefaultListItemLateralShadowSizePx(resources));
@@ -343,7 +343,7 @@
         String disclaimerUrl = flagEnabled ? MY_ACTIVITY_LINK : GOOGLE_HISTORY_LINK;
         setPrivacyDisclaimerText(
                 mOtherFormsOfBrowsingHistoryTextView, disclaimerTextId, disclaimerUrl);
-        MarginResizer.createWithViewAdapter(mOtherFormsOfBrowsingHistoryTextView,
+        MarginResizer.createAndAttach(mOtherFormsOfBrowsingHistoryTextView,
                 mHistoryManager.getSelectableListLayout().getUiConfig(),
                 getDefaultTextMargin(resources),
                 SelectableListLayout.getDefaultListItemLateralShadowSizePx(resources));
@@ -362,7 +362,7 @@
     @Override
     protected DateViewHolder createDateViewHolder(ViewGroup parent) {
         DateViewHolder viewHolder = super.createDateViewHolder(parent);
-        MarginResizer.createWithViewAdapter(viewHolder.itemView,
+        MarginResizer.createAndAttach(viewHolder.itemView,
                 mHistoryManager.getSelectableListLayout().getUiConfig(),
                 getDefaultTextMargin(parent.getResources()),
                 SelectableListLayout.getDefaultListItemLateralShadowSizePx(parent.getResources()));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
index ed03b46f..87c284a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
@@ -70,7 +70,7 @@
 
     protected final SuggestionsRecyclerView mRecyclerView;
 
-    private final UiConfig mUiConfig;
+    protected final UiConfig mUiConfig;
     private final MarginResizer mMarginResizer;
 
     /**
@@ -133,8 +133,8 @@
         }
         mWideLateralMargin = resources.getDimensionPixelSize(R.dimen.ntp_wide_card_lateral_margins);
 
-        mMarginResizer = MarginResizer.createWithViewAdapter(itemView, mUiConfig,
-                mDefaultLateralMargin, mWideLateralMargin);
+        mMarginResizer =
+                new MarginResizer(itemView, uiConfig, mDefaultLateralMargin, mWideLateralMargin);
     }
 
     @Override
@@ -198,10 +198,18 @@
         // Make sure we use the right background.
         updateLayoutParams();
 
+        mMarginResizer.attach();
+
         mRecyclerView.onCardBound(this);
     }
 
     @Override
+    public void recycle() {
+        mMarginResizer.detach();
+        super.recycle();
+    }
+
+    @Override
     public void updateLayoutParams() {
         // Nothing to do for dismissed cards.
         if (getAdapterPosition() == RecyclerView.NO_POSITION) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 3200d1b..6b34104 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -279,6 +279,11 @@
         mRecyclerView = (SuggestionsRecyclerView) recyclerView;
     }
 
+    @Override
+    public void onViewRecycled(NewTabPageViewHolder holder) {
+        holder.recycle();
+    }
+
     /**
      * @return the set of item positions that should be dismissed simultaneously when dismissing the
      *         item at the given {@code position} (including the position itself), or an empty set
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageViewHolder.java
index add59f29f..d66418c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageViewHolder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp.cards;
 
+import android.support.annotation.CallSuper;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 
@@ -45,6 +46,13 @@
     public void updateLayoutParams() {
     }
 
+    /**
+     * Called when the view holder is recycled, to release unused resources.
+     * @see NewTabPageAdapter#onViewRecycled(NewTabPageViewHolder)
+     */
+    @CallSuper
+    public void recycle() {}
+
     protected RecyclerView.LayoutParams getParams() {
         return (RecyclerView.LayoutParams) itemView.getLayoutParams();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewHolder.java
index b341ba5d..a11c041 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewHolder.java
@@ -21,6 +21,7 @@
     private static final double SCROLL_HEADER_HEIGHT_PERCENTAGE = 0.7;
 
     private final int mMaxSnippetHeaderHeight;
+    private final MarginResizer mMarginResizer;
 
     public SectionHeaderViewHolder(final SuggestionsRecyclerView recyclerView, UiConfig config) {
         super(LayoutInflater.from(recyclerView.getContext())
@@ -30,13 +31,19 @@
 
         int wideLateralMargin = recyclerView.getResources().getDimensionPixelSize(
                 R.dimen.ntp_wide_card_lateral_margins);
-        MarginResizer.createWithViewAdapter(itemView, config, 0,
-                wideLateralMargin);
+        mMarginResizer = new MarginResizer(itemView, config, 0, wideLateralMargin);
     }
 
     public void onBindViewHolder(SectionHeader header) {
         ((TextView) itemView).setText(header.getHeaderText());
         updateDisplay(0, false);
+        mMarginResizer.attach();
+    }
+
+    @Override
+    public void recycle() {
+        mMarginResizer.detach();
+        super.recycle();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
index af2b514..e99bbcc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -39,12 +39,13 @@
             REFRESH_OFFLINE_BADGE_VISIBILITY_CALLBACK = new RefreshOfflineBadgeVisibilityCallback();
 
     private final SuggestionsUiDelegate mUiDelegate;
-    private final UiConfig mUiConfig;
     private final SuggestionsBinder mSuggestionsBinder;
 
     private SuggestionsCategoryInfo mCategoryInfo;
     private SnippetArticle mArticle;
 
+    private final DisplayStyleObserverAdapter mDisplayStyleObserver;
+
     /**
      * Constructs a {@link SnippetArticleViewHolder} item used to display snippets.
      * @param parent The SuggestionsRecyclerView that is going to contain the newly created view.
@@ -58,16 +59,16 @@
         super(getLayout(), parent, uiConfig, contextMenuManager);
 
         mUiDelegate = uiDelegate;
-        mUiConfig = uiConfig;
         mSuggestionsBinder = new SuggestionsBinder(itemView, uiDelegate);
+        mDisplayStyleObserver =
+                new DisplayStyleObserverAdapter(itemView, uiConfig, new DisplayStyleObserver() {
+                    @Override
+                    public void onDisplayStyleChanged(UiConfig.DisplayStyle newDisplayStyle) {
+                        updateLayout();
+                    }
+                });
 
         new ImpressionTracker(itemView, this);
-        new DisplayStyleObserverAdapter(itemView, uiConfig, new DisplayStyleObserver() {
-            @Override
-            public void onDisplayStyleChanged(UiConfig.DisplayStyle newDisplayStyle) {
-                updateLayout();
-            }
-        });
     }
 
     @Override
@@ -126,11 +127,19 @@
 
         updateLayout();
 
+        mDisplayStyleObserver.attach();
         mSuggestionsBinder.updateViewInformation(mArticle);
 
         refreshOfflineBadgeVisibility();
     }
 
+    @Override
+    public void recycle() {
+        mDisplayStyleObserver.detach();
+        mSuggestionsBinder.recycle();
+        super.recycle();
+    }
+
     /**
      * Updates the layout taking into account screen dimensions and the type of snippet displayed.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
index 9832169..d43e09d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
@@ -30,6 +30,7 @@
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.download.ui.DownloadFilter;
+import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.widget.TintedImageView;
 
@@ -366,4 +367,14 @@
             fadeThumbnailIn(thumbnail);
         }
     }
+
+    /**
+     * Called when the containing view holder is recycled, to release unused resources.
+     * @see NewTabPageViewHolder#recycle()
+     */
+    public void recycle() {
+        // Clear the thumbnail and favicon drawables to allow the bitmap memory to be reclaimed.
+        mThumbnailView.setImageDrawable(null);
+        mPublisherTextView.setCompoundDrawables(null, null, null, null);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/DisplayStyleObserverAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/DisplayStyleObserverAdapter.java
index 5d4b337..ce8c6aeb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/DisplayStyleObserverAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/DisplayStyleObserverAdapter.java
@@ -27,6 +27,8 @@
 
     private boolean mIsViewAttached;
 
+    private final UiConfig mUiConfig;
+
     /**
      * @param view the view whose lifecycle is tracked to determine when to not fire the
      *             observer.
@@ -36,6 +38,7 @@
      *                 window.
      */
     public DisplayStyleObserverAdapter(View view, UiConfig config, DisplayStyleObserver observer) {
+        mUiConfig = config;
         mObserver = observer;
 
         // TODO(dgn): getParent() is not a good way to test that, but isAttachedToWindow()
@@ -43,9 +46,21 @@
         mIsViewAttached = view.getParent() != null;
 
         view.addOnAttachStateChangeListener(this);
+    }
 
-        // This call will also assign the initial value to |mCurrentDisplayStyle|
-        config.addObserver(this);
+    /**
+     * Attaches to the {@link #mUiConfig}.
+     */
+    public void attach() {
+        // This call will also assign the initial value to |mCurrentDisplayStyle|.
+        mUiConfig.addObserver(this);
+    }
+
+    /**
+     * Detaches from the {@link #mUiConfig}.
+     */
+    public void detach() {
+        mUiConfig.removeObserver(this);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/MarginResizer.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/MarginResizer.java
index 31d09bf..501936b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/MarginResizer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/MarginResizer.java
@@ -16,31 +16,51 @@
     /** The wide display value for the lateral margins. */
     private int mWideMarginSizePixels;
     private final View mView;
+    private final DisplayStyleObserverAdapter mDisplayStyleObserver;
 
     @HorizontalDisplayStyle
     private int mCurrentDisplayStyle;
 
     /**
-     * Factory method that creates a {@link MarginResizer} and wraps it in a
-     * {@link DisplayStyleObserverAdapter} that will take care of invoking it when appropriate.
      * @param view The view that will have its margins resized.
      * @param config The UiConfig object to subscribe to.
      * @param defaultMarginPixels Margin size to use in {@link HorizontalDisplayStyle#REGULAR}.
      * @param wideMarginPixels Margin size to use in {@link HorizontalDisplayStyle#WIDE}.
-     * @return The newly created {@link MarginResizer}.
      */
-    public static MarginResizer createWithViewAdapter(View view, UiConfig config,
-            int defaultMarginPixels, int wideMarginPixels) {
-        MarginResizer marginResizer =
-                new MarginResizer(view, defaultMarginPixels, wideMarginPixels);
-        new DisplayStyleObserverAdapter(view, config, marginResizer);
-        return marginResizer;
-    }
-
-    public MarginResizer(View view, int defaultMarginPixels, int wideMarginPixels) {
+    public MarginResizer(
+            View view, UiConfig config, int defaultMarginPixels, int wideMarginPixels) {
         mView = view;
         mDefaultMarginSizePixels = defaultMarginPixels;
         mWideMarginSizePixels = wideMarginPixels;
+        mDisplayStyleObserver = new DisplayStyleObserverAdapter(view, config, this);
+    }
+
+    /**
+     * Convenience method to create a new MarginResizer and immediately attach it to a {@link
+     * UiConfig}. If the {@link UiConfig} can outlive the view, the regular constructor should be
+     * used, so it can be detached to avoid memory leaks.
+     * @param view The view that will have its margins resized.
+     * @param config The UiConfig object to subscribe to.
+     * @param defaultMarginPixels Margin size to use in {@link HorizontalDisplayStyle#REGULAR}.
+     * @param wideMarginPixels Margin size to use in {@link HorizontalDisplayStyle#WIDE}.
+     */
+    public static void createAndAttach(
+            View view, UiConfig config, int defaultMarginPixels, int wideMarginPixels) {
+        new MarginResizer(view, config, defaultMarginPixels, wideMarginPixels).attach();
+    }
+
+    /**
+     * Attaches to the {@link UiConfig}.
+     */
+    public void attach() {
+        mDisplayStyleObserver.attach();
+    }
+
+    /**
+     * Detaches from the {@link UiConfig}.
+     */
+    public void detach() {
+        mDisplayStyleObserver.detach();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/UiConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/UiConfig.java
index 5aa23d6..590b6dee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/UiConfig.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/displaystyle/UiConfig.java
@@ -54,11 +54,21 @@
      * display style.
      */
     public void addObserver(DisplayStyleObserver observer) {
+        assert !mObservers.contains(observer);
         mObservers.add(observer);
         observer.onDisplayStyleChanged(mCurrentDisplayStyle);
     }
 
     /**
+     * Unregisters a previously registered {@link DisplayStyleObserver}.
+     * @param observer The {@link DisplayStyleObserver} to be unregistered.
+     */
+    public void removeObserver(DisplayStyleObserver observer) {
+        boolean success = mObservers.remove(observer);
+        assert success;
+    }
+
+    /**
      * Refresh the display style, notify observers of changes.
      */
     public void updateDisplayStyle() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
index a71a148..f226df58 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
@@ -71,7 +71,7 @@
      * @param uiConfig The UiConfig used to observe display style changes.
      */
     public void configureWideDisplayStyle(UiConfig uiConfig) {
-        MarginResizer.createWithViewAdapter(this, uiConfig,
+        MarginResizer.createAndAttach(this, uiConfig,
                 SelectableListLayout.getDefaultListItemLateralMarginPx(getResources()), 0);
     }
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 0a47df1..de25e2a3 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2613,7 +2613,6 @@
       "android/bottombar/overlay_panel_content.cc",
       "android/bottombar/overlay_panel_content.h",
       "android/browsing_data/browsing_data_bridge.cc",
-      "android/browsing_data/browsing_data_bridge.h",
       "android/browsing_data/browsing_data_counter_bridge.cc",
       "android/browsing_data/browsing_data_counter_bridge.h",
       "android/browsing_data/url_filter_bridge.cc",
@@ -2628,8 +2627,6 @@
       "android/chrome_context_util.h",
       "android/chrome_feature_list.cc",
       "android/chrome_feature_list.h",
-      "android/chrome_jni_registrar.cc",
-      "android/chrome_jni_registrar.h",
       "android/chrome_startup_flags.cc",
       "android/chrome_startup_flags.h",
       "android/compositor/compositor_view.cc",
@@ -2698,7 +2695,6 @@
       "android/data_usage/data_use_tab_model.cc",
       "android/data_usage/data_use_tab_model.h",
       "android/data_usage/data_use_tab_ui_manager_android.cc",
-      "android/data_usage/data_use_tab_ui_manager_android.h",
       "android/data_usage/data_use_ui_tab_model.cc",
       "android/data_usage/data_use_ui_tab_model.h",
       "android/data_usage/data_use_ui_tab_model_factory.cc",
@@ -2737,7 +2733,6 @@
       "android/download/intercept_download_resource_throttle.h",
       "android/download/items/offline_content_aggregator_factory_android.cc",
       "android/download/service/download_background_task.cc",
-      "android/download/service/download_background_task.h",
       "android/download/service/download_task_scheduler.cc",
       "android/download/service/download_task_scheduler.h",
       "android/download/ui/thumbnail_provider.cc",
@@ -2749,9 +2744,7 @@
       "android/feature_utilities.cc",
       "android/feature_utilities.h",
       "android/feedback/connectivity_checker.cc",
-      "android/feedback/connectivity_checker.h",
       "android/feedback/screenshot_task.cc",
-      "android/feedback/screenshot_task.h",
       "android/find_in_page/find_in_page_bridge.cc",
       "android/find_in_page/find_in_page_bridge.h",
       "android/foreign_session_helper.cc",
@@ -2802,13 +2795,11 @@
       "android/logo_service.cc",
       "android/logo_service.h",
       "android/metrics/launch_metrics.cc",
-      "android/metrics/launch_metrics.h",
       "android/metrics/uma_session_stats.cc",
       "android/metrics/uma_session_stats.h",
       "android/metrics/uma_utils.cc",
       "android/metrics/uma_utils.h",
       "android/metrics/variations_session.cc",
-      "android/metrics/variations_session.h",
       "android/mojo/chrome_interface_registrar_android.cc",
       "android/mojo/chrome_interface_registrar_android.h",
       "android/net/external_estimate_provider_android.cc",
@@ -2828,9 +2819,7 @@
       "android/ntp/recent_tabs_page_prefs.cc",
       "android/ntp/recent_tabs_page_prefs.h",
       "android/ntp/suggestions_event_reporter_bridge.cc",
-      "android/ntp/suggestions_event_reporter_bridge.h",
       "android/omnibox/answers_image_bridge.cc",
-      "android/omnibox/answers_image_bridge.h",
       "android/omnibox/autocomplete_controller_android.cc",
       "android/omnibox/autocomplete_controller_android.h",
       "android/omnibox/omnibox_prerender.cc",
@@ -2840,15 +2829,12 @@
       "android/password_ui_view_android.cc",
       "android/password_ui_view_android.h",
       "android/payments/service_worker_payment_app_bridge.cc",
-      "android/payments/service_worker_payment_app_bridge.h",
       "android/physical_web/eddystone_encoder_bridge.cc",
       "android/physical_web/eddystone_encoder_bridge.h",
       "android/physical_web/physical_web_data_source_android.cc",
       "android/physical_web/physical_web_data_source_android.h",
       "android/policy/policy_auditor.cc",
-      "android/policy/policy_auditor.h",
       "android/preferences/autofill/autofill_profile_bridge.cc",
-      "android/preferences/autofill/autofill_profile_bridge.h",
       "android/preferences/browser_prefs_android.cc",
       "android/preferences/browser_prefs_android.h",
       "android/preferences/clipboard_android.cc",
@@ -2858,9 +2844,7 @@
       "android/preferences/preferences_launcher.cc",
       "android/preferences/preferences_launcher.h",
       "android/preferences/website_preference_bridge.cc",
-      "android/preferences/website_preference_bridge.h",
       "android/profiles/profile_downloader_android.cc",
-      "android/profiles/profile_downloader_android.h",
       "android/provider/blocking_ui_thread_async_request.cc",
       "android/provider/blocking_ui_thread_async_request.h",
       "android/provider/bookmark_model_observer_task.cc",
@@ -2869,14 +2853,12 @@
       "android/provider/chrome_browser_provider.h",
       "android/provider/run_on_ui_thread_blocking.h",
       "android/rappor/rappor_service_bridge.cc",
-      "android/rappor/rappor_service_bridge.h",
       "android/recently_closed_tabs_bridge.cc",
       "android/recently_closed_tabs_bridge.h",
       "android/resource_id.h",
       "android/resource_mapper.cc",
       "android/resource_mapper.h",
       "android/rlz/revenue_stats.cc",
-      "android/rlz/revenue_stats.h",
       "android/rlz/rlz_ping_handler.cc",
       "android/rlz/rlz_ping_handler.h",
       "android/search_geolocation/search_geolocation_disclosure_infobar_delegate.cc",
@@ -2890,7 +2872,6 @@
       "android/service_tab_launcher.cc",
       "android/service_tab_launcher.h",
       "android/sessions/session_tab_helper_android.cc",
-      "android/sessions/session_tab_helper_android.h",
       "android/shortcut_helper.cc",
       "android/shortcut_helper.h",
       "android/shortcut_info.cc",
@@ -2898,7 +2879,6 @@
       "android/signin/account_management_screen_helper.cc",
       "android/signin/account_management_screen_helper.h",
       "android/signin/account_tracker_service_android.cc",
-      "android/signin/account_tracker_service_android.h",
       "android/signin/signin_investigator_android.cc",
       "android/signin/signin_investigator_android.h",
       "android/signin/signin_manager_android.cc",
@@ -2917,15 +2897,12 @@
       "android/thumbnail/thumbnail_cache.cc",
       "android/thumbnail/thumbnail_cache.h",
       "android/url_utilities.cc",
-      "android/url_utilities.h",
       "android/usb/web_usb_chooser_service_android.cc",
       "android/usb/web_usb_chooser_service_android.h",
       "android/voice_search_tab_helper.cc",
       "android/voice_search_tab_helper.h",
       "android/warmup_manager.cc",
-      "android/warmup_manager.h",
       "android/web_contents_factory.cc",
-      "android/web_contents_factory.h",
       "android/webapk/chrome_webapk_host.cc",
       "android/webapk/chrome_webapk_host.h",
       "android/webapk/webapk_icon_hasher.cc",
@@ -4270,7 +4247,7 @@
     ":chrome_internal_resources_gen",
     "//chrome/app:chrome_content_manifest_overlays",
     "//chrome/browser/engagement:mojo_bindings_js",
-    "//chrome/browser/media:mojo_bindings__generator",
+    "//chrome/browser/media:mojo_bindings_js",
     "//chrome/browser/ui/webui/omnibox:mojo_bindings_js",
     "//chrome/browser/ui/webui/usb_internals:mojo_bindings_js",
     "//device/bluetooth/public/interfaces:experimental_interfaces_js",
diff --git a/chrome/browser/android/accessibility/font_size_prefs_android.cc b/chrome/browser/android/accessibility/font_size_prefs_android.cc
index f271db4..62fdadc 100644
--- a/chrome/browser/android/accessibility/font_size_prefs_android.cc
+++ b/chrome/browser/android/accessibility/font_size_prefs_android.cc
@@ -58,11 +58,6 @@
   return pref_service_->GetBoolean(prefs::kWebKitForceEnableZoom);
 }
 
-// static
-bool FontSizePrefsAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   FontSizePrefsAndroid* font_size_prefs_android =
       new FontSizePrefsAndroid(env, obj);
diff --git a/chrome/browser/android/accessibility/font_size_prefs_android.h b/chrome/browser/android/accessibility/font_size_prefs_android.h
index 014e4f3..d2732f73 100644
--- a/chrome/browser/android/accessibility/font_size_prefs_android.h
+++ b/chrome/browser/android/accessibility/font_size_prefs_android.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_ACCESSIBILITY_FONT_SIZE_PREFS_ANDROID_H_
 #define CHROME_BROWSER_ANDROID_ACCESSIBILITY_FONT_SIZE_PREFS_ANDROID_H_
 
-#include <jni.h>
-
 #include <memory>
 
 #include "base/android/scoped_java_ref.h"
@@ -35,8 +33,6 @@
   bool GetForceEnableZoom(JNIEnv* env,
                           const base::android::JavaRef<jobject>& obj);
 
-  static bool Register(JNIEnv* env);
-
  private:
   // Callback for FontScaleFactor changes from pref change registrar.
   void OnFontScaleFactorChanged();
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index 797b9b7..6234b7d 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -449,8 +449,4 @@
   return true;
 }
 
-bool RegisterAppBannerInfoBarDelegateAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace banners
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
index 581ae22..b62e5e3 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
@@ -170,9 +170,6 @@
   DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBarDelegateAndroid);
 };
 
-// Register native methods.
-bool RegisterAppBannerInfoBarDelegateAndroid(JNIEnv* env);
-
 }  // namespace banners
 
 #endif  // CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc
index a5c12745..3ac1c62 100644
--- a/chrome/browser/android/banners/app_banner_manager_android.cc
+++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -332,11 +332,6 @@
 }
 
 // static
-bool AppBannerManagerAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 jint GetHomescreenLanguageOption(JNIEnv* env,
                                  const JavaParamRef<jclass>& clazz) {
   return AppBannerSettingsHelper::GetHomescreenLanguageOption();
diff --git a/chrome/browser/android/banners/app_banner_manager_android.h b/chrome/browser/android/banners/app_banner_manager_android.h
index e442309..21f6ab9 100644
--- a/chrome/browser/android/banners/app_banner_manager_android.h
+++ b/chrome/browser/android/banners/app_banner_manager_android.h
@@ -69,9 +69,6 @@
   // AppBannerManager overrides.
   void RequestAppBanner(const GURL& validated_url, bool is_debug_mode) override;
 
-  // Registers native methods.
-  static bool Register(JNIEnv* env);
-
  protected:
   // Return the ideal badge icon size.
   int GetIdealBadgeIconSizeInPx();
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc
index ac4fa92..dd1b163e 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.cc
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc
@@ -130,11 +130,6 @@
   delete this;
 }
 
-// static
-bool BookmarkBridge::RegisterBookmarkBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static jlong Init(JNIEnv* env,
                   const JavaParamRef<jobject>& obj,
                   const JavaParamRef<jobject>& j_profile) {
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h
index 85e6cd2..e3c30f5 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.h
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_BOOKMARKS_BOOKMARK_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_BOOKMARKS_BOOKMARK_BRIDGE_H_
 
-#include <jni.h>
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/compiler_specific.h"
@@ -33,8 +31,6 @@
   BookmarkBridge(JNIEnv* env, jobject obj, jobject j_profile);
   void Destroy(JNIEnv*, const base::android::JavaParamRef<jobject>&);
 
-  static bool RegisterBookmarkBridge(JNIEnv* env);
-
   bool IsDoingExtensiveChanges(JNIEnv* env,
                                const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
index b4509e3..3911754c 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
@@ -200,11 +200,6 @@
   PartnerBookmarksShim::DisablePartnerBookmarksEditing();
 }
 
-// static
-bool PartnerBookmarksReader::RegisterPartnerBookmarksReader(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 // ----------------------------------------------------------------
 
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.h b/chrome/browser/android/bookmarks/partner_bookmarks_reader.h
index ec65524e..f4e3916 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_reader.h
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.h
@@ -40,9 +40,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
-  // JNI registration
-  static bool RegisterPartnerBookmarksReader(JNIEnv* env);
-
  private:
   PartnerBookmarksShim* partner_bookmarks_shim_;
   Profile* profile_;
diff --git a/chrome/browser/android/bottombar/overlay_panel_content.cc b/chrome/browser/android/bottombar/overlay_panel_content.cc
index 667a5656..9b35b4d 100644
--- a/chrome/browser/android/bottombar/overlay_panel_content.cc
+++ b/chrome/browser/android/bottombar/overlay_panel_content.cc
@@ -147,10 +147,6 @@
           env, delegate));
 }
 
-bool RegisterOverlayPanelContent(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   OverlayPanelContent* content = new OverlayPanelContent(env, obj);
   return reinterpret_cast<intptr_t>(content);
diff --git a/chrome/browser/android/bottombar/overlay_panel_content.h b/chrome/browser/android/bottombar/overlay_panel_content.h
index 67357ec..0296eeb 100644
--- a/chrome/browser/android/bottombar/overlay_panel_content.h
+++ b/chrome/browser/android/bottombar/overlay_panel_content.h
@@ -81,6 +81,4 @@
   DISALLOW_COPY_AND_ASSIGN(OverlayPanelContent);
 };
 
-bool RegisterOverlayPanelContent(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_BOTTOMBAR_OVERLAY_PANEL_CONTENT_H_
diff --git a/chrome/browser/android/browsing_data/browsing_data_bridge.cc b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
index f14586a1..2d96cf1d 100644
--- a/chrome/browser/android/browsing_data/browsing_data_bridge.cc
+++ b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/browsing_data/browsing_data_bridge.h"
-
 #include <jni.h>
 #include <stddef.h>
 
@@ -62,10 +60,6 @@
 
 }  // namespace
 
-bool RegisterBrowsingDataBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static void ClearBrowsingData(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/browsing_data/browsing_data_bridge.h b/chrome/browser/android/browsing_data/browsing_data_bridge.h
deleted file mode 100644
index 8c320b6..0000000
--- a/chrome/browser/android/browsing_data/browsing_data_bridge.h
+++ /dev/null
@@ -1,12 +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 CHROME_BROWSER_ANDROID_BROWSING_DATA_BROWSING_DATA_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_BROWSING_DATA_BROWSING_DATA_BRIDGE_H_
-
-#include <jni.h>
-
-bool RegisterBrowsingDataBridge(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_BROWSING_DATA_BROWSING_DATA_BRIDGE_H_
diff --git a/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc b/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc
index 634d172..616747a 100644
--- a/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc
+++ b/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc
@@ -59,11 +59,6 @@
   delete this;
 }
 
-// static
-bool BrowsingDataCounterBridge::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void BrowsingDataCounterBridge::onCounterFinished(
     std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result) {
   JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/android/browsing_data/browsing_data_counter_bridge.h b/chrome/browser/android/browsing_data/browsing_data_counter_bridge.h
index ba6a631..170ff593 100644
--- a/chrome/browser/android/browsing_data/browsing_data_counter_bridge.h
+++ b/chrome/browser/android/browsing_data/browsing_data_counter_bridge.h
@@ -26,8 +26,6 @@
   // Called by the Java counterpart when it is getting garbage collected.
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
-  static bool Register(JNIEnv* env);
-
  private:
   void onCounterFinished(
       std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result);
diff --git a/chrome/browser/android/browsing_data/url_filter_bridge.cc b/chrome/browser/android/browsing_data/url_filter_bridge.cc
index e9a19ad0..d012891 100644
--- a/chrome/browser/android/browsing_data/url_filter_bridge.cc
+++ b/chrome/browser/android/browsing_data/url_filter_bridge.cc
@@ -32,8 +32,3 @@
   GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
   return url_filter_.Run(url);
 }
-
-// static
-bool UrlFilterBridge::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/browsing_data/url_filter_bridge.h b/chrome/browser/android/browsing_data/url_filter_bridge.h
index 650a75c..5177f43f 100644
--- a/chrome/browser/android/browsing_data/url_filter_bridge.h
+++ b/chrome/browser/android/browsing_data/url_filter_bridge.h
@@ -31,9 +31,6 @@
     return j_bridge_;
   }
 
-  // JNI registration.
-  static bool Register(JNIEnv* env);
-
  private:
   // The wrapped native filter.
   base::Callback<bool(const GURL&)> url_filter_;
diff --git a/chrome/browser/android/chrome_application.cc b/chrome/browser/android/chrome_application.cc
index 04bab09..5c4d345 100644
--- a/chrome/browser/android/chrome_application.cc
+++ b/chrome/browser/android/chrome_application.cc
@@ -90,14 +90,3 @@
   std::for_each(loaded_profiles.begin(), loaded_profiles.end(),
                 RemoveSessionCookiesForProfile);
 }
-
-namespace chrome {
-namespace android {
-
-// static
-bool ChromeApplication::RegisterBindings(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-}  // namespace android
-}  // namespace chrome
diff --git a/chrome/browser/android/chrome_application.h b/chrome/browser/android/chrome_application.h
index ea05aad3..18680ff 100644
--- a/chrome/browser/android/chrome_application.h
+++ b/chrome/browser/android/chrome_application.h
@@ -16,9 +16,6 @@
 // provides functions to request browser side actions, such as opening a
 // settings page.
 class ChromeApplication {
- public:
-  static bool RegisterBindings(JNIEnv* env);
-
  private:
   ChromeApplication() {}
   ~ChromeApplication() {}
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 4315806..3117f1a 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -333,9 +333,5 @@
                                                  jdefault_value);
 }
 
-bool RegisterChromeFeatureListJni(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index b2c5bd6..9f2dc387 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -63,8 +63,6 @@
 extern const base::Feature kWebVRCardboardSupport;
 extern const base::Feature kXGEOVisibleNetworks;
 
-bool RegisterChromeFeatureListJni(JNIEnv* env);
-
 }  // namespace android
 }  // namespace chrome
 
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
deleted file mode 100644
index 3dd2e1b..0000000
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright (c) 2012 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 "chrome/browser/android/chrome_jni_registrar.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_registrar.h"
-#include "base/macros.h"
-#include "base/trace_event/trace_event.h"
-#include "chrome/browser/after_startup_task_utils_android.h"
-#include "chrome/browser/android/accessibility/font_size_prefs_android.h"
-#include "chrome/browser/android/banners/app_banner_infobar_delegate_android.h"
-#include "chrome/browser/android/banners/app_banner_manager_android.h"
-#include "chrome/browser/android/bookmarks/bookmark_bridge.h"
-#include "chrome/browser/android/bookmarks/partner_bookmarks_reader.h"
-#include "chrome/browser/android/bottombar/overlay_panel_content.h"
-#include "chrome/browser/android/browsing_data/browsing_data_bridge.h"
-#include "chrome/browser/android/browsing_data/browsing_data_counter_bridge.h"
-#include "chrome/browser/android/browsing_data/url_filter_bridge.h"
-#include "chrome/browser/android/chrome_application.h"
-#include "chrome/browser/android/chrome_backup_agent.h"
-#include "chrome/browser/android/chrome_feature_list.h"
-#include "chrome/browser/android/contextualsearch/contextual_search_context.h"
-#include "chrome/browser/android/contextualsearch/contextual_search_manager.h"
-#include "chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h"
-#include "chrome/browser/android/contextualsearch/contextual_search_tab_helper.h"
-#include "chrome/browser/android/contextualsearch/ctr_suppression.h"
-#include "chrome/browser/android/cookies/cookies_fetcher.h"
-#include "chrome/browser/android/customtabs/origin_verifier.h"
-#include "chrome/browser/android/data_usage/data_use_tab_ui_manager_android.h"
-#include "chrome/browser/android/data_usage/external_data_use_observer_bridge.h"
-#include "chrome/browser/android/devtools_server.h"
-#include "chrome/browser/android/document/document_web_contents_delegate.h"
-#include "chrome/browser/android/dom_distiller/distiller_ui_handle_android.h"
-#include "chrome/browser/android/download/download_controller.h"
-#include "chrome/browser/android/download/download_manager_service.h"
-#include "chrome/browser/android/download/service/download_background_task.h"
-#include "chrome/browser/android/download/ui/thumbnail_provider.h"
-#include "chrome/browser/android/favicon_helper.h"
-#include "chrome/browser/android/feature_engagement_tracker/feature_engagement_tracker_factory_android.h"
-#include "chrome/browser/android/feature_utilities.h"
-#include "chrome/browser/android/feedback/connectivity_checker.h"
-#include "chrome/browser/android/feedback/screenshot_task.h"
-#include "chrome/browser/android/find_in_page/find_in_page_bridge.h"
-#include "chrome/browser/android/foreign_session_helper.h"
-#include "chrome/browser/android/history/browsing_history_bridge.h"
-#include "chrome/browser/android/history_report/history_report_jni_bridge.h"
-#include "chrome/browser/android/instantapps/instant_apps_infobar_delegate.h"
-#include "chrome/browser/android/instantapps/instant_apps_settings.h"
-#include "chrome/browser/android/large_icon_bridge.h"
-#include "chrome/browser/android/locale/locale_manager.h"
-#include "chrome/browser/android/locale/special_locale_handler.h"
-#include "chrome/browser/android/location_settings_impl.h"
-#include "chrome/browser/android/logo_bridge.h"
-#include "chrome/browser/android/metrics/launch_metrics.h"
-#include "chrome/browser/android/metrics/uma_session_stats.h"
-#include "chrome/browser/android/metrics/uma_utils.h"
-#include "chrome/browser/android/metrics/variations_session.h"
-#include "chrome/browser/android/net/external_estimate_provider_android.h"
-#include "chrome/browser/android/ntp/content_suggestions_notification_helper.h"
-#include "chrome/browser/android/ntp/most_visited_sites_bridge.h"
-#include "chrome/browser/android/ntp/ntp_snippets_bridge.h"
-#include "chrome/browser/android/ntp/recent_tabs_page_prefs.h"
-#include "chrome/browser/android/ntp/suggestions_event_reporter_bridge.h"
-#include "chrome/browser/android/offline_pages/background_scheduler_bridge.h"
-#include "chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h"
-#include "chrome/browser/android/offline_pages/offline_page_bridge.h"
-#include "chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h"
-#include "chrome/browser/android/omnibox/answers_image_bridge.h"
-#include "chrome/browser/android/omnibox/autocomplete_controller_android.h"
-#include "chrome/browser/android/omnibox/omnibox_prerender.h"
-#include "chrome/browser/android/password_ui_view_android.h"
-#include "chrome/browser/android/payments/service_worker_payment_app_bridge.h"
-#include "chrome/browser/android/physical_web/eddystone_encoder_bridge.h"
-#include "chrome/browser/android/physical_web/physical_web_data_source_android.h"
-#include "chrome/browser/android/policy/policy_auditor.h"
-#include "chrome/browser/android/preferences/autofill/autofill_profile_bridge.h"
-#include "chrome/browser/android/preferences/pref_service_bridge.h"
-#include "chrome/browser/android/preferences/website_preference_bridge.h"
-#include "chrome/browser/android/profiles/profile_downloader_android.h"
-#include "chrome/browser/android/provider/chrome_browser_provider.h"
-#include "chrome/browser/android/rappor/rappor_service_bridge.h"
-#include "chrome/browser/android/recently_closed_tabs_bridge.h"
-#include "chrome/browser/android/rlz/revenue_stats.h"
-#include "chrome/browser/android/rlz/rlz_ping_handler.h"
-#include "chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h"
-#include "chrome/browser/android/service_tab_launcher.h"
-#include "chrome/browser/android/sessions/session_tab_helper_android.h"
-#include "chrome/browser/android/shortcut_helper.h"
-#include "chrome/browser/android/signin/account_management_screen_helper.h"
-#include "chrome/browser/android/signin/account_tracker_service_android.h"
-#include "chrome/browser/android/signin/signin_investigator_android.h"
-#include "chrome/browser/android/signin/signin_manager_android.h"
-#include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/android/tab_state.h"
-#include "chrome/browser/android/tab_web_contents_delegate_android.h"
-#include "chrome/browser/android/url_utilities.h"
-#include "chrome/browser/android/voice_search_tab_helper.h"
-#include "chrome/browser/android/warmup_manager.h"
-#include "chrome/browser/android/web_contents_factory.h"
-#include "chrome/browser/android/webapk/chrome_webapk_host.h"
-#include "chrome/browser/android/webapk/webapk_installer.h"
-#include "chrome/browser/android/webapk/webapk_update_data_fetcher.h"
-#include "chrome/browser/android/webapk/webapk_update_manager.h"
-#include "chrome/browser/android/webapps/add_to_homescreen_manager.h"
-#include "chrome/browser/autofill/android/personal_data_manager_android.h"
-#include "chrome/browser/autofill/android/phone_number_util_android.h"
-#include "chrome/browser/dom_distiller/dom_distiller_service_factory_android.h"
-#include "chrome/browser/dom_distiller/tab_utils_android.h"
-#include "chrome/browser/engagement/site_engagement_service_android.h"
-#include "chrome/browser/history/android/sqlite_cursor.h"
-#include "chrome/browser/invalidation/invalidation_service_factory_android.h"
-#include "chrome/browser/media/android/cdm/media_drm_credential_manager.h"
-#include "chrome/browser/media/android/remote/record_cast_action.h"
-#include "chrome/browser/media/android/remote/remote_media_player_bridge.h"
-#include "chrome/browser/media/android/router/media_router_android.h"
-#include "chrome/browser/media/android/router/media_router_dialog_controller_android.h"
-#include "chrome/browser/net/spdyproxy/data_reduction_promo_infobar_delegate_android.h"
-#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h"
-#include "chrome/browser/notifications/notification_platform_bridge_android.h"
-#include "chrome/browser/password_manager/account_chooser_dialog_android.h"
-#include "chrome/browser/password_manager/auto_signin_first_run_dialog_android.h"
-#include "chrome/browser/payments/android/chrome_payments_jni_registrar.h"
-#include "chrome/browser/permissions/permission_dialog_delegate.h"
-#include "chrome/browser/permissions/permission_update_infobar_delegate_android.h"
-#include "chrome/browser/predictors/loading_predictor_android.h"
-#include "chrome/browser/prerender/external_prerender_handler_android.h"
-#include "chrome/browser/profiles/profile_android.h"
-#include "chrome/browser/search_engines/template_url_service_android.h"
-#include "chrome/browser/signin/oauth2_token_service_delegate_android.h"
-#include "chrome/browser/speech/tts_android.h"
-#include "chrome/browser/ssl/security_state_model_android.h"
-#include "chrome/browser/supervised_user/child_accounts/child_account_service_android.h"
-#include "chrome/browser/supervised_user/supervised_user_content_provider_android.h"
-#include "chrome/browser/sync/profile_sync_service_android.h"
-#include "chrome/browser/sync/sessions/sync_sessions_metrics_android.h"
-#include "components/feature_engagement_tracker/public/android/feature_engagement_tracker_jni_registrar.h"
-#include "components/offline_pages/features/features.h"
-#include "components/safe_browsing_db/android/jni_registrar.h"
-#include "components/spellcheck/browser/android/component_jni_registrar.h"
-#include "components/spellcheck/spellcheck_build_features.h"
-#include "components/sync/android/sync_jni_registrar.h"
-#include "components/variations/android/component_jni_registrar.h"
-#include "printing/features/features.h"
-
-#if BUILDFLAG(ENABLE_PRINTING) && !BUILDFLAG(ENABLE_PRINT_PREVIEW)
-#include "printing/printing_context_android.h"
-#endif
-
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES_HARNESS)
-#include "chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h"
-#endif
-
-namespace android {
-
-static base::android::RegistrationMethod kChromeRegisteredMethods[] = {
-    // Register JNI for chrome classes.
-    {"AccountChooserDialogAndroid", RegisterAccountChooserDialogAndroid},
-    {"AutoSigninFirstRunDialogAndroid",
-     RegisterAutoSigninFirstRunDialogAndroid},
-    {"AccountManagementScreenHelper", AccountManagementScreenHelper::Register},
-    {"AccountTrackerService", signin::android::RegisterAccountTrackerService},
-    {"AddToHomescreenManager", AddToHomescreenManager::Register},
-    {"AfterStartupTaskUtils", RegisterAfterStartupTaskUtilsJNI},
-    {"AnswersImageBridge", RegisterAnswersImageBridge},
-    {"AppBannerInfoBarDelegateAndroid",
-     banners::RegisterAppBannerInfoBarDelegateAndroid},
-    {"AppBannerManagerAndroid", banners::AppBannerManagerAndroid::Register},
-    {"AutocompleteControllerAndroid", RegisterAutocompleteControllerAndroid},
-    {"AutofillProfileBridge", autofill::RegisterAutofillProfileBridge},
-    {"BackgroundSchedulerBridge",
-     offline_pages::android::RegisterBackgroundSchedulerBridge},
-    {"PrefetchBackgroundTask", offline_pages::RegisterPrefetchBackgroundTask},
-    {"BookmarkBridge", BookmarkBridge::RegisterBookmarkBridge},
-    {"BrowsingDataBridge", RegisterBrowsingDataBridge},
-    {"BrowsingDataCounterBridge", BrowsingDataCounterBridge::Register},
-    {"BrowsingHistoryBridge", RegisterBrowsingHistoryBridge},
-    {"ChildAccountService", RegisterChildAccountService},
-    {"ChromeApplication", chrome::android::ChromeApplication::RegisterBindings},
-    {"ChromeBackupAgent", chrome::android::RegisterBackupAgent},
-    {"ChromeBrowserProvider",
-     ChromeBrowserProvider::RegisterChromeBrowserProvider},
-    {"ChromeFeatureList", chrome::android::RegisterChromeFeatureListJni},
-    {"ChromeMediaRouter", media_router::MediaRouterAndroidBridge::Register},
-    {"ChromeMediaRouterDialogController",
-     media_router::MediaRouterDialogControllerAndroid::Register},
-    {"ChromePayments", payments::android::RegisterChromePayments},
-    {"ChromeWebApkHost", ChromeWebApkHost::Register},
-    {"SecurityStateModel", RegisterSecurityStateModelAndroid},
-    {"ConnectivityChecker", chrome::android::RegisterConnectivityChecker},
-    {"ContentSuggestionsNotificationHelper",
-     ntp_snippets::ContentSuggestionsNotificationHelper::Register},
-    {"ContextualSearchContext", RegisterContextualSearchContext},
-    {"ContextualSearchManager", RegisterContextualSearchManager},
-    {"ContextualSearchRankerLoggerImpl",
-     RegisterContextualSearchRankerLoggerImpl},
-    {"ContextualSearchTabHelper", RegisterContextualSearchTabHelper},
-    {"CookiesFetcher", RegisterCookiesFetcher},
-    {"CtrSuppression", RegisterCtrSuppression},
-    {"DataReductionPromoInfoBarDelegate",
-     DataReductionPromoInfoBarDelegateAndroid::Register},
-    {"DataReductionProxySettings", DataReductionProxySettingsAndroid::Register},
-    {"DataUseTabUIManager", RegisterDataUseTabUIManager},
-    {"DevToolsServer", RegisterDevToolsServer},
-    {"DocumentWebContentsDelegate", DocumentWebContentsDelegate::Register},
-    {"DomDistillerServiceFactory",
-     dom_distiller::android::DomDistillerServiceFactoryAndroid::Register},
-    {"DomDistillerTabUtils", RegisterDomDistillerTabUtils},
-    {"DownloadBackgroundTask",
-     download::android::RegisterDownloadBackgroundTask},
-    {"DownloadController", DownloadController::RegisterDownloadController},
-    {"DownloadManagerService",
-     DownloadManagerService::RegisterDownloadManagerService},
-    {"EddystoneEncoderBridge", RegisterEddystoneEncoderBridge},
-    {"ExternalDataUseObserverBridge",
-     chrome::android::RegisterExternalDataUseObserver},
-    {"ExternalPrerenderRequestHandler",
-     prerender::ExternalPrerenderHandlerAndroid::
-         RegisterExternalPrerenderHandlerAndroid},
-    {"FaviconHelper", FaviconHelper::RegisterFaviconHelper},
-    {"FeatureEngagementTracker",
-     feature_engagement_tracker::RegisterFeatureEngagementTrackerJni},
-    {"FeatureEngagementTrackerFactory",
-     RegisterFeatureEngagementTrackerFactoryJni},
-    {"FeatureUtilities", RegisterFeatureUtilities},
-    {"FindInPageBridge", FindInPageBridge::RegisterFindInPageBridge},
-    {"FontSizePrefsAndroid", FontSizePrefsAndroid::Register},
-    {"ForeignSessionHelper",
-     ForeignSessionHelper::RegisterForeignSessionHelper},
-    {"HistoryReportJniBridge", history_report::RegisterHistoryReportJniBridge},
-    {"InstantAppsInfobarDelegate", RegisterInstantAppsInfoBarDelegate},
-    {"InstantAppsSettings", RegisterInstantAppsSettings},
-    {"InvalidationServiceFactory",
-     invalidation::InvalidationServiceFactoryAndroid::Register},
-    {"LargeIconBridge", LargeIconBridge::RegisterLargeIconBridge},
-    {"LaunchMetrics", metrics::RegisterLaunchMetrics},
-    {"LoadingPredictor", predictors::RegisterLoadingPredictor},
-    {"LocaleManager", RegisterLocaleManager},
-    {"LocationSettingsImpl", LocationSettingsImpl::Register},
-    {"LogoBridge", RegisterLogoBridge},
-    {"MediaDrmCredentialManager",
-     MediaDrmCredentialManager::RegisterMediaDrmCredentialManager},
-    {"MostVisitedSitesBridge", MostVisitedSitesBridge::Register},
-    {"ExternalEstimateProviderAndroid",
-     chrome::android::RegisterExternalEstimateProviderAndroid},
-    {"RecentTabsPagePrefs", RecentTabsPagePrefs::RegisterJni},
-    {"NotificationPlatformBridge",
-     NotificationPlatformBridgeAndroid::RegisterNotificationPlatformBridge},
-    {"NTPSnippetsBridge", NTPSnippetsBridge::Register},
-    {"OAuth2TokenServiceDelegateAndroid",
-     OAuth2TokenServiceDelegateAndroid::Register},
-    {"OfflinePageBridge", offline_pages::android::RegisterOfflinePageBridge},
-    {"OfflinePageDownloadBridge",
-     offline_pages::android::OfflinePageDownloadBridge::Register},
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES_HARNESS)
-    {"OfflinePageEvaluationBridge",
-     offline_pages::android::OfflinePageEvaluationBridge::Register},
-#endif
-    {"OmniboxPrerender", RegisterOmniboxPrerender},
-    {"OriginVerifier", customtabs::RegisterOriginVerifier},
-    {"OverlayPanelContent", RegisterOverlayPanelContent},
-    {"PartnerBookmarksReader",
-     PartnerBookmarksReader::RegisterPartnerBookmarksReader},
-    {"PasswordUIViewAndroid",
-     PasswordUIViewAndroid::RegisterPasswordUIViewAndroid},
-    {"PermissionDialogDelegate",
-     PermissionDialogDelegate::RegisterPermissionDialogDelegate},
-    {"PermissionUpdateInfoBarDelegate",
-     PermissionUpdateInfoBarDelegate::RegisterPermissionUpdateInfoBarDelegate},
-    {"PersonalDataManagerAndroid",
-     autofill::PersonalDataManagerAndroid::Register},
-    {"PhoneNumberUtil", RegisterPhoneNumberUtil},
-    {"PhysicalWebDataSourceAndroid",
-     PhysicalWebDataSourceAndroid::RegisterPhysicalWebDataSource},
-    {"PolicyAuditor", RegisterPolicyAuditor},
-    {"PrefServiceBridge", PrefServiceBridge::RegisterPrefServiceBridge},
-    {"ProfileAndroid", ProfileAndroid::RegisterProfileAndroid},
-    {"ProfileDownloader", RegisterProfileDownloader},
-    {"ProfileSyncService", ProfileSyncServiceAndroid::Register},
-    {"RapporServiceBridge", rappor::RegisterRapporServiceBridge},
-    {"RecentlyClosedBridge", RecentlyClosedTabsBridge::Register},
-    {"RecordCastAction", remote_media::RegisterRecordCastAction},
-    {"RemoteMediaPlayerBridge",
-     remote_media::RemoteMediaPlayerBridge::RegisterRemoteMediaPlayerBridge},
-    {"RevenueStats", chrome::android::RegisterRevenueStats},
-    {"RlzPingHandler", chrome::android::RegisterRlzPingHandler},
-    {"SafeBrowsing", safe_browsing::android::RegisterBrowserJNI},
-    {"ScreenshotTask", chrome::android::RegisterScreenshotTask},
-    {"ServiceTabLauncher", ServiceTabLauncher::Register},
-    {"SearchGeolocationDisclosureTabHelper",
-     SearchGeolocationDisclosureTabHelper::Register},
-    {"ServiceWorkerPaymentAppBridge", RegisterServiceWorkerPaymentAppBridge},
-    {"SessionTabHelper", RegisterSessionTabHelper},
-    {"ShortcutHelper", ShortcutHelper::RegisterShortcutHelper},
-    {"SigninInvestigator", SigninInvestigatorAndroid::Register},
-    {"SigninManager", SigninManagerAndroid::Register},
-    {"SiteEngagementService", SiteEngagementServiceAndroid::Register},
-    {"SpecialLocaleHandler", RegisterSpecialLocaleHandler},
-#if BUILDFLAG(ENABLE_SPELLCHECK)
-    {"SpellCheckerSessionBridge", spellcheck::android::RegisterSpellcheckJni},
-#endif
-    {"SqliteCursor", SQLiteCursor::RegisterSqliteCursor},
-    {"StartupMetricUtils", chrome::android::RegisterStartupMetricUtils},
-    {"SuggestionsEventReporterBridge", RegisterSuggestionsEventReporterBridge},
-    {"SupervisedUserContentProvider", SupervisedUserContentProvider::Register},
-    {"Sync", syncer::RegisterSyncJni},
-    {"SyncSessionsMetrics", SyncSessionsMetricsAndroid::Register},
-    {"TabAndroid", TabAndroid::RegisterTabAndroid},
-    {"TabState", RegisterTabState},
-    {"TabWebContentsDelegateAndroid", RegisterTabWebContentsDelegateAndroid},
-    {"TemplateUrlServiceAndroid", TemplateUrlServiceAndroid::Register},
-    {"ThumbnailProvider", ThumbnailProvider::RegisterThumbnailProvider},
-    {"TtsPlatformImpl", TtsPlatformImplAndroid::Register},
-    {"UmaSessionStats", RegisterUmaSessionStats},
-    {"UrlFilterBridge", UrlFilterBridge::Register},
-    {"UrlUtilities", RegisterUrlUtilities},
-    {"Variations", variations::android::RegisterVariations},
-    {"VariationsSession", chrome::android::RegisterVariationsSession},
-    {"WarmupManager", RegisterWarmupManager},
-    {"WebApkInstaller", WebApkInstaller::Register},
-    {"WebApkUpdateManager", WebApkUpdateManager::Register},
-    {"WebApkUpdateDataFetcher", WebApkUpdateDataFetcher::Register},
-    {"WebContentsFactory", RegisterWebContentsFactory},
-    {"WebsitePreferenceBridge", RegisterWebsitePreferenceBridge},
-#if BUILDFLAG(ENABLE_PRINTING) && !BUILDFLAG(ENABLE_PRINT_PREVIEW)
-    {"PrintingContext",
-     printing::PrintingContextAndroid::RegisterPrintingContext},
-#endif
-};
-
-bool RegisterBrowserJNI(JNIEnv* env) {
-  TRACE_EVENT0("startup", "chrome_android::RegisterJni");
-  return RegisterNativeMethods(env, kChromeRegisteredMethods,
-                               arraysize(kChromeRegisteredMethods));
-}
-
-}  // namespace android
diff --git a/chrome/browser/android/chrome_jni_registrar.h b/chrome/browser/android/chrome_jni_registrar.h
deleted file mode 100644
index 1f36175..0000000
--- a/chrome/browser/android/chrome_jni_registrar.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_ANDROID_CHROME_JNI_REGISTRAR_H_
-#define CHROME_BROWSER_ANDROID_CHROME_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-namespace android {
-
-// Register all JNI bindings necessary for chrome browser process.
-bool RegisterBrowserJNI(JNIEnv* env);
-
-}  // namespace android
-
-#endif  // CHROME_BROWSER_ANDROID_CHROME_JNI_REGISTRAR_H_
diff --git a/chrome/browser/android/compositor/compositor_view.cc b/chrome/browser/android/compositor/compositor_view.cc
index a529608..4114eb9 100644
--- a/chrome/browser/android/compositor/compositor_view.cc
+++ b/chrome/browser/android/compositor/compositor_view.cc
@@ -196,6 +196,7 @@
   if (overlay_video_mode_ == enabled)
     return;
   overlay_video_mode_ = enabled;
+  compositor_->SetRequiresAlphaChannel(enabled);
   compositor_->SetHasTransparentBackground(enabled);
   SetNeedsComposite(env, object);
 }
diff --git a/chrome/browser/android/contextualsearch/contextual_search_context.cc b/chrome/browser/android/contextualsearch/contextual_search_context.cc
index 6910a66..e8304c6d 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_context.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_context.cc
@@ -137,10 +137,6 @@
   delete this;
 }
 
-bool RegisterContextualSearchContext(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 jlong Init(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) {
   ContextualSearchContext* context = new ContextualSearchContext(env, obj);
   return reinterpret_cast<intptr_t>(context);
diff --git a/chrome/browser/android/contextualsearch/contextual_search_context.h b/chrome/browser/android/contextualsearch/contextual_search_context.h
index 3226a97..4d962c0 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_context.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_context.h
@@ -106,6 +106,4 @@
   DISALLOW_COPY_AND_ASSIGN(ContextualSearchContext);
 };
 
-bool RegisterContextualSearchContext(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_CONTEXT_H_
diff --git a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc
index ba3b811..5141f6a3 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc
@@ -77,10 +77,6 @@
   delete this;
 }
 
-bool RegisterContextualSearchRankerLoggerImpl(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 jlong Init(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) {
   ContextualSearchRankerLoggerImpl* ranker_logger_impl =
       new ContextualSearchRankerLoggerImpl(env, obj);
diff --git a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h
index 2561e3a..9eb62519 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h
@@ -64,6 +64,4 @@
   DISALLOW_COPY_AND_ASSIGN(ContextualSearchRankerLoggerImpl);
 };
 
-bool RegisterContextualSearchRankerLoggerImpl(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_RANKER_LOGGER_IMPL_H_
diff --git a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc
index e39a905..229f1a9 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc
@@ -52,7 +52,3 @@
       env, obj, profile);
   return reinterpret_cast<intptr_t>(tab);
 }
-
-bool RegisterContextualSearchTabHelper(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h
index bafbb70..36f7b2c 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_TAB_HELPER_H_
 #define CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_TAB_HELPER_H_
 
-#include <jni.h>
-
 #include <memory>
 
 #include "base/android/jni_weak_ref.h"
@@ -32,6 +30,4 @@
   DISALLOW_COPY_AND_ASSIGN(ContextualSearchTabHelper);
 };
 
-bool RegisterContextualSearchTabHelper(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_TAB_HELPER_H_
diff --git a/chrome/browser/android/contextualsearch/ctr_suppression.cc b/chrome/browser/android/contextualsearch/ctr_suppression.cc
index 91f5cc9..286f125 100644
--- a/chrome/browser/android/contextualsearch/ctr_suppression.cc
+++ b/chrome/browser/android/contextualsearch/ctr_suppression.cc
@@ -99,10 +99,6 @@
   delete this;
 }
 
-bool RegisterCtrSuppression(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   CtrSuppression* suppression = new CtrSuppression(env, obj);
   return reinterpret_cast<intptr_t>(suppression);
diff --git a/chrome/browser/android/contextualsearch/ctr_suppression.h b/chrome/browser/android/contextualsearch/ctr_suppression.h
index 7f7f2ad..906af90 100644
--- a/chrome/browser/android/contextualsearch/ctr_suppression.h
+++ b/chrome/browser/android/contextualsearch/ctr_suppression.h
@@ -64,6 +64,4 @@
   DISALLOW_COPY_AND_ASSIGN(CtrSuppression);
 };
 
-bool RegisterCtrSuppression(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CTR_SUPPRESSION_H_
diff --git a/chrome/browser/android/cookies/cookies_fetcher.cc b/chrome/browser/android/cookies/cookies_fetcher.cc
index 662cf0f..daf74b0 100644
--- a/chrome/browser/android/cookies/cookies_fetcher.cc
+++ b/chrome/browser/android/cookies/cookies_fetcher.cc
@@ -173,8 +173,3 @@
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   return reinterpret_cast<intptr_t>(new CookiesFetcher(env, obj, 0));
 }
-
-// Register native methods
-bool RegisterCookiesFetcher(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/cookies/cookies_fetcher.h b/chrome/browser/android/cookies/cookies_fetcher.h
index f942bb17..cfa87db 100644
--- a/chrome/browser/android/cookies/cookies_fetcher.h
+++ b/chrome/browser/android/cookies/cookies_fetcher.h
@@ -42,7 +42,4 @@
   DISALLOW_COPY_AND_ASSIGN(CookiesFetcher);
 };
 
-// Registers the CookiesFetcher native method.
-bool RegisterCookiesFetcher(JNIEnv* env);
-
 #endif // CHROME_BROWSER_ANDROID_COOKIES_COOKIES_FETCHER_H_
diff --git a/chrome/browser/android/customtabs/origin_verifier.cc b/chrome/browser/android/customtabs/origin_verifier.cc
index e91ede7..979402d 100644
--- a/chrome/browser/android/customtabs/origin_verifier.cc
+++ b/chrome/browser/android/customtabs/origin_verifier.cc
@@ -84,8 +84,4 @@
   return reinterpret_cast<intptr_t>(native_verifier);
 }
 
-bool RegisterOriginVerifier(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace customtabs
diff --git a/chrome/browser/android/customtabs/origin_verifier.h b/chrome/browser/android/customtabs/origin_verifier.h
index ae216af6..4cdbcf12 100644
--- a/chrome/browser/android/customtabs/origin_verifier.h
+++ b/chrome/browser/android/customtabs/origin_verifier.h
@@ -48,7 +48,6 @@
   DISALLOW_COPY_AND_ASSIGN(OriginVerifier);
 };
 
-bool RegisterOriginVerifier(JNIEnv* env);
 }  // namespace customtabs
 
 #endif  // CHROME_BROWSER_ANDROID_CUSTOMTABS_ORIGIN_VERIFIER_H_
diff --git a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
index a96d7db..d306909 100644
--- a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
+++ b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/data_usage/data_use_tab_ui_manager_android.h"
-
 #include <stdint.h>
 #include <string>
 
@@ -187,7 +185,3 @@
              net::NetworkChangeNotifier::GetConnectionType()) &&
          !net::android::GetIsRoaming();
 }
-
-bool RegisterDataUseTabUIManager(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.h b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.h
deleted file mode 100644
index b2444c3..0000000
--- a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_TAB_UI_MANAGER_ANDROID_H_
-#define CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_TAB_UI_MANAGER_ANDROID_H_
-
-#include <jni.h>
-
-// Registers the RegisterDataUseTabUIManager's native methods through JNI.
-bool RegisterDataUseTabUIManager(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_TAB_UI_MANAGER_ANDROID_H_
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc b/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc
index 3ec90ed6..ebcadd96 100644
--- a/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc
+++ b/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc
@@ -230,10 +230,6 @@
   }
 }
 
-bool RegisterExternalDataUseObserver(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 
 }  // namespace chrome
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_bridge.h b/chrome/browser/android/data_usage/external_data_use_observer_bridge.h
index 3d4a0c7..b29513e 100644
--- a/chrome/browser/android/data_usage/external_data_use_observer_bridge.h
+++ b/chrome/browser/android/data_usage/external_data_use_observer_bridge.h
@@ -127,8 +127,6 @@
   DISALLOW_COPY_AND_ASSIGN(ExternalDataUseObserverBridge);
 };
 
-bool RegisterExternalDataUseObserver(JNIEnv* env);
-
 }  // namespace android
 
 }  // namespace chrome
diff --git a/chrome/browser/android/devtools_server.cc b/chrome/browser/android/devtools_server.cc
index 02d29cc..7fa17d7 100644
--- a/chrome/browser/android/devtools_server.cc
+++ b/chrome/browser/android/devtools_server.cc
@@ -170,10 +170,6 @@
   return is_started_;
 }
 
-bool RegisterDevToolsServer(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static jlong InitRemoteDebugging(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/devtools_server.h b/chrome/browser/android/devtools_server.h
index 67fede7..1d6f8e88 100644
--- a/chrome/browser/android/devtools_server.h
+++ b/chrome/browser/android/devtools_server.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_DEVTOOLS_SERVER_H_
 #define CHROME_BROWSER_ANDROID_DEVTOOLS_SERVER_H_
 
-#include <jni.h>
-
 #include <memory>
 #include <string>
 
@@ -33,6 +31,4 @@
   DISALLOW_COPY_AND_ASSIGN(DevToolsServer);
 };
 
-bool RegisterDevToolsServer(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_DEVTOOLS_SERVER_H_
diff --git a/chrome/browser/android/document/document_web_contents_delegate.cc b/chrome/browser/android/document/document_web_contents_delegate.cc
index 19c0001..cd26cb1 100644
--- a/chrome/browser/android/document/document_web_contents_delegate.cc
+++ b/chrome/browser/android/document/document_web_contents_delegate.cc
@@ -27,10 +27,6 @@
   web_contents->SetDelegate(this);
 }
 
-bool DocumentWebContentsDelegate::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void DocumentWebContentsDelegate::AddNewContents(
     content::WebContents* source,
     content::WebContents* new_contents,
diff --git a/chrome/browser/android/document/document_web_contents_delegate.h b/chrome/browser/android/document/document_web_contents_delegate.h
index 6a765d2..bc989ce 100644
--- a/chrome/browser/android/document/document_web_contents_delegate.h
+++ b/chrome/browser/android/document/document_web_contents_delegate.h
@@ -28,9 +28,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jobject>& jweb_contents);
 
-  // Registers the JNI calls.
-  static bool Register(JNIEnv* env);
-
   // Overridden from WebContentsDelegate.
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index 51fe451..df38873 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -173,11 +173,6 @@
 }
 
 // static
-bool DownloadController::RegisterDownloadController(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 DownloadControllerBase* DownloadControllerBase::Get() {
   base::AutoLock lock(g_download_controller_lock_.Get());
   if (!DownloadControllerBase::download_controller_)
diff --git a/chrome/browser/android/download/download_controller.h b/chrome/browser/android/download/download_controller.h
index b426801..9ae33d7 100644
--- a/chrome/browser/android/download/download_controller.h
+++ b/chrome/browser/android/download/download_controller.h
@@ -34,8 +34,6 @@
  public:
   static DownloadController* GetInstance();
 
-  static bool RegisterDownloadController(JNIEnv* env);
-
   // DownloadControllerBase implementation.
   void AcquireFileAccessPermission(
       const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index b99c2295..8c643c3 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -66,11 +66,6 @@
 }  // namespace
 
 // static
-bool DownloadManagerService::RegisterDownloadManagerService(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 void DownloadManagerService::OnDownloadCanceled(
     content::DownloadItem* download,
     DownloadController::DownloadCancelReason reason) {
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h
index 7f241c63..358fb61 100644
--- a/chrome/browser/android/download/download_manager_service.h
+++ b/chrome/browser/android/download/download_manager_service.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_
 #define CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_
 
-#include <jni.h>
 #include <map>
 #include <string>
 
@@ -31,9 +30,6 @@
     : public download::AllDownloadItemNotifier::Observer,
       public DownloadHistory::Observer {
  public:
-  // JNI registration.
-  static bool RegisterDownloadManagerService(JNIEnv* env);
-
   static void OnDownloadCanceled(
       content::DownloadItem* download,
       DownloadController::DownloadCancelReason reason);
diff --git a/chrome/browser/android/download/service/download_background_task.cc b/chrome/browser/android/download/service/download_background_task.cc
index 9ad0bccf..2553462 100644
--- a/chrome/browser/android/download/service/download_background_task.cc
+++ b/chrome/browser/android/download/service/download_background_task.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/download/service/download_background_task.h"
-
 #include "base/android/callback_android.h"
 #include "base/callback_forward.h"
 #include "chrome/browser/download/download_service_factory.h"
@@ -18,11 +16,6 @@
 namespace download {
 namespace android {
 
-// static
-bool RegisterDownloadBackgroundTask(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void CallTaskFinishedCallback(const base::android::JavaRef<jobject>& j_callback,
                               bool needs_reschedule) {
   RunCallbackAndroid(j_callback, needs_reschedule);
diff --git a/chrome/browser/android/download/service/download_background_task.h b/chrome/browser/android/download/service/download_background_task.h
deleted file mode 100644
index 730abf5..0000000
--- a/chrome/browser/android/download/service/download_background_task.h
+++ /dev/null
@@ -1,22 +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 CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_BACKGROUND_TASK_H_
-#define CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_BACKGROUND_TASK_H_
-
-#include <jni.h>
-#include <memory>
-
-#include "base/android/jni_android.h"
-#include "base/macros.h"
-
-namespace download {
-namespace android {
-
-bool RegisterDownloadBackgroundTask(JNIEnv* env);
-
-}  // namespace android
-}  // namespace download
-
-#endif  // CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_BACKGROUND_TASK_H_
diff --git a/chrome/browser/android/download/ui/thumbnail_provider.cc b/chrome/browser/android/download/ui/thumbnail_provider.cc
index 545a8a0..2d2b647 100644
--- a/chrome/browser/android/download/ui/thumbnail_provider.cc
+++ b/chrome/browser/android/download/ui/thumbnail_provider.cc
@@ -161,11 +161,6 @@
 }
 
 // static
-bool ThumbnailProvider::RegisterThumbnailProvider(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) {
   return reinterpret_cast<intptr_t>(new ThumbnailProvider(jobj));
 }
diff --git a/chrome/browser/android/download/ui/thumbnail_provider.h b/chrome/browser/android/download/ui/thumbnail_provider.h
index aa3ea8e0..95ca85af 100644
--- a/chrome/browser/android/download/ui/thumbnail_provider.h
+++ b/chrome/browser/android/download/ui/thumbnail_provider.h
@@ -33,9 +33,6 @@
   void OnThumbnailRetrieved(const std::string& file_path,
                             const SkBitmap& thumbnail);
 
-  // Registers the JNI bindings.
-  static bool RegisterThumbnailProvider(JNIEnv* env);
-
  private:
   ~ThumbnailProvider();
 
diff --git a/chrome/browser/android/favicon_helper.cc b/chrome/browser/android/favicon_helper.cc
index 247962bc..3fec960 100644
--- a/chrome/browser/android/favicon_helper.cc
+++ b/chrome/browser/android/favicon_helper.cc
@@ -263,7 +263,3 @@
       base::Bind(&FaviconHelper::OnFaviconDownloaded, j_availability_callback,
                  profile, page_url, icon_type, is_temporary));
 }
-
-bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/favicon_helper.h b/chrome/browser/android/favicon_helper.h
index 962d1d9..730622a 100644
--- a/chrome/browser/android/favicon_helper.h
+++ b/chrome/browser/android/favicon_helper.h
@@ -49,7 +49,6 @@
       jboolean j_is_large_icon,
       jboolean j_is_temporary,
       const base::android::JavaParamRef<jobject>& j_availability_callback);
-  static bool RegisterFaviconHelper(JNIEnv* env);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(FaviconHelperTest, GetLargestSizeIndex);
diff --git a/chrome/browser/android/feature_utilities.cc b/chrome/browser/android/feature_utilities.cc
index 1fa3bb7..b047649 100644
--- a/chrome/browser/android/feature_utilities.cc
+++ b/chrome/browser/android/feature_utilities.cc
@@ -39,7 +39,3 @@
                                    jboolean j_is_in_multi_window_mode) {
   is_in_multi_window_mode = j_is_in_multi_window_mode;
 }
-
-bool RegisterFeatureUtilities(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/feature_utilities.h b/chrome/browser/android/feature_utilities.h
index c6fe340..287c1a1f 100644
--- a/chrome/browser/android/feature_utilities.h
+++ b/chrome/browser/android/feature_utilities.h
@@ -23,6 +23,4 @@
 } // namespace android
 } // namespace chrome
 
-bool RegisterFeatureUtilities(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_FEATURE_UTILITIES_H_
diff --git a/chrome/browser/android/feedback/connectivity_checker.cc b/chrome/browser/android/feedback/connectivity_checker.cc
index 38d79b7..1b84b28 100644
--- a/chrome/browser/android/feedback/connectivity_checker.cc
+++ b/chrome/browser/android/feedback/connectivity_checker.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/feedback/connectivity_checker.h"
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
@@ -194,9 +192,5 @@
   return url.is_valid();
 }
 
-bool RegisterConnectivityChecker(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/feedback/connectivity_checker.h b/chrome/browser/android/feedback/connectivity_checker.h
deleted file mode 100644
index fe48f06..0000000
--- a/chrome/browser/android/feedback/connectivity_checker.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_FEEDBACK_CONNECTIVITY_CHECKER_H_
-#define CHROME_BROWSER_ANDROID_FEEDBACK_CONNECTIVITY_CHECKER_H_
-
-#include "base/android/jni_android.h"
-
-namespace chrome {
-namespace android {
-
-bool RegisterConnectivityChecker(JNIEnv* env);
-
-}  // namespace android
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_ANDROID_FEEDBACK_CONNECTIVITY_CHECKER_H_
diff --git a/chrome/browser/android/feedback/screenshot_task.cc b/chrome/browser/android/feedback/screenshot_task.cc
index 0381101..f9679df 100644
--- a/chrome/browser/android/feedback/screenshot_task.cc
+++ b/chrome/browser/android/feedback/screenshot_task.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/feedback/screenshot_task.h"
-
 #include <stddef.h>
 
 #include "base/android/scoped_java_ref.h"
@@ -25,10 +23,6 @@
 namespace chrome {
 namespace android {
 
-bool RegisterScreenshotTask(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void SnapshotCallback(JNIEnv* env,
                       const JavaRef<jobject>& callback,
                       scoped_refptr<base::RefCountedMemory> png_data) {
diff --git a/chrome/browser/android/feedback/screenshot_task.h b/chrome/browser/android/feedback/screenshot_task.h
deleted file mode 100644
index 3751f20..0000000
--- a/chrome/browser/android/feedback/screenshot_task.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_FEEDBACK_SCREENSHOT_TASK_H_
-#define CHROME_BROWSER_ANDROID_FEEDBACK_SCREENSHOT_TASK_H_
-
-#include "base/android/jni_android.h"
-
-namespace chrome {
-namespace android {
-
-bool RegisterScreenshotTask(JNIEnv* env);
-
-}  // namespace android
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_ANDROID_FEEDBACK_SCREENSHOT_TASK_H_
diff --git a/chrome/browser/android/find_in_page/find_in_page_bridge.cc b/chrome/browser/android/find_in_page/find_in_page_bridge.cc
index 88d2998..453715c 100644
--- a/chrome/browser/android/find_in_page/find_in_page_bridge.cc
+++ b/chrome/browser/android/find_in_page/find_in_page_bridge.cc
@@ -82,7 +82,3 @@
   FindInPageBridge* bridge = new FindInPageBridge(env, obj, j_web_contents);
   return reinterpret_cast<intptr_t>(bridge);
 }
-
-bool FindInPageBridge::RegisterFindInPageBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/find_in_page/find_in_page_bridge.h b/chrome/browser/android/find_in_page/find_in_page_bridge.h
index 3836c7b..975b545 100644
--- a/chrome/browser/android/find_in_page/find_in_page_bridge.h
+++ b/chrome/browser/android/find_in_page/find_in_page_bridge.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_FIND_IN_PAGE_FIND_IN_PAGE_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_FIND_IN_PAGE_FIND_IN_PAGE_BRIDGE_H_
 
-#include <jni.h>
-
 #include "base/android/jni_weak_ref.h"
 #include "base/macros.h"
 #include "content/public/browser/web_contents.h"
@@ -46,8 +44,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
-  static bool RegisterFindInPageBridge(JNIEnv* env);
-
  private:
   content::WebContents* web_contents_;
   JavaObjectWeakGlobalRef weak_java_ref_;
diff --git a/chrome/browser/android/foreign_session_helper.cc b/chrome/browser/android/foreign_session_helper.cc
index a4177ca..08ebcdbf 100644
--- a/chrome/browser/android/foreign_session_helper.cc
+++ b/chrome/browser/android/foreign_session_helper.cc
@@ -320,8 +320,3 @@
   if (open_tabs)
     open_tabs->DeleteForeignSession(ConvertJavaStringToUTF8(env, session_tag));
 }
-
-// static
-bool ForeignSessionHelper::RegisterForeignSessionHelper(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/foreign_session_helper.h b/chrome/browser/android/foreign_session_helper.h
index 7819bc2..2a13b170 100644
--- a/chrome/browser/android/foreign_session_helper.h
+++ b/chrome/browser/android/foreign_session_helper.h
@@ -51,8 +51,6 @@
   void OnSyncConfigurationCompleted(syncer::SyncService* sync) override;
   void OnForeignSessionUpdated(syncer::SyncService* sync) override;
 
-  static bool RegisterForeignSessionHelper(JNIEnv* env);
-
  private:
   ~ForeignSessionHelper() override;
 
diff --git a/chrome/browser/android/history_report/history_report_jni_bridge.cc b/chrome/browser/android/history_report/history_report_jni_bridge.cc
index 9009662f..bea0664e 100644
--- a/chrome/browser/android/history_report/history_report_jni_bridge.cc
+++ b/chrome/browser/android/history_report/history_report_jni_bridge.cc
@@ -38,10 +38,6 @@
   return reinterpret_cast<intptr_t>(bridge);
 }
 
-bool RegisterHistoryReportJniBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 HistoryReportJniBridge::HistoryReportJniBridge(JNIEnv* env, jobject obj)
     : weak_java_provider_(env, obj) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/android/history_report/history_report_jni_bridge.h b/chrome/browser/android/history_report/history_report_jni_bridge.h
index e93f01d..df596da 100644
--- a/chrome/browser/android/history_report/history_report_jni_bridge.h
+++ b/chrome/browser/android/history_report/history_report_jni_bridge.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_HISTORY_REPORT_HISTORY_REPORT_JNI_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_HISTORY_REPORT_HISTORY_REPORT_JNI_BRIDGE_H_
 
-#include <jni.h>
-
 #include <memory>
 #include <string>
 
@@ -25,8 +23,6 @@
 class DeltaFileService;
 class UsageReportsBufferService;
 
-bool RegisterHistoryReportJniBridge(JNIEnv* env);
-
 class HistoryReportJniBridge {
  public:
   HistoryReportJniBridge(JNIEnv* env, jobject obj);
diff --git a/chrome/browser/android/instantapps/instant_apps_infobar_delegate.cc b/chrome/browser/android/instantapps/instant_apps_infobar_delegate.cc
index a0bad77..626a566 100644
--- a/chrome/browser/android/instantapps/instant_apps_infobar_delegate.cc
+++ b/chrome/browser/android/instantapps/instant_apps_infobar_delegate.cc
@@ -93,7 +93,3 @@
   base::RecordAction(base::UserMetricsAction(
       "Android.InstantApps.BannerShown"));
 }
-
-bool RegisterInstantAppsInfoBarDelegate(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/instantapps/instant_apps_infobar_delegate.h b/chrome/browser/android/instantapps/instant_apps_infobar_delegate.h
index d0b877a..c9933a99 100644
--- a/chrome/browser/android/instantapps/instant_apps_infobar_delegate.h
+++ b/chrome/browser/android/instantapps/instant_apps_infobar_delegate.h
@@ -47,7 +47,4 @@
   DISALLOW_COPY_AND_ASSIGN(InstantAppsInfoBarDelegate);
 };
 
-// Register native methods.
-bool RegisterInstantAppsInfoBarDelegate(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_INSTANTAPPS_INSTANT_APPS_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/android/instantapps/instant_apps_settings.cc b/chrome/browser/android/instantapps/instant_apps_settings.cc
index a9b80d32..78d6730 100644
--- a/chrome/browser/android/instantapps/instant_apps_settings.cc
+++ b/chrome/browser/android/instantapps/instant_apps_settings.cc
@@ -94,7 +94,3 @@
       AppBannerSettingsHelper::kInstantAppsKey,
       base::Time::Now()) == InstallableStatusCode::NO_ERROR_DETECTED;
 }
-
-bool RegisterInstantAppsSettings(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/instantapps/instant_apps_settings.h b/chrome/browser/android/instantapps/instant_apps_settings.h
index e8c393b..ae38e75 100644
--- a/chrome/browser/android/instantapps/instant_apps_settings.h
+++ b/chrome/browser/android/instantapps/instant_apps_settings.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_INSTANTAPPS_INSTANT_APPS_SETTINGS_H_
 #define CHROME_BROWSER_ANDROID_INSTANTAPPS_INSTANT_APPS_SETTINGS_H_
 
-#include <jni.h>
 #include <string>
 #include "base/macros.h"
 
@@ -26,7 +25,4 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(InstantAppsSettings);
 };
 
-// Register native methods.
-bool RegisterInstantAppsSettings(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_INSTANTAPPS_INSTANT_APPS_SETTINGS_H_
diff --git a/chrome/browser/android/large_icon_bridge.cc b/chrome/browser/android/large_icon_bridge.cc
index c5bfc68..4e3e78fc 100644
--- a/chrome/browser/android/large_icon_bridge.cc
+++ b/chrome/browser/android/large_icon_bridge.cc
@@ -99,8 +99,3 @@
 
   return true;
 }
-
-// static
-bool LargeIconBridge::RegisterLargeIconBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/large_icon_bridge.h b/chrome/browser/android/large_icon_bridge.h
index 955c7f7..74c71684 100644
--- a/chrome/browser/android/large_icon_bridge.h
+++ b/chrome/browser/android/large_icon_bridge.h
@@ -26,7 +26,6 @@
       const base::android::JavaParamRef<jstring>& j_page_url,
       jint min_source_size_px,
       const base::android::JavaParamRef<jobject>& j_callback);
-  static bool RegisterLargeIconBridge(JNIEnv* env);
 
  private:
   virtual ~LargeIconBridge();
diff --git a/chrome/browser/android/locale/locale_manager.cc b/chrome/browser/android/locale/locale_manager.cc
index 23767e8f..d2d9ea83 100644
--- a/chrome/browser/android/locale/locale_manager.cc
+++ b/chrome/browser/android/locale/locale_manager.cc
@@ -26,7 +26,3 @@
   GURL url(base::android::ConvertJavaStringToUTF8(env, j_url));
   return TemplateURLPrepopulateData::GetEngineType(url);
 }
-
-bool RegisterLocaleManager(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/locale/locale_manager.h b/chrome/browser/android/locale/locale_manager.h
index f345a16a..792dcf79 100644
--- a/chrome/browser/android/locale/locale_manager.h
+++ b/chrome/browser/android/locale/locale_manager.h
@@ -19,6 +19,4 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(LocaleManager);
 };
 
-bool RegisterLocaleManager(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_LOCALE_LOCALE_MANAGER_H_
diff --git a/chrome/browser/android/locale/special_locale_handler.cc b/chrome/browser/android/locale/special_locale_handler.cc
index 8f26c935..b5ae169 100644
--- a/chrome/browser/android/locale/special_locale_handler.cc
+++ b/chrome/browser/android/locale/special_locale_handler.cc
@@ -144,8 +144,3 @@
 }
 
 SpecialLocaleHandler::~SpecialLocaleHandler() {}
-
-// static
-bool RegisterSpecialLocaleHandler(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/locale/special_locale_handler.h b/chrome/browser/android/locale/special_locale_handler.h
index b2f2738e..2a663bf2e 100644
--- a/chrome/browser/android/locale/special_locale_handler.h
+++ b/chrome/browser/android/locale/special_locale_handler.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_LOCALE_SPECIAL_LOCALE_HANDLER_H_
 #define CHROME_BROWSER_ANDROID_LOCALE_SPECIAL_LOCALE_HANDLER_H_
 
-#include <jni.h>
-
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "components/search_engines/template_url.h"
@@ -49,6 +47,4 @@
   DISALLOW_COPY_AND_ASSIGN(SpecialLocaleHandler);
 };
 
-bool RegisterSpecialLocaleHandler(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_LOCALE_SPECIAL_LOCALE_HANDLER_H_
diff --git a/chrome/browser/android/location_settings_impl.cc b/chrome/browser/android/location_settings_impl.cc
index 63595af..18cec609 100644
--- a/chrome/browser/android/location_settings_impl.cc
+++ b/chrome/browser/android/location_settings_impl.cc
@@ -67,7 +67,3 @@
   // PromptToEnableSystemLocationSetting.
   delete callback;
 }
-
-bool LocationSettingsImpl::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/location_settings_impl.h b/chrome/browser/android/location_settings_impl.h
index c4e4928..97be0928 100644
--- a/chrome/browser/android/location_settings_impl.h
+++ b/chrome/browser/android/location_settings_impl.h
@@ -28,9 +28,6 @@
       content::WebContents* web_contents,
       LocationSettingsDialogOutcomeCallback callback) override;
 
-  // Registers the location settings native methods through JNI.
-  static bool Register(JNIEnv* env);
-
  private:
   DISALLOW_COPY_AND_ASSIGN(LocationSettingsImpl);
 };
diff --git a/chrome/browser/android/logo_bridge.cc b/chrome/browser/android/logo_bridge.cc
index 41804c3..7e40686 100644
--- a/chrome/browser/android/logo_bridge.cc
+++ b/chrome/browser/android/logo_bridge.cc
@@ -214,8 +214,3 @@
   GURL url = GURL(ConvertJavaStringToUTF8(env, j_url));
   animated_logo_fetcher_->Start(env, url, j_callback);
 }
-
-// static
-bool RegisterLogoBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/logo_bridge.h b/chrome/browser/android/logo_bridge.h
index 879b594..7f9489d 100644
--- a/chrome/browser/android/logo_bridge.h
+++ b/chrome/browser/android/logo_bridge.h
@@ -57,6 +57,4 @@
   DISALLOW_COPY_AND_ASSIGN(LogoBridge);
 };
 
-bool RegisterLogoBridge(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_LOGO_BRIDGE_H_
diff --git a/chrome/browser/android/metrics/launch_metrics.cc b/chrome/browser/android/metrics/launch_metrics.cc
index a44f9e32..f9aa5271 100644
--- a/chrome/browser/android/metrics/launch_metrics.cc
+++ b/chrome/browser/android/metrics/launch_metrics.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/metrics/launch_metrics.h"
-
 #include "base/android/jni_string.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
@@ -29,10 +27,6 @@
   HOME_SCREEN_LAUNCH_COUNT = 2
 };
 
-bool RegisterLaunchMetrics(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static void RecordLaunch(JNIEnv* env,
                          const JavaParamRef<jclass>& caller,
                          jboolean standalone,
diff --git a/chrome/browser/android/metrics/launch_metrics.h b/chrome/browser/android/metrics/launch_metrics.h
deleted file mode 100644
index 996af92c..0000000
--- a/chrome/browser/android/metrics/launch_metrics.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2015 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 CHROME_BROWSER_ANDROID_METRICS_LAUNCH_METRICS_H_
-#define CHROME_BROWSER_ANDROID_METRICS_LAUNCH_METRICS_H_
-
-#include "base/android/jni_android.h"
-
-namespace metrics {
-bool RegisterLaunchMetrics(JNIEnv* env);
-}  // namespace metrics
-
-#endif  // CHROME_BROWSER_ANDROID_METRICS_LAUNCH_METRICS_H_
diff --git a/chrome/browser/android/metrics/uma_session_stats.cc b/chrome/browser/android/metrics/uma_session_stats.cc
index bc80487b..f2a557f1 100644
--- a/chrome/browser/android/metrics/uma_session_stats.cc
+++ b/chrome/browser/android/metrics/uma_session_stats.cc
@@ -243,8 +243,3 @@
   g_uma_session_stats = new UmaSessionStats();
   return reinterpret_cast<intptr_t>(g_uma_session_stats);
 }
-
-// Register native methods
-bool RegisterUmaSessionStats(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/metrics/uma_session_stats.h b/chrome/browser/android/metrics/uma_session_stats.h
index 9b20b4b..a2fd9af4 100644
--- a/chrome/browser/android/metrics/uma_session_stats.h
+++ b/chrome/browser/android/metrics/uma_session_stats.h
@@ -43,7 +43,4 @@
   DISALLOW_COPY_AND_ASSIGN(UmaSessionStats);
 };
 
-// Registers the native methods through jni
-bool RegisterUmaSessionStats(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_
diff --git a/chrome/browser/android/metrics/uma_utils.cc b/chrome/browser/android/metrics/uma_utils.cc
index f0d1c2d5e..c294609 100644
--- a/chrome/browser/android/metrics/uma_utils.cc
+++ b/chrome/browser/android/metrics/uma_utils.cc
@@ -41,9 +41,5 @@
                           : metrics::EnableMetricsDefault::OPT_OUT);
 }
 
-bool RegisterStartupMetricUtils(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/metrics/uma_utils.h b/chrome/browser/android/metrics/uma_utils.h
index d455b126..9d03494c 100644
--- a/chrome/browser/android/metrics/uma_utils.h
+++ b/chrome/browser/android/metrics/uma_utils.h
@@ -13,7 +13,6 @@
 namespace android {
 
 base::Time GetMainEntryPointTime();
-bool RegisterStartupMetricUtils(JNIEnv* env);
 
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/metrics/variations_session.cc b/chrome/browser/android/metrics/variations_session.cc
index 406fbee3..8477e35f 100644
--- a/chrome/browser/android/metrics/variations_session.cc
+++ b/chrome/browser/android/metrics/variations_session.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/metrics/variations_session.h"
-
 #include "base/android/jni_string.h"
 #include "chrome/browser/browser_process.h"
 #include "components/variations/service/variations_service.h"
@@ -53,12 +51,3 @@
 
   return base::android::ConvertUTF8ToJavaString(env, latest_country);
 }
-
-namespace chrome {
-namespace android {
-
-// Register native methods
-bool RegisterVariationsSession(JNIEnv* env) { return RegisterNativesImpl(env); }
-
-}  // namespace android
-}  // namespace chrome
diff --git a/chrome/browser/android/metrics/variations_session.h b/chrome/browser/android/metrics/variations_session.h
deleted file mode 100644
index eda210b3..0000000
--- a/chrome/browser/android/metrics/variations_session.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_METRICS_VARIATIONS_SESSION_H_
-#define CHROME_BROWSER_ANDROID_METRICS_VARIATIONS_SESSION_H_
-
-#include <jni.h>
-
-namespace chrome {
-namespace android {
-
-// Registers the native methods through jni.
-bool RegisterVariationsSession(JNIEnv* env);
-
-}  // namespace android
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_ANDROID_METRICS_VARIATIONS_SESSION_H_
diff --git a/chrome/browser/android/net/external_estimate_provider_android.cc b/chrome/browser/android/net/external_estimate_provider_android.cc
index 90a8747..3f51cfa 100644
--- a/chrome/browser/android/net/external_estimate_provider_android.cc
+++ b/chrome/browser/android/net/external_estimate_provider_android.cc
@@ -143,9 +143,5 @@
   }
 }
 
-bool RegisterExternalEstimateProviderAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/net/external_estimate_provider_android.h b/chrome/browser/android/net/external_estimate_provider_android.h
index 69f6aaa..23623dc 100644
--- a/chrome/browser/android/net/external_estimate_provider_android.h
+++ b/chrome/browser/android/net/external_estimate_provider_android.h
@@ -75,8 +75,6 @@
   DISALLOW_COPY_AND_ASSIGN(ExternalEstimateProviderAndroid);
 };
 
-bool RegisterExternalEstimateProviderAndroid(JNIEnv* env);
-
 }  // namespace android
 }  // namespace chrome
 
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
index bb234e0..17e3aa7 100644
--- a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
+++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
@@ -105,11 +105,6 @@
   return ntp_snippets::IsDisabledForProfile(profile);
 }
 
-// static
-bool ContentSuggestionsNotificationHelper::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static void RecordNotificationOptOut(JNIEnv* env,
                                      const JavaParamRef<jclass>& class_object,
                                      jint reason) {
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.h b/chrome/browser/android/ntp/content_suggestions_notification_helper.h
index aea2334..be7b35c 100644
--- a/chrome/browser/android/ntp/content_suggestions_notification_helper.h
+++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.h
@@ -49,9 +49,6 @@
   // that the user is interested in them.
   static bool IsDisabledForProfile(Profile* profile);
 
-  // Registers JNI methods.
-  static bool Register(JNIEnv* env);
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ContentSuggestionsNotificationHelper);
 };
diff --git a/chrome/browser/android/ntp/most_visited_sites_bridge.cc b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
index 3fec5c68..33c590786 100644
--- a/chrome/browser/android/ntp/most_visited_sites_bridge.cc
+++ b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
@@ -260,11 +260,6 @@
                                       static_cast<TileVisualType>(tile_type));
 }
 
-// static
-bool MostVisitedSitesBridge::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static jlong Init(JNIEnv* env,
                   const JavaParamRef<jobject>& obj,
                   const JavaParamRef<jobject>& jprofile) {
diff --git a/chrome/browser/android/ntp/most_visited_sites_bridge.h b/chrome/browser/android/ntp/most_visited_sites_bridge.h
index 3eede8c..8458c79 100644
--- a/chrome/browser/android/ntp/most_visited_sites_bridge.h
+++ b/chrome/browser/android/ntp/most_visited_sites_bridge.h
@@ -58,9 +58,6 @@
       jint tile_type,
       jint source);
 
-  // Registers JNI methods.
-  static bool Register(JNIEnv* env);
-
  private:
   ~MostVisitedSitesBridge();
 
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index 88659629..e4d81ff 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -458,8 +458,3 @@
   RunCallbackAndroid(callback,
                      ToJavaSuggestionList(env, category, suggestions));
 }
-
-// static
-bool NTPSnippetsBridge::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h
index 396ac80..65aa5c99 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.h
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_NTP_NTP_SNIPPETS_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_NTP_NTP_SNIPPETS_BRIDGE_H_
 
-#include <jni.h>
-
 #include "base/android/scoped_java_ref.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
@@ -106,8 +104,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
-  static bool Register(JNIEnv* env);
-
  private:
   ~NTPSnippetsBridge() override;
 
diff --git a/chrome/browser/android/ntp/recent_tabs_page_prefs.cc b/chrome/browser/android/ntp/recent_tabs_page_prefs.cc
index 520ecaab..a5dcedb 100644
--- a/chrome/browser/android/ntp/recent_tabs_page_prefs.cc
+++ b/chrome/browser/android/ntp/recent_tabs_page_prefs.cc
@@ -110,8 +110,3 @@
   registry->RegisterBooleanPref(prefs::kNtpCollapsedSyncPromo, false);
   registry->RegisterDictionaryPref(prefs::kNtpCollapsedForeignSessions);
 }
-
-// static
-bool RecentTabsPagePrefs::RegisterJni(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/ntp/recent_tabs_page_prefs.h b/chrome/browser/android/ntp/recent_tabs_page_prefs.h
index 7c26168d..2ae74c0 100644
--- a/chrome/browser/android/ntp/recent_tabs_page_prefs.h
+++ b/chrome/browser/android/ntp/recent_tabs_page_prefs.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_NTP_RECENT_TABS_PAGE_PREFS_H_
 #define CHROME_BROWSER_ANDROID_NTP_RECENT_TABS_PAGE_PREFS_H_
 
-#include <jni.h>
-
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "chrome/browser/profiles/profile.h"
@@ -49,7 +47,6 @@
       const base::android::JavaParamRef<jstring>& session_tag,
       jboolean is_collapsed);
 
-  static bool RegisterJni(JNIEnv* env);
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
  private:
diff --git a/chrome/browser/android/ntp/suggestions_event_reporter_bridge.cc b/chrome/browser/android/ntp/suggestions_event_reporter_bridge.cc
index db8e76717..0ad24f07 100644
--- a/chrome/browser/android/ntp/suggestions_event_reporter_bridge.cc
+++ b/chrome/browser/android/ntp/suggestions_event_reporter_bridge.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/ntp/suggestions_event_reporter_bridge.h"
-
 #include <jni.h>
 #include <vector>
 
@@ -189,7 +187,3 @@
   }
   scheduler->OnBrowserForegrounded();
 }
-
-bool RegisterSuggestionsEventReporterBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/ntp/suggestions_event_reporter_bridge.h b/chrome/browser/android/ntp/suggestions_event_reporter_bridge.h
deleted file mode 100644
index 9d441dc0..0000000
--- a/chrome/browser/android/ntp/suggestions_event_reporter_bridge.h
+++ /dev/null
@@ -1,16 +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 CHROME_BROWSER_ANDROID_NTP_SUGGESTIONS_EVENT_REPORTER_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_NTP_SUGGESTIONS_EVENT_REPORTER_BRIDGE_H_
-
-#include <jni.h>
-
-// The C++ counterpart to SuggestionsEventReporterBridge.java.
-//
-// It exposes static calls that record metrics and interact with the user
-// classifier
-bool RegisterSuggestionsEventReporterBridge(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_NTP_SUGGESTIONS_EVENT_REPORTER_BRIDGE_H_
diff --git a/chrome/browser/android/offline_pages/background_scheduler_bridge.cc b/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
index 409c14cd8..3804b51 100644
--- a/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
+++ b/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
@@ -131,9 +131,5 @@
   return *device_conditions_;
 }
 
-bool RegisterBackgroundSchedulerBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/background_scheduler_bridge.h b/chrome/browser/android/offline_pages/background_scheduler_bridge.h
index 756cd1d..604cb9a 100644
--- a/chrome/browser/android/offline_pages/background_scheduler_bridge.h
+++ b/chrome/browser/android/offline_pages/background_scheduler_bridge.h
@@ -35,8 +35,6 @@
   std::unique_ptr<DeviceConditions> device_conditions_;
 };
 
-bool RegisterBackgroundSchedulerBridge(JNIEnv* env);
-
 }  // namespace android
 }  // namespace offline_pages
 
diff --git a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
index bf6c1c8..4a661c9 100644
--- a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
+++ b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
@@ -199,11 +199,6 @@
 }
 }  // namespace
 
-// static
-bool OfflinePageEvaluationBridge::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static jlong CreateBridgeForProfile(JNIEnv* env,
                                     const JavaParamRef<jobject>& obj,
                                     const JavaParamRef<jobject>& j_profile,
diff --git a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h
index a56f9cbb..fafff2a 100644
--- a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h
+++ b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_OFFLINE_PAGES_EVALUATION_OFFLINE_PAGE_EVALUATION_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_OFFLINE_PAGES_EVALUATION_OFFLINE_PAGE_EVALUATION_BRIDGE_H_
 
-#include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
@@ -29,8 +28,6 @@
                                     public RequestCoordinator::Observer,
                                     public OfflineEventLogger::Client {
  public:
-  static bool Register(JNIEnv* env);
-
   OfflinePageEvaluationBridge(JNIEnv* env,
                               const base::android::JavaParamRef<jobject>& obj,
                               content::BrowserContext* browser_context,
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc
index 104e5f7..a5cabfd 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.cc
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -724,9 +724,5 @@
       ConvertUTF8ToJavaString(env, client_id.id));
 }
 
-bool RegisterOfflinePageBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.h b/chrome/browser/android/offline_pages/offline_page_bridge.h
index 21283c61..838c6c2 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.h
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.h
@@ -183,8 +183,6 @@
   DISALLOW_COPY_AND_ASSIGN(OfflinePageBridge);
 };
 
-bool RegisterOfflinePageBridge(JNIEnv* env);
-
 }  // namespace android
 }  // namespace offline_pages
 
diff --git a/chrome/browser/android/omnibox/answers_image_bridge.cc b/chrome/browser/android/omnibox/answers_image_bridge.cc
index fa08f54..9e1cb0a 100644
--- a/chrome/browser/android/omnibox/answers_image_bridge.cc
+++ b/chrome/browser/android/omnibox/answers_image_bridge.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/omnibox/answers_image_bridge.h"
-
-#include <jni.h>
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
@@ -79,8 +75,3 @@
       GURL(url), new AnswersImageObserverAndroid(env, java_callback),
       NO_TRAFFIC_ANNOTATION_YET);
 }
-
-// static
-bool RegisterAnswersImageBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/omnibox/answers_image_bridge.h b/chrome/browser/android/omnibox/answers_image_bridge.h
deleted file mode 100644
index 23d75bc..0000000
--- a/chrome/browser/android/omnibox/answers_image_bridge.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2014 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 CHROME_BROWSER_ANDROID_OMNIBOX_ANSWERS_IMAGE_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_OMNIBOX_ANSWERS_IMAGE_BRIDGE_H_
-
-#include <jni.h>
-
-// Registers native methods.
-bool RegisterAnswersImageBridge(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_OMNIBOX_ANSWERS_IMAGE_BRIDGE_H_
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index 9fc6d4a..aced4afd 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -610,8 +610,3 @@
   // ZeroSuggestPrefetcher deletes itself after it's done prefetching.
   new ZeroSuggestPrefetcher(profile);
 }
-
-// Register native methods
-bool RegisterAutocompleteControllerAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.h b/chrome/browser/android/omnibox/autocomplete_controller_android.h
index 9caa74e2..76de477 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.h
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.h
@@ -149,7 +149,4 @@
   DISALLOW_COPY_AND_ASSIGN(AutocompleteControllerAndroid);
 };
 
-// Registers the LocationBar native method.
-bool RegisterAutocompleteControllerAndroid(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_OMNIBOX_AUTOCOMPLETE_CONTROLLER_ANDROID_H_
diff --git a/chrome/browser/android/omnibox/omnibox_prerender.cc b/chrome/browser/android/omnibox/omnibox_prerender.cc
index 5342880..f2dd249 100644
--- a/chrome/browser/android/omnibox/omnibox_prerender.cc
+++ b/chrome/browser/android/omnibox/omnibox_prerender.cc
@@ -33,10 +33,6 @@
   return reinterpret_cast<intptr_t>(omnibox);
 }
 
-bool RegisterOmniboxPrerender(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void OmniboxPrerender::Clear(JNIEnv* env,
                              const JavaParamRef<jobject>& obj,
                              const JavaParamRef<jobject>& j_profile_android) {
diff --git a/chrome/browser/android/omnibox/omnibox_prerender.h b/chrome/browser/android/omnibox/omnibox_prerender.h
index 67eb29a..6248b61 100644
--- a/chrome/browser/android/omnibox/omnibox_prerender.h
+++ b/chrome/browser/android/omnibox/omnibox_prerender.h
@@ -68,6 +68,4 @@
   DISALLOW_COPY_AND_ASSIGN(OmniboxPrerender);
 };
 
-bool RegisterOmniboxPrerender(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_OMNIBOX_OMNIBOX_PRERENDER_H_
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index c5daa6b..d78cc887 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -128,7 +128,3 @@
   PasswordUIViewAndroid* controller = new PasswordUIViewAndroid(env, obj);
   return reinterpret_cast<intptr_t>(controller);
 }
-
-bool PasswordUIViewAndroid::RegisterPasswordUIViewAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/password_ui_view_android.h b/chrome/browser/android/password_ui_view_android.h
index 4154d8d..dd6df57 100644
--- a/chrome/browser/android/password_ui_view_android.h
+++ b/chrome/browser/android/password_ui_view_android.h
@@ -64,9 +64,6 @@
   // Destroy the native implementation.
   void Destroy(JNIEnv*, const base::android::JavaParamRef<jobject>&);
 
-  // JNI registration
-  static bool RegisterPasswordUIViewAndroid(JNIEnv* env);
-
  private:
   PasswordManagerPresenter password_manager_presenter_;
   // Java side of UI controller.
diff --git a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc
index 6ad6b22..ac4edd6 100644
--- a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc
+++ b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/payments/service_worker_payment_app_bridge.h"
-
 #include <utility>
 
 #include "base/android/jni_array.h"
@@ -187,7 +185,3 @@
                  ScopedJavaGlobalRef<jobject>(env, jweb_contents),
                  ScopedJavaGlobalRef<jobject>(env, jcallback)));
 }
-
-bool RegisterServiceWorkerPaymentAppBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/payments/service_worker_payment_app_bridge.h b/chrome/browser/android/payments/service_worker_payment_app_bridge.h
deleted file mode 100644
index e658bcd..0000000
--- a/chrome/browser/android/payments/service_worker_payment_app_bridge.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 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 CHROME_BROWSER_ANDROID_PAYMENTS_SERVICE_WORKER_PAYMENT_APP_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_PAYMENTS_SERVICE_WORKER_PAYMENT_APP_BRIDGE_H_
-
-#include <jni.h>
-
-bool RegisterServiceWorkerPaymentAppBridge(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_PAYMENTS_SERVICE_WORKER_PAYMENT_APP_BRIDGE_H_
diff --git a/chrome/browser/android/physical_web/eddystone_encoder_bridge.cc b/chrome/browser/android/physical_web/eddystone_encoder_bridge.cc
index 09f0283..1a263a8 100644
--- a/chrome/browser/android/physical_web/eddystone_encoder_bridge.cc
+++ b/chrome/browser/android/physical_web/eddystone_encoder_bridge.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/android/physical_web/eddystone_encoder_bridge.h"
 
-#include <jni.h>
 #include <vector>
 
 #include "base/android/jni_android.h"
@@ -13,10 +12,6 @@
 #include "components/physical_web/eddystone/eddystone_encoder.h"
 #include "jni/PhysicalWebBroadcastService_jni.h"
 
-bool RegisterEddystoneEncoderBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static base::android::ScopedJavaLocalRef<jbyteArray> EncodeUrl(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller,
diff --git a/chrome/browser/android/physical_web/eddystone_encoder_bridge.h b/chrome/browser/android/physical_web/eddystone_encoder_bridge.h
index cbfad62..7e410fb 100644
--- a/chrome/browser/android/physical_web/eddystone_encoder_bridge.h
+++ b/chrome/browser/android/physical_web/eddystone_encoder_bridge.h
@@ -5,15 +5,11 @@
 #ifndef CHROME_BROWSER_ANDROID_PHYSICAL_WEB_EDDYSTONE_ENCODER_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_PHYSICAL_WEB_EDDYSTONE_ENCODER_BRIDGE_H_
 
-#include <jni.h>
-
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 
 using base::android::JavaParamRef;
 
-bool RegisterEddystoneEncoderBridge(JNIEnv* env);
-
 base::android::ScopedJavaLocalRef<jbyteArray> EncodeUrlForTesting(
     JNIEnv* env,
     const JavaParamRef<jobject>& jcaller,
diff --git a/chrome/browser/android/policy/policy_auditor.cc b/chrome/browser/android/policy/policy_auditor.cc
index 2b1d69a59..79b04af 100644
--- a/chrome/browser/android/policy/policy_auditor.cc
+++ b/chrome/browser/android/policy/policy_auditor.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/policy/policy_auditor.h"
-
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/ssl_status.h"
@@ -64,7 +62,3 @@
   }
   return NONE;
 }
-
-bool RegisterPolicyAuditor(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/policy/policy_auditor.h b/chrome/browser/android/policy/policy_auditor.h
deleted file mode 100644
index 1864d6b..0000000
--- a/chrome/browser/android/policy/policy_auditor.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 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 CHROME_BROWSER_ANDROID_POLICY_POLICY_AUDITOR_H_
-#define CHROME_BROWSER_ANDROID_POLICY_POLICY_AUDITOR_H_
-
-#include <jni.h>
-
-bool RegisterPolicyAuditor(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_POLICY_POLICY_AUDITOR_H_
diff --git a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
index 5c3e7e5..a2b392af 100644
--- a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
+++ b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/preferences/autofill/autofill_profile_bridge.h"
-
-#include <jni.h>
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
@@ -143,9 +139,4 @@
   return ConvertUTF8ToJavaString(env, best_language_tag);
 }
 
-// static
-bool RegisterAutofillProfileBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 } // namespace autofill
diff --git a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.h b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.h
deleted file mode 100644
index 4b83a021..0000000
--- a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_PREFERENCES_AUTOFILL_AUTOFILL_PROFILE_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_PREFERENCES_AUTOFILL_AUTOFILL_PROFILE_BRIDGE_H_
-
-#include <jni.h>
-
-namespace autofill {
-
-// Registers native methods.
-bool RegisterAutofillProfileBridge(JNIEnv* env);
-
-} // namespace autofill
-
-#endif  // CHROME_BROWSER_ANDROID_PREFERENCES_AUTOFILL_AUTOFILL_PROFILE_BRIDGE_H_
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index 8da39d5..db3f22e 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -921,11 +921,6 @@
 }
 
 // static
-bool PrefServiceBridge::RegisterPrefServiceBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 // This logic should be kept in sync with prependToAcceptLanguagesIfNecessary in
 // chrome/android/java/src/org/chromium/chrome/browser/
 //     physicalweb/PwsClientImpl.java
diff --git a/chrome/browser/android/preferences/pref_service_bridge.h b/chrome/browser/android/preferences/pref_service_bridge.h
index fac21f47..4718f32 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.h
+++ b/chrome/browser/android/preferences/pref_service_bridge.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_PREFERENCES_PREF_SERVICE_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_PREFERENCES_PREF_SERVICE_BRIDGE_H_
 
-#include <jni.h>
 #include <string>
 #include <vector>
 
@@ -13,8 +12,6 @@
 
 class PrefServiceBridge {
  public:
-  static bool RegisterPrefServiceBridge(JNIEnv* env);
-
   // Use |locale| to create a language-region pair and language code to prepend
   // to the default accept languages. For Malay, we'll end up creating
   // "ms-MY,ms,en-US,en", and for Swiss-German, we will have
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index d751493a..fd2e1a3 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/preferences/website_preference_bridge.h"
-
 #include <algorithm>
 #include <string>
 #include <vector>
@@ -847,8 +845,3 @@
   return !!GetHostContentSettingsMap(false)->GetWebsiteSetting(
       url, GURL(), CONTENT_SETTINGS_TYPE_ADS_DATA, std::string(), nullptr);
 }
-
-// Register native methods
-bool RegisterWebsitePreferenceBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/preferences/website_preference_bridge.h b/chrome/browser/android/preferences/website_preference_bridge.h
deleted file mode 100644
index 34b26d8b..0000000
--- a/chrome/browser/android/preferences/website_preference_bridge.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_PREFERENCES_WEBSITE_PREFERENCE_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_PREFERENCES_WEBSITE_PREFERENCE_BRIDGE_H_
-
-#include <jni.h>
-
-bool RegisterWebsitePreferenceBridge(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_PREFERENCES_WEBSITE_PREFERENCE_BRIDGE_H_
diff --git a/chrome/browser/android/profiles/profile_downloader_android.cc b/chrome/browser/android/profiles/profile_downloader_android.cc
index 6df4612f..25eb7b1 100644
--- a/chrome/browser/android/profiles/profile_downloader_android.cc
+++ b/chrome/browser/android/profiles/profile_downloader_android.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/profiles/profile_downloader_android.h"
-
 #include <stddef.h>
 
 #include "base/android/jni_android.h"
@@ -209,8 +207,3 @@
       image_side_pixels, is_pre_signin);
   retriever->Start();
 }
-
-// static
-bool RegisterProfileDownloader(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/profiles/profile_downloader_android.h b/chrome/browser/android/profiles/profile_downloader_android.h
deleted file mode 100644
index c71a2585..0000000
--- a/chrome/browser/android/profiles/profile_downloader_android.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2014 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 CHROME_BROWSER_ANDROID_PROFILES_PROFILE_DOWNLOADER_ANDROID_H_
-#define CHROME_BROWSER_ANDROID_PROFILES_PROFILE_DOWNLOADER_ANDROID_H_
-
-#include <jni.h>
-
-// Registers the ProfileDownloader's native methods through JNI.
-bool RegisterProfileDownloader(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_PROFILES_PROFILE_DOWNLOADER_ANDROID_H_
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
index 8cb67d5..66d11f78 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.cc
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -815,10 +815,6 @@
   return reinterpret_cast<intptr_t>(provider);
 }
 
-bool ChromeBrowserProvider::RegisterChromeBrowserProvider(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 ChromeBrowserProvider::ChromeBrowserProvider(JNIEnv* env, jobject obj)
     : weak_java_provider_(env, obj),
       history_service_observer_(this),
diff --git a/chrome/browser/android/provider/chrome_browser_provider.h b/chrome/browser/android/provider/chrome_browser_provider.h
index af2f72b0..7f32c43 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.h
+++ b/chrome/browser/android/provider/chrome_browser_provider.h
@@ -35,9 +35,6 @@
   ChromeBrowserProvider(JNIEnv* env, jobject obj);
   void Destroy(JNIEnv*, const base::android::JavaParamRef<jobject>&);
 
-  // JNI registration.
-  static bool RegisterChromeBrowserProvider(JNIEnv* env);
-
   // Adds either a new bookmark or bookmark folder based on |is_folder|.  The
   // bookmark is added to the beginning of the specified parent and if the
   // parent ID is not valid (i.e. < 0) then it will be added to the bookmark
diff --git a/chrome/browser/android/rappor/rappor_service_bridge.cc b/chrome/browser/android/rappor/rappor_service_bridge.cc
index 804f142d..b6e2726 100644
--- a/chrome/browser/android/rappor/rappor_service_bridge.cc
+++ b/chrome/browser/android/rappor/rappor_service_bridge.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/rappor/rappor_service_bridge.h"
-
 #include "base/android/jni_string.h"
 #include "chrome/browser/browser_process.h"
 #include "components/rappor/public/rappor_utils.h"
@@ -37,8 +35,4 @@
                        metric, rappor::UMA_RAPPOR_TYPE, value);
 }
 
-bool RegisterRapporServiceBridge(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace rappor
diff --git a/chrome/browser/android/rappor/rappor_service_bridge.h b/chrome/browser/android/rappor/rappor_service_bridge.h
deleted file mode 100644
index e00bc67..0000000
--- a/chrome/browser/android/rappor/rappor_service_bridge.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_RAPPOR_RAPPOR_SERVICE_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_RAPPOR_RAPPOR_SERVICE_BRIDGE_H_
-
-#include <jni.h>
-#include <string>
-
-namespace rappor {
-
-bool RegisterRapporServiceBridge(JNIEnv* env);
-
-}  // namespace rappor
-
-#endif  // CHROME_BROWSER_ANDROID_RAPPOR_RAPPOR_SERVICE_BRIDGE_H_
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.cc b/chrome/browser/android/recently_closed_tabs_bridge.cc
index b80c3b4..09933891 100644
--- a/chrome/browser/android/recently_closed_tabs_bridge.cc
+++ b/chrome/browser/android/recently_closed_tabs_bridge.cc
@@ -179,8 +179,3 @@
       ProfileAndroid::FromProfileAndroid(jprofile));
   return reinterpret_cast<intptr_t>(bridge);
 }
-
-// static
-bool RecentlyClosedTabsBridge::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.h b/chrome/browser/android/recently_closed_tabs_bridge.h
index 5d8aeb0..5383fa7 100644
--- a/chrome/browser/android/recently_closed_tabs_bridge.h
+++ b/chrome/browser/android/recently_closed_tabs_bridge.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_RECENTLY_CLOSED_TABS_BRIDGE_H_
 #define CHROME_BROWSER_ANDROID_RECENTLY_CLOSED_TABS_BRIDGE_H_
 
-#include <jni.h>
-
 #include "base/android/scoped_java_ref.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
@@ -46,9 +44,6 @@
   void TabRestoreServiceDestroyed(
       sessions::TabRestoreService* service) override;
 
-  // Registers JNI methods.
-  static bool Register(JNIEnv* env);
-
  private:
   ~RecentlyClosedTabsBridge() override;
 
diff --git a/chrome/browser/android/rlz/revenue_stats.cc b/chrome/browser/android/rlz/revenue_stats.cc
index e9fbbc6c..0b90d0c 100644
--- a/chrome/browser/android/rlz/revenue_stats.cc
+++ b/chrome/browser/android/rlz/revenue_stats.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/rlz/revenue_stats.h"
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data_android.h"
@@ -15,11 +13,6 @@
 namespace chrome {
 namespace android {
 
-// Register native methods
-bool RegisterRevenueStats(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 static void SetSearchClient(JNIEnv* env,
                             const JavaParamRef<jclass>& clazz,
                             const JavaParamRef<jstring>& jclient) {
diff --git a/chrome/browser/android/rlz/revenue_stats.h b/chrome/browser/android/rlz/revenue_stats.h
deleted file mode 100644
index 80fe681..0000000
--- a/chrome/browser/android/rlz/revenue_stats.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_RLZ_REVENUE_STATS_H_
-#define CHROME_BROWSER_ANDROID_RLZ_REVENUE_STATS_H_
-
-#include <jni.h>
-
-namespace chrome {
-namespace android {
-
-bool RegisterRevenueStats(JNIEnv* env);
-
-}  // namespace android
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_ANDROID_RLZ_REVENUE_STATS_H_
diff --git a/chrome/browser/android/rlz/rlz_ping_handler.cc b/chrome/browser/android/rlz/rlz_ping_handler.cc
index 5ae5323..487c154 100644
--- a/chrome/browser/android/rlz/rlz_ping_handler.cc
+++ b/chrome/browser/android/rlz/rlz_ping_handler.cc
@@ -142,10 +142,5 @@
   handler->Ping(j_brand, j_language, j_events, j_id, j_callback);
 }
 
-// Register native methods
-bool RegisterRlzPingHandler(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/rlz/rlz_ping_handler.h b/chrome/browser/android/rlz/rlz_ping_handler.h
index 2abe720..6422230 100644
--- a/chrome/browser/android/rlz/rlz_ping_handler.h
+++ b/chrome/browser/android/rlz/rlz_ping_handler.h
@@ -43,8 +43,6 @@
   DISALLOW_COPY_AND_ASSIGN(RlzPingHandler);
 };
 
-bool RegisterRlzPingHandler(JNIEnv* env);
-
 }  // namespace android
 }  // namespace chrome
 
diff --git a/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.cc b/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.cc
index f45ba63..e8b17078 100644
--- a/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.cc
+++ b/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.cc
@@ -137,11 +137,6 @@
       prefs::kSearchGeolocationPostDisclosureMetricsRecorded, false);
 }
 
-// static
-bool SearchGeolocationDisclosureTabHelper::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void SearchGeolocationDisclosureTabHelper::MaybeShowDisclosureForNavigation(
     const GURL& gurl) {
   if (!consistent_geolocation_disclosure_enabled_)
diff --git a/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h b/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h
index c0f38dc7..c316b99 100644
--- a/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h
+++ b/chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_SEARCH_GEOLOCATION_SEARCH_GEOLOCATION_DISCLOSURE_TAB_HELPER_H_
 #define CHROME_BROWSER_ANDROID_SEARCH_GEOLOCATION_SEARCH_GEOLOCATION_DISCLOSURE_TAB_HELPER_H_
 
-#include <jni.h>
-
 #include "base/macros.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -40,9 +38,6 @@
 
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
-  // Registers native methods.
-  static bool Register(JNIEnv* env);
-
  private:
   explicit SearchGeolocationDisclosureTabHelper(content::WebContents* contents);
   friend class content::WebContentsUserData<
diff --git a/chrome/browser/android/service_tab_launcher.cc b/chrome/browser/android/service_tab_launcher.cc
index d323635..4142f656 100644
--- a/chrome/browser/android/service_tab_launcher.cc
+++ b/chrome/browser/android/service_tab_launcher.cc
@@ -81,7 +81,3 @@
 
   tab_launched_callbacks_.Remove(request_id);
 }
-
-bool ServiceTabLauncher::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/service_tab_launcher.h b/chrome/browser/android/service_tab_launcher.h
index 05cca24..242a16a 100644
--- a/chrome/browser/android/service_tab_launcher.h
+++ b/chrome/browser/android/service_tab_launcher.h
@@ -40,8 +40,6 @@
   // the provisional load for the main frame of the navigation.
   void OnTabLaunched(int request_id, content::WebContents* web_contents);
 
-  static bool Register(JNIEnv* env);
-
  private:
   friend struct base::DefaultSingletonTraits<ServiceTabLauncher>;
 
diff --git a/chrome/browser/android/sessions/session_tab_helper_android.cc b/chrome/browser/android/sessions/session_tab_helper_android.cc
index 140bb034..a2e8061c 100644
--- a/chrome/browser/android/sessions/session_tab_helper_android.cc
+++ b/chrome/browser/android/sessions/session_tab_helper_android.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/sessions/session_tab_helper_android.h"
-
 #include "base/android/jni_android.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "content/public/browser/web_contents.h"
@@ -20,7 +18,3 @@
   CHECK(web_contents);
   return SessionTabHelper::IdForTab(web_contents);
 }
-
-bool RegisterSessionTabHelper(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/sessions/session_tab_helper_android.h b/chrome/browser/android/sessions/session_tab_helper_android.h
deleted file mode 100644
index e73fa71..0000000
--- a/chrome/browser/android/sessions/session_tab_helper_android.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_SESSIONS_SESSION_TAB_HELPER_ANDROID_H_
-#define CHROME_BROWSER_ANDROID_SESSIONS_SESSION_TAB_HELPER_ANDROID_H_
-
-#include <jni.h>
-
-// Registers the SessionTabHelper's native methods through JNI.
-bool RegisterSessionTabHelper(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_SESSIONS_SESSION_TAB_HELPER_ANDROID_H_
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index 847fb27..30309ec3 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -407,7 +407,3 @@
   webapk_list_callback->Run(webapk_list);
   delete webapk_list_callback;
 }
-
-bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h
index 43755d6dd..8f4b966 100644
--- a/chrome/browser/android/shortcut_helper.h
+++ b/chrome/browser/android/shortcut_helper.h
@@ -29,9 +29,6 @@
   using WebApkInfoCallback =
       base::Callback<void(const std::vector<WebApkInfo>&)>;
 
-  // Registers JNI hooks.
-  static bool RegisterShortcutHelper(JNIEnv* env);
-
   // Adds a shortcut to the launcher using a SkBitmap. The type of shortcut
   // added depends on the properties in |info|.
   static void AddToLauncherWithSkBitmap(content::WebContents* web_contents,
diff --git a/chrome/browser/android/signin/account_management_screen_helper.cc b/chrome/browser/android/signin/account_management_screen_helper.cc
index 5ec128b..8d232e08 100644
--- a/chrome/browser/android/signin/account_management_screen_helper.cc
+++ b/chrome/browser/android/signin/account_management_screen_helper.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/android/signin/account_management_screen_helper.h"
 
-#include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
@@ -34,8 +33,3 @@
       static_cast<ProfileMetrics::ProfileAndroidAccountManagementMenu>(metric),
       static_cast<signin::GAIAServiceType>(gaiaServiceType));
 }
-
-// static
-bool AccountManagementScreenHelper::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/signin/account_management_screen_helper.h b/chrome/browser/android/signin/account_management_screen_helper.h
index c9019bc..a5a9adf 100644
--- a/chrome/browser/android/signin/account_management_screen_helper.h
+++ b/chrome/browser/android/signin/account_management_screen_helper.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_SIGNIN_ACCOUNT_MANAGEMENT_SCREEN_HELPER_H_
 #define CHROME_BROWSER_ANDROID_SIGNIN_ACCOUNT_MANAGEMENT_SCREEN_HELPER_H_
 
-#include <jni.h>
-
 #include "base/macros.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 
@@ -15,9 +13,6 @@
 // The glue for Java-side implementation of AccountManagementScreenHelper.
 class AccountManagementScreenHelper {
  public:
-  // Registers AccountManagementScreenHelper native methods through JNI.
-  static bool Register(JNIEnv* env);
-
   // Opens the account management screen.
   static void OpenAccountManagementScreen(Profile* profile,
                                           signin::GAIAServiceType service_type);
diff --git a/chrome/browser/android/signin/account_tracker_service_android.cc b/chrome/browser/android/signin/account_tracker_service_android.cc
index 49d61b47..76dc4c0 100644
--- a/chrome/browser/android/signin/account_tracker_service_android.cc
+++ b/chrome/browser/android/signin/account_tracker_service_android.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/signin/account_tracker_service_android.h"
-
 #include <stddef.h>
 
 #include "base/android/jni_array.h"
@@ -68,9 +66,5 @@
   return true;
 }
 
-bool RegisterAccountTrackerService(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace android
 }  // namespace signin
diff --git a/chrome/browser/android/signin/account_tracker_service_android.h b/chrome/browser/android/signin/account_tracker_service_android.h
deleted file mode 100644
index c831feac..0000000
--- a/chrome/browser/android/signin/account_tracker_service_android.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_SIGNIN_ACCOUNT_TRACKER_SERVICE_ANDROID_H_
-#define CHROME_BROWSER_ANDROID_SIGNIN_ACCOUNT_TRACKER_SERVICE_ANDROID_H_
-
-#include <jni.h>
-
-namespace signin {
-namespace android {
-// A bridge between the Java and C++ AccountTrackerService.
-bool RegisterAccountTrackerService(JNIEnv* env);
-
-}  // namespace android
-}  // namespace signin
-
-#endif  // CHROME_BROWSER_ANDROID_SIGNIN_ACCOUNT_TRACKER_SERVICE_ANDROID_H_
diff --git a/chrome/browser/android/signin/signin_investigator_android.cc b/chrome/browser/android/signin/signin_investigator_android.cc
index ff04b04..b1dfa29 100644
--- a/chrome/browser/android/signin/signin_investigator_android.cc
+++ b/chrome/browser/android/signin/signin_investigator_android.cc
@@ -16,11 +16,6 @@
 using base::android::JavaParamRef;
 
 // static
-bool SigninInvestigatorAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 jint Investigate(JNIEnv* env,
                  const JavaParamRef<jclass>& jcaller,
                  const JavaParamRef<jstring>& current_email) {
diff --git a/chrome/browser/android/signin/signin_investigator_android.h b/chrome/browser/android/signin/signin_investigator_android.h
index da8e4ca..3195dc0c 100644
--- a/chrome/browser/android/signin/signin_investigator_android.h
+++ b/chrome/browser/android/signin/signin_investigator_android.h
@@ -15,9 +15,6 @@
 // SigninInvestigator.
 class SigninInvestigatorAndroid {
  public:
-  // Registers the SigninInvestigatorAndroid's native methods through JNI.
-  static bool Register(JNIEnv* env);
-
   // Investigates the current signin, and returns an int corresponding to the
   // scenario we are currently in.
   static jint Investigate(
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index 29e9ad8b..eac88f72 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -402,8 +402,3 @@
   std::string domain = gaia::ExtractDomainName(email);
   return base::android::ConvertUTF8ToJavaString(env, domain);
 }
-
-// static
-bool SigninManagerAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index e164336..6a50bba 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_MANAGER_ANDROID_H_
 #define CHROME_BROWSER_ANDROID_SIGNIN_SIGNIN_MANAGER_ANDROID_H_
 
-#include <jni.h>
-
 #include <memory>
 #include <string>
 
@@ -31,9 +29,6 @@
  public:
   SigninManagerAndroid(JNIEnv* env, jobject obj);
 
-  // Registers the SigninManagerAndroid's native methods through JNI.
-  static bool Register(JNIEnv* env);
-
   void CheckPolicyBeforeSignIn(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 90198a6..4d0f6ab 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -836,8 +836,3 @@
   // This will automatically bind to the Java object and pass ownership there.
   new TabAndroid(env, obj);
 }
-
-// static
-bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index ae6bdce6..e8203e0d 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -262,9 +262,6 @@
   void AttachDetachedTab(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
 
-  // Register the Tab's native methods through JNI.
-  static bool RegisterTabAndroid(JNIEnv* env);
-
  private:
   prerender::PrerenderManager* GetPrerenderManager() const;
 
diff --git a/chrome/browser/android/tab_state.cc b/chrome/browser/android/tab_state.cc
index 0c94d37..749d398 100644
--- a/chrome/browser/android/tab_state.cc
+++ b/chrome/browser/android/tab_state.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/android/tab_state.h"
 
-#include <jni.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -564,7 +563,3 @@
   if (web_contents.get())
     TabAndroid::CreateHistoricalTabFromContents(web_contents.get());
 }
-
-bool RegisterTabState(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/tab_state.h b/chrome/browser/android/tab_state.h
index 2b0182a5..4f15fa08 100644
--- a/chrome/browser/android/tab_state.h
+++ b/chrome/browser/android/tab_state.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_TAB_STATE_H_
 #define CHROME_BROWSER_ANDROID_TAB_STATE_H_
 
-#include <jni.h>
 #include <vector>
 
 #include "base/android/scoped_java_ref.h"
@@ -67,7 +66,4 @@
                                               jboolean is_off_the_record);
 };
 
-// Registers methods for JNI.
-bool RegisterTabState(JNIEnv* env);
-
 #endif  // CHROME_BROWSER_ANDROID_TAB_STATE_H_
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index 3512ed97..1b24acd 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -105,11 +105,6 @@
   notification_registrar_.RemoveAll();
 }
 
-// Register native methods.
-bool RegisterTabWebContentsDelegateAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void TabWebContentsDelegateAndroid::LoadingStateChanged(
     WebContents* source, bool to_different_document) {
   bool has_stopped = source == nullptr || !source->IsLoading();
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h
index 1d85597..fa5d84db 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.h
+++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -5,8 +5,6 @@
 #ifndef CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_
 #define CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_
 
-#include <jni.h>
-
 #include "base/files/file_path.h"
 #include "components/web_contents_delegate_android/web_contents_delegate_android.h"
 #include "content/public/browser/bluetooth_chooser.h"
@@ -97,9 +95,6 @@
   content::NotificationRegistrar notification_registrar_;
 };
 
-// Register the native methods through JNI.
-bool RegisterTabWebContentsDelegateAndroid(JNIEnv* env);
-
 }  // namespace android
 
 #endif  // CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/android/url_utilities.cc b/chrome/browser/android/url_utilities.cc
index 1e28a53..4f89529 100644
--- a/chrome/browser/android/url_utilities.cc
+++ b/chrome/browser/android/url_utilities.cc
@@ -175,9 +175,3 @@
                                const JavaParamRef<jstring>& url) {
   return CheckSchemeBelongsToList(env, url, g_downloadable_schemes);
 }
-
-
-// Register native methods
-bool RegisterUrlUtilities(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/url_utilities.h b/chrome/browser/android/url_utilities.h
deleted file mode 100644
index eabbb8d..0000000
--- a/chrome/browser/android/url_utilities.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2013 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 CHROME_BROWSER_ANDROID_URL_UTILITIES_H_
-#define CHROME_BROWSER_ANDROID_URL_UTILITIES_H_
-
-#include <jni.h>
-
-bool RegisterUrlUtilities(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_URL_UTILITIES_H_
diff --git a/chrome/browser/android/warmup_manager.cc b/chrome/browser/android/warmup_manager.cc
index e3271e3c..c06e1d7 100644
--- a/chrome/browser/android/warmup_manager.cc
+++ b/chrome/browser/android/warmup_manager.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/warmup_manager.h"
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "chrome/browser/net/predictor.h"
@@ -26,9 +24,3 @@
     }
   }
 }
-
-
-// Register native methods.
-bool RegisterWarmupManager(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/warmup_manager.h b/chrome/browser/android/warmup_manager.h
deleted file mode 100644
index 8df72da2..0000000
--- a/chrome/browser/android/warmup_manager.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_WARMUP_MANAGER_H_
-#define CHROME_BROWSER_ANDROID_WARMUP_MANAGER_H_
-
-#include <jni.h>
-
-bool RegisterWarmupManager(JNIEnv* env);
-#endif  // CHROME_BROWSER_ANDROID_WARMUP_MANAGER_H_
diff --git a/chrome/browser/android/web_contents_factory.cc b/chrome/browser/android/web_contents_factory.cc
index 63fe8fa..cc0314d 100644
--- a/chrome/browser/android/web_contents_factory.cc
+++ b/chrome/browser/android/web_contents_factory.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/web_contents_factory.h"
-
 #include "base/android/jni_android.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -29,7 +27,3 @@
   params.initialize_renderer = static_cast<bool>(initialize_renderer);
   return content::WebContents::Create(params)->GetJavaWebContents();
 }
-
-bool RegisterWebContentsFactory(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/web_contents_factory.h b/chrome/browser/android/web_contents_factory.h
deleted file mode 100644
index 5915675..0000000
--- a/chrome/browser/android/web_contents_factory.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_ANDROID_WEB_CONTENTS_FACTORY_H_
-#define CHROME_BROWSER_ANDROID_WEB_CONTENTS_FACTORY_H_
-
-#include "base/android/jni_android.h"
-
-// Register the WebContentsFactory's native methods through JNI.
-bool RegisterWebContentsFactory(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_WEB_CONTENTS_FACTORY_H_
-
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.cc b/chrome/browser/android/webapk/chrome_webapk_host.cc
index f18514d..a3bbaf7 100644
--- a/chrome/browser/android/webapk/chrome_webapk_host.cc
+++ b/chrome/browser/android/webapk/chrome_webapk_host.cc
@@ -18,11 +18,6 @@
 }  // anonymous namespace
 
 // static
-bool ChromeWebApkHost::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-// static
 bool ChromeWebApkHost::CanInstallWebApk() {
   return base::FeatureList::IsEnabled(chrome::android::kImprovedA2HS);
 }
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.h b/chrome/browser/android/webapk/chrome_webapk_host.h
index 7505772..a8c7f2f7 100644
--- a/chrome/browser/android/webapk/chrome_webapk_host.h
+++ b/chrome/browser/android/webapk/chrome_webapk_host.h
@@ -5,17 +5,12 @@
 #ifndef CHROME_BROWSER_ANDROID_WEBAPK_CHROME_WEBAPK_HOST_H_
 #define CHROME_BROWSER_ANDROID_WEBAPK_CHROME_WEBAPK_HOST_H_
 
-#include <jni.h>
-
 #include "base/macros.h"
 
 // ChromeWebApkHost is the C++ counterpart of org.chromium.chrome.browser's
 // ChromeWebApkHost in Java.
 class ChromeWebApkHost {
  public:
-  // Registers JNI hooks.
-  static bool Register(JNIEnv* env);
-
   // Returns whether installing WebApk is possible.
   static bool CanInstallWebApk();
 
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index 663093d..61f0913 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -274,11 +274,6 @@
       callback);
 }
 
-// static
-bool WebApkInstaller::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void WebApkInstaller::InstallOrUpdateWebApk(const std::string& package_name,
                                             int version,
                                             const std::string& token) {
diff --git a/chrome/browser/android/webapk/webapk_installer.h b/chrome/browser/android/webapk/webapk_installer.h
index 2c21121a..3a9418d 100644
--- a/chrome/browser/android/webapk/webapk_installer.h
+++ b/chrome/browser/android/webapk/webapk_installer.h
@@ -98,9 +98,6 @@
       const base::Callback<void(std::unique_ptr<std::vector<uint8_t>>)>&
           callback);
 
-  // Registers JNI hooks.
-  static bool Register(JNIEnv* env);
-
  protected:
   explicit WebApkInstaller(content::BrowserContext* browser_context);
 
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
index 6849a69..b7a9d96 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -62,11 +62,6 @@
 
 WebApkUpdateDataFetcher::~WebApkUpdateDataFetcher() {}
 
-// static
-bool WebApkUpdateDataFetcher::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void WebApkUpdateDataFetcher::ReplaceWebContents(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.h b/chrome/browser/android/webapk/webapk_update_data_fetcher.h
index 7f341f18..777a760 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.h
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.h
@@ -45,9 +45,6 @@
              const base::android::JavaParamRef<jobject>& obj,
              const base::android::JavaParamRef<jobject>& java_web_contents);
 
-  // Registers JNI hooks.
-  static bool Register(JNIEnv* env);
-
  private:
   ~WebApkUpdateDataFetcher() override;
 
diff --git a/chrome/browser/android/webapk/webapk_update_manager.cc b/chrome/browser/android/webapk/webapk_update_manager.cc
index 1b721b9..9af9a7b 100644
--- a/chrome/browser/android/webapk/webapk_update_manager.cc
+++ b/chrome/browser/android/webapk/webapk_update_manager.cc
@@ -51,11 +51,6 @@
 
 }  // anonymous namespace
 
-// static
-bool WebApkUpdateManager::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 // static JNI method.
 static void BuildUpdateWebApkProto(
     JNIEnv* env,
diff --git a/chrome/browser/android/webapk/webapk_update_manager.h b/chrome/browser/android/webapk/webapk_update_manager.h
index 6040726..d27ce9bb 100644
--- a/chrome/browser/android/webapk/webapk_update_manager.h
+++ b/chrome/browser/android/webapk/webapk_update_manager.h
@@ -15,9 +15,6 @@
 // request to WebAPK Server.
 class WebApkUpdateManager {
  public:
-  // Registers JNI hooks.
-  static bool Register(JNIEnv* env);
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(WebApkUpdateManager);
 };
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
index 44c823e9..40f2360 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -54,11 +54,6 @@
   java_ref_.Reset(env, obj);
 }
 
-// static
-bool AddToHomescreenManager::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void AddToHomescreenManager::Destroy(JNIEnv* env,
                                      const JavaParamRef<jobject>& obj) {
   delete this;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.h b/chrome/browser/android/webapps/add_to_homescreen_manager.h
index 7cdefa41..3d2b780b 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_manager.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_manager.h
@@ -27,9 +27,6 @@
  public:
   AddToHomescreenManager(JNIEnv* env, jobject obj);
 
-  // Registers JNI hooks.
-  static bool Register(JNIEnv* env);
-
   // Called by the Java counterpart to destroy its native half.
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 99f5e38..98428d0a 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -674,6 +674,9 @@
         <include name="IDR_SANDBOX_INTERNALS_HTML" file="resources\sandbox_internals\sandbox_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
         <include name="IDR_SANDBOX_INTERNALS_JS" file="resources\sandbox_internals\sandbox_internals.js" type="BINDATA" compress="gzip" />
       </if>
+      <include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
+      <include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
+      <include name="IDR_MEDIA_ENGAGEMENT_MOJO_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index df2c387..92120fd 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -72,6 +72,7 @@
           "translate::mojom::ContentTranslateDriver",
 
           // TODO(beng): These should be moved to a separate capability.
+	  "media::mojom::MediaEngagementScoreDetailsProvider",
           "mojom::OmniboxPageHandler",
           "mojom::PluginsPageHandler",
           "mojom::SiteEngagementDetailsProvider",
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
index 2ac6fed9..0794be5 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -16,7 +17,7 @@
 #include "chrome/browser/chromeos/attestation/fake_certificate.h"
 #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
 #include "chromeos/attestation/mock_attestation_flow.h"
-#include "chromeos/dbus/mock_cryptohome_client.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -36,21 +37,6 @@
 const int64_t kCertExpiringSoon = 20;
 const int64_t kCertExpired = -20;
 
-void DBusCallbackFalse(const BoolDBusMethodCallback& callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, false));
-}
-
-void DBusCallbackTrue(const BoolDBusMethodCallback& callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, true));
-}
-
-void DBusCallbackError(const BoolDBusMethodCallback& callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_FAILURE, false));
-}
-
 void CertCallbackSuccess(const AttestationFlow::CertificateCallback& callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(callback, true, "fake_cert"));
@@ -62,20 +48,6 @@
                                                 base::BindOnce(callback, true));
 }
 
-class FakeDBusData {
- public:
-  explicit FakeDBusData(const std::string& data) : data_(data) {}
-
-  void operator() (const CryptohomeClient::DataMethodCallback& callback) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, true, data_));
-  }
-
- private:
-  std::string data_;
-};
-
 }  // namespace
 
 class AttestationPolicyObserverTest : public ::testing::Test {
@@ -88,9 +60,9 @@
 
  protected:
   enum MockOptions {
-    MOCK_KEY_EXISTS = 1,          // Configure so a certified key exists.
-    MOCK_KEY_UPLOADED = (1 << 1), // Configure so an upload has occurred.
-    MOCK_NEW_KEY = (1 << 2)       // Configure expecting new key generation.
+    MOCK_KEY_EXISTS = 1,           // Configure so a certified key exists.
+    MOCK_KEY_UPLOADED = (1 << 1),  // Configure so an upload has occurred.
+    MOCK_NEW_KEY = (1 << 2)        // Configure expecting new key generation.
   };
 
   // Configures mock expectations according to |mock_options|.  If options
@@ -99,21 +71,14 @@
     bool key_exists = (mock_options & MOCK_KEY_EXISTS);
     // Setup expected key / cert queries.
     if (key_exists) {
-      EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-          .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackTrue)));
-      EXPECT_CALL(cryptohome_client_, TpmAttestationGetCertificate(_, _, _, _))
-          .WillRepeatedly(WithArgs<3>(Invoke(FakeDBusData(certificate))));
-    } else {
-      EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-          .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
+      cryptohome_client_.SetTpmAttestationDeviceCertificate(
+          kEnterpriseMachineKey, certificate);
     }
 
     // Setup expected key payload queries.
     bool key_uploaded = (mock_options & MOCK_KEY_UPLOADED);
-    std::string payload = CreatePayload();
-    EXPECT_CALL(cryptohome_client_, TpmAttestationGetKeyPayload(_, _, _, _))
-        .WillRepeatedly(WithArgs<3>(Invoke(
-            FakeDBusData(key_uploaded ? payload : ""))));
+    cryptohome_client_.SetTpmAttestationDeviceKeyPayload(
+        kEnterpriseMachineKey, key_uploaded ? CreatePayload() : std::string());
 
     // Setup expected key uploads.  Use WillOnce() so StrictMock will trigger an
     // error if our expectations are not met exactly.  We want to verify that
@@ -125,9 +90,6 @@
       EXPECT_CALL(policy_client_,
                   UploadCertificate(new_key ? "fake_cert" : certificate, _))
           .WillOnce(WithArgs<1>(Invoke(StatusCallbackSuccess)));
-      EXPECT_CALL(cryptohome_client_,
-                  TpmAttestationSetKeyPayload(_, _, _, payload, _))
-          .WillOnce(WithArgs<4>(Invoke(DBusCallbackTrue)));
     }
 
     // Setup expected key generations.  Again use WillOnce().  Key generation is
@@ -157,7 +119,7 @@
 
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
   ScopedCrosSettingsTestHelper settings_helper_;
-  StrictMock<MockCryptohomeClient> cryptohome_client_;
+  FakeCryptohomeClient cryptohome_client_;
   StrictMock<MockAttestationFlow> attestation_flow_;
   StrictMock<policy::MockCloudPolicyClient> policy_client_;
 };
@@ -175,6 +137,9 @@
 TEST_F(AttestationPolicyObserverTest, NewCertificate) {
   SetupMocks(MOCK_NEW_KEY, "");
   Run();
+  EXPECT_EQ(CreatePayload(),
+            cryptohome_client_.GetTpmAttestationDeviceKeyPayload(
+                kEnterpriseMachineKey));
 }
 
 TEST_F(AttestationPolicyObserverTest, KeyExistsNotUploaded) {
@@ -183,6 +148,9 @@
                                     &certificate));
   SetupMocks(MOCK_KEY_EXISTS, certificate);
   Run();
+  EXPECT_EQ(CreatePayload(),
+            cryptohome_client_.GetTpmAttestationDeviceKeyPayload(
+                kEnterpriseMachineKey));
 }
 
 TEST_F(AttestationPolicyObserverTest, KeyExistsAlreadyUploaded) {
@@ -217,10 +185,23 @@
 TEST_F(AttestationPolicyObserverTest, DBusFailureRetry) {
   SetupMocks(MOCK_NEW_KEY, "");
   // Simulate a DBus failure.
-  EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-      .WillOnce(WithArgs<3>(Invoke(DBusCallbackError)))
-      .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
+  cryptohome_client_.SetServiceIsAvailable(false);
+
+  // Emulate delayed service initialization.
+  // Run() instantiates an Observer, which synchronously calls
+  // TpmAttestationDoesKeyExist() and fails. During this call, we make the
+  // service available in the next run, so on retry, it will successfully
+  // return the result.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](FakeCryptohomeClient* cryptohome_client) {
+                       cryptohome_client->SetServiceIsAvailable(true);
+                     },
+                     base::Unretained(&cryptohome_client_)));
   Run();
+  EXPECT_EQ(CreatePayload(),
+            cryptohome_client_.GetTpmAttestationDeviceKeyPayload(
+                kEnterpriseMachineKey));
 }
 
 }  // namespace attestation
diff --git a/chrome/browser/extensions/extension_tab_util_browsertest.cc b/chrome/browser/extensions/extension_tab_util_browsertest.cc
index a458cd1..b858492 100644
--- a/chrome/browser/extensions/extension_tab_util_browsertest.cc
+++ b/chrome/browser/extensions/extension_tab_util_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -119,8 +120,16 @@
   EXPECT_EQ(options_url, GetActiveUrl(browser()));
 }
 
+// Flaky on Windows: http://crbug.com/745729
+#if defined(OS_WIN)
+#define MAYBE_OpenSplitModeExtensionOptionsPageIncognito \
+  DISABLED_OpenSplitModeExtensionOptionsPageIncognito
+#else
+#define MAYBE_OpenSplitModeExtensionOptionsPageIncognito \
+  OpenSplitModeExtensionOptionsPageIncognito
+#endif
 IN_PROC_BROWSER_TEST_F(ExtensionTabUtilBrowserTest,
-                       OpenSplitModeExtensionOptionsPageIncognito) {
+                       MAYBE_OpenSplitModeExtensionOptionsPageIncognito) {
   const Extension* options_split_extension = LoadExtensionIncognito(
       test_data_dir_.AppendASCII("options_page_split_incognito"));
   ASSERT_TRUE(options_split_extension);
diff --git a/chrome/browser/media/BUILD.gn b/chrome/browser/media/BUILD.gn
index 1d20e7d..7cdced2 100644
--- a/chrome/browser/media/BUILD.gn
+++ b/chrome/browser/media/BUILD.gn
@@ -13,7 +13,4 @@
     "//mojo/common:common_custom_types",
     "//url/mojo:url_mojom_gurl",
   ]
-
-  # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  use_new_js_bindings = false
 }
diff --git a/chrome/browser/media/media_engagement_score.cc b/chrome/browser/media/media_engagement_score.cc
index fa095a6..6b761f8 100644
--- a/chrome/browser/media/media_engagement_score.cc
+++ b/chrome/browser/media/media_engagement_score.cc
@@ -61,11 +61,12 @@
     last_media_playback_time_ = base::Time::FromInternalValue(internal_time);
 }
 
-media::mojom::MediaEngagementScoreDetails
+// TODO(beccahughes): Add typemap.
+media::mojom::MediaEngagementScoreDetailsPtr
 MediaEngagementScore::GetScoreDetails() const {
-  return media::mojom::MediaEngagementScoreDetails(origin_, GetTotalScore(),
-                                                   visits(), media_playbacks(),
-                                                   last_media_playback_time());
+  return media::mojom::MediaEngagementScoreDetails::New(
+      origin_, GetTotalScore(), visits(), media_playbacks(),
+      last_media_playback_time().ToJsTime());
 }
 
 MediaEngagementScore::~MediaEngagementScore() = default;
diff --git a/chrome/browser/media/media_engagement_score.h b/chrome/browser/media/media_engagement_score.h
index 0735e4fb..e39e810 100644
--- a/chrome/browser/media/media_engagement_score.h
+++ b/chrome/browser/media/media_engagement_score.h
@@ -66,7 +66,7 @@
   }
 
   // Get a breakdown of the score that can be serialized by Mojo.
-  media::mojom::MediaEngagementScoreDetails GetScoreDetails() const;
+  media::mojom::MediaEngagementScoreDetailsPtr GetScoreDetails() const;
 
  private:
   friend class MediaEngagementServiceTest;
diff --git a/chrome/browser/media/media_engagement_score_details.mojom b/chrome/browser/media/media_engagement_score_details.mojom
index f5252b8..e4e0fb9 100644
--- a/chrome/browser/media/media_engagement_score_details.mojom
+++ b/chrome/browser/media/media_engagement_score_details.mojom
@@ -4,7 +4,6 @@
 
 module media.mojom;
 
-import "mojo/common/time.mojom";
 import "url/mojo/url.mojom";
 
 struct MediaEngagementScoreDetails {
@@ -14,5 +13,11 @@
   // Details of the components which make up |score|.
   int32 visits;
   int32 media_playbacks;
-  mojo.common.mojom.Time last_media_playback_time;
+
+  // Last media playback time in milliseconds since the epoch format.
+  double last_media_playback_time;
+};
+
+interface MediaEngagementScoreDetailsProvider {
+  GetMediaEngagementScoreDetails() => (array<MediaEngagementScoreDetails> info);
 };
diff --git a/chrome/browser/media/media_engagement_score_unittest.cc b/chrome/browser/media/media_engagement_score_unittest.cc
index 7343969..a4b04e9e 100644
--- a/chrome/browser/media/media_engagement_score_unittest.cc
+++ b/chrome/browser/media/media_engagement_score_unittest.cc
@@ -97,14 +97,14 @@
   void SetVisits(int visits) { score_->visits_ = visits; }
 
   void VerifyGetScoreDetails(MediaEngagementScore* score) {
-    media::mojom::MediaEngagementScoreDetails details =
+    media::mojom::MediaEngagementScoreDetailsPtr details =
         score->GetScoreDetails();
-    EXPECT_EQ(details.origin, score->origin_);
-    EXPECT_EQ(details.total_score, score->GetTotalScore());
-    EXPECT_EQ(details.visits, score->visits());
-    EXPECT_EQ(details.media_playbacks, score->media_playbacks());
-    EXPECT_EQ(details.last_media_playback_time,
-              score->last_media_playback_time());
+    EXPECT_EQ(details->origin, score->origin_);
+    EXPECT_EQ(details->total_score, score->GetTotalScore());
+    EXPECT_EQ(details->visits, score->visits());
+    EXPECT_EQ(details->media_playbacks, score->media_playbacks());
+    EXPECT_EQ(details->last_media_playback_time,
+              score->last_media_playback_time().ToJsTime());
   }
 };
 
diff --git a/chrome/browser/media/media_engagement_service.cc b/chrome/browser/media/media_engagement_service.cc
index c669cd16..8ba90d802 100644
--- a/chrome/browser/media/media_engagement_service.cc
+++ b/chrome/browser/media/media_engagement_service.cc
@@ -201,11 +201,11 @@
   score.Commit();
 }
 
-std::vector<media::mojom::MediaEngagementScoreDetails>
+std::vector<media::mojom::MediaEngagementScoreDetailsPtr>
 MediaEngagementService::GetAllScoreDetails() const {
   std::set<GURL> origins = GetEngagementOriginsFromContentSettings(profile_);
 
-  std::vector<media::mojom::MediaEngagementScoreDetails> details;
+  std::vector<media::mojom::MediaEngagementScoreDetailsPtr> details;
   details.reserve(origins.size());
   for (const GURL& origin : origins) {
     // TODO(beccahughes): Why would an origin not be valid here?
diff --git a/chrome/browser/media/media_engagement_service.h b/chrome/browser/media/media_engagement_service.h
index df0f638..bdc2da50 100644
--- a/chrome/browser/media/media_engagement_service.h
+++ b/chrome/browser/media/media_engagement_service.h
@@ -62,7 +62,7 @@
 
   // Returns an array of engagement score details for all origins which
   // have a score.
-  std::vector<media::mojom::MediaEngagementScoreDetails> GetAllScoreDetails()
+  std::vector<media::mojom::MediaEngagementScoreDetailsPtr> GetAllScoreDetails()
       const;
 
   // Overridden from history::HistoryServiceObserver:
diff --git a/chrome/browser/media/media_engagement_service_unittest.cc b/chrome/browser/media/media_engagement_service_unittest.cc
index 4e17a9b..97ffe21 100644
--- a/chrome/browser/media/media_engagement_service_unittest.cc
+++ b/chrome/browser/media/media_engagement_service_unittest.cc
@@ -196,7 +196,7 @@
 
   void SetNow(base::Time now) { test_clock_->SetNow(now); }
 
-  std::vector<media::mojom::MediaEngagementScoreDetails> GetAllScoreDetails()
+  std::vector<media::mojom::MediaEngagementScoreDetailsPtr> GetAllScoreDetails()
       const {
     return service_->GetAllScoreDetails();
   }
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 02b443f..ba200933 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -42,6 +42,7 @@
 #include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
 #include "components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h"
 #include "components/ntp_snippets/breaking_news/subscription_manager.h"
+#include "components/ntp_snippets/breaking_news/subscription_manager_impl.h"
 #include "components/ntp_snippets/category_rankers/category_ranker.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "components/ntp_snippets/features.h"
@@ -114,7 +115,7 @@
 using ntp_snippets::RemoteSuggestionsProviderImpl;
 using ntp_snippets::RemoteSuggestionsSchedulerImpl;
 using ntp_snippets::RemoteSuggestionsStatusService;
-using ntp_snippets::SubscriptionManager;
+using ntp_snippets::SubscriptionManagerImpl;
 using ntp_snippets::TabDelegateSyncAdapter;
 using ntp_snippets::UserClassifier;
 using suggestions::ImageDecoderImpl;
@@ -404,7 +405,7 @@
                                 : google_apis::GetNonStableAPIKey();
   }
 
-  auto subscription_manager = base::MakeUnique<SubscriptionManager>(
+  auto subscription_manager = base::MakeUnique<SubscriptionManagerImpl>(
       request_context, pref_service, signin_manager, token_service, api_key,
       GetPushUpdatesSubscriptionEndpoint(chrome::GetChannel()),
       GetPushUpdatesUnsubscriptionEndpoint(chrome::GetChannel()));
diff --git a/chrome/browser/predictors/loading_data_collector.cc b/chrome/browser/predictors/loading_data_collector.cc
index 9840f52..78c3fba 100644
--- a/chrome/browser/predictors/loading_data_collector.cc
+++ b/chrome/browser/predictors/loading_data_collector.cc
@@ -342,6 +342,12 @@
   if (navigation_id.main_frame_url.is_empty())
     return;
 
+  // Initialize |predictor_| no matter whether the |navigation_id| is present in
+  // |inflight_navigations_|. This is the case for NTP and about:blank pages,
+  // for example.
+  if (predictor_)
+    predictor_->StartInitialization();
+
   NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id);
   if (nav_it == inflight_navigations_.end())
     return;
@@ -359,9 +365,8 @@
   if (stats_collector_)
     stats_collector_->RecordPageRequestSummary(*summary);
 
-  if (predictor_) {
+  if (predictor_)
     predictor_->RecordPageRequestSummary(std::move(summary));
-  }
 }
 
 void LoadingDataCollector::RecordFirstContentfulPaint(
diff --git a/chrome/browser/predictors/loading_predictor_unittest.cc b/chrome/browser/predictors/loading_predictor_unittest.cc
index 991f62a5..7b25cfaa 100644
--- a/chrome/browser/predictors/loading_predictor_unittest.cc
+++ b/chrome/browser/predictors/loading_predictor_unittest.cc
@@ -56,8 +56,6 @@
 
   auto mock = base::MakeUnique<StrictMock<MockResourcePrefetchPredictor>>(
       config, profile_.get());
-  EXPECT_CALL(*mock, StartInitialization());
-  EXPECT_CALL(*mock, Shutdown());
   EXPECT_CALL(*mock, GetPrefetchData(GURL(kUrl), _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(*mock, GetPrefetchData(GURL(kUrl2), _))
diff --git a/chrome/browser/predictors/loading_test_util.h b/chrome/browser/predictors/loading_test_util.h
index 88577c2..83175db 100644
--- a/chrome/browser/predictors/loading_test_util.h
+++ b/chrome/browser/predictors/loading_test_util.h
@@ -36,11 +36,6 @@
 
   MOCK_CONST_METHOD2(GetPrefetchData,
                      bool(const GURL&, ResourcePrefetchPredictor::Prediction*));
-  MOCK_METHOD0(StartInitialization, void());
-  MOCK_METHOD0(Shutdown, void());
-  MOCK_METHOD2(StartPrefetching,
-               void(const GURL&, const ResourcePrefetchPredictor::Prediction&));
-  MOCK_METHOD1(StopPrefeching, void(const GURL&));
   MOCK_METHOD1(RecordPageRequestSummaryProxy, void(PageRequestSummary*));
 };
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 222a42a..08180fd 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -79,7 +79,7 @@
 #include "components/language/core/browser/url_language_histogram.h"
 #include "components/network_time/network_time_tracker.h"
 #include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
-#include "components/ntp_snippets/breaking_news/subscription_manager.h"
+#include "components/ntp_snippets/breaking_news/subscription_manager_impl.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
 #include "components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h"
@@ -477,7 +477,7 @@
   ntp_snippets::RemoteSuggestionsProviderImpl::RegisterProfilePrefs(registry);
   ntp_snippets::RemoteSuggestionsSchedulerImpl::RegisterProfilePrefs(registry);
   ntp_snippets::RequestThrottler::RegisterProfilePrefs(registry);
-  ntp_snippets::SubscriptionManager::RegisterProfilePrefs(registry);
+  ntp_snippets::SubscriptionManagerImpl::RegisterProfilePrefs(registry);
   ntp_snippets::UserClassifier::RegisterProfilePrefs(registry);
   ntp_tiles::MostVisitedSites::RegisterProfilePrefs(registry);
   password_bubble_experiment::RegisterPrefs(registry);
diff --git a/chrome/browser/resources/media/OWNERS b/chrome/browser/resources/media/OWNERS
new file mode 100644
index 0000000..77384f3
--- /dev/null
+++ b/chrome/browser/resources/media/OWNERS
@@ -0,0 +1,8 @@
+# For Media Engagement
+mlamouri@chromium.org
+beccahughes@chromium.org
+
+# For WebRTC
+per-file webrtc_*=file://third_party/webrtc_overrides/OWNERS
+
+# COMPONENT: Internals>Media>UI
diff --git a/chrome/browser/resources/media/media_engagement.html b/chrome/browser/resources/media/media_engagement.html
new file mode 100644
index 0000000..77b8ed85
--- /dev/null
+++ b/chrome/browser/resources/media/media_engagement.html
@@ -0,0 +1,129 @@
+<!doctype html>
+<html>
+<head>
+  <title>Media Engagement</title>
+  <meta charset="utf-8">
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+  <script src="chrome://resources/js/mojo_bindings.js"></script>
+  <script src="chrome://resources/js/promise_resolver.js"></script>
+  <script src="chrome://resources/js/util.js"></script>
+
+  <script src="chrome/browser/media/media_engagement_score_details.mojom.js">
+  </script>
+
+  <script src="chrome://media-engagement/media-engagement.js"></script>
+  <style>
+    body {
+      font-family: 'Roboto', 'Noto', sans-serif;
+      font-size: 14px;
+    }
+
+    table {
+      border-collapse: collapse;
+    }
+
+    table td,
+    table th {
+      border: 1px solid #777;
+      padding-left: 4px;
+      padding-right: 4px;
+    }
+
+    table th {
+      background: rgb(224, 236, 255);
+      cursor: pointer;
+      padding-bottom: 4px;
+      padding-right: 16px;
+      padding-top: 4px;
+      white-space: nowrap;
+    }
+
+    .engagement-bar {
+      background-color: black;
+      height: 2px;
+    }
+
+    .engagement-bar-cell {
+      border: none;
+    }
+
+    .origin-cell {
+      background-color: rgba(230, 230, 230, 0.5);
+      min-width: 500px;
+    }
+
+    .visits-count-cell,
+    .media-playbacks-count-cell,
+    .last-playback-time-cell {
+      background-color: rgba(230, 230, 230, 0.5);
+      text-align: right;
+    }
+
+    .base-score-input {
+      border: 1px solid #ccc;
+      border-radius: 2px;
+      text-align: right;
+      width: 70px;
+    }
+
+    .base-score-input:focus {
+      border: 1px solid rgb(143, 185, 252);
+      box-shadow: 0 0 2px rgb(113, 158, 206);
+      outline: none;
+    }
+
+    table tr:hover {
+      background: rgb(255, 255, 187);
+    }
+
+    th.sort-column::after {
+      content: 'â–²';
+      position: absolute;
+    }
+
+    th[sort-reverse].sort-column::after {
+      content: 'â–¼';
+      position: absolute;
+    }
+  </style>
+</head>
+<body>
+  <h1>Media Engagement</h1>
+  <table>
+    <thead>
+      <tr id="engagement-table-header">
+        <th sort-key="origin">
+          Origin
+        </th>
+        <th sort-key="visits" sort-reverse>
+          Visits
+        </th>
+        <th sort-key="mediaPlaybacks" sort-reverse>
+          Number of Playbacks
+        </th>
+        <th sort-key="lastMediaPlaybackTime" sort-reverse>
+          Last Playback
+        </th>
+        <th sort-key="totalScore" class="sort-column" sort-reverse>
+          Score
+        </th>
+      </tr>
+    </thead>
+    <tbody id="engagement-table-body">
+    </tbody>
+  </table>
+
+  <template id="datarow">
+    <tr>
+      <td class="origin-cell"></td>
+      <td class="visits-count-cell"></td>
+      <td class="media-playbacks-count-cell"></td>
+      <td class="last-playback-time-cell"></td>
+      <td class="total-score-cell"></td>
+      <td class="engagement-bar-cell">
+        <div class="engagement-bar"></div>
+      </td>
+    </tr>
+  </template>
+</body>
+</html>
diff --git a/chrome/browser/resources/media/media_engagement.js b/chrome/browser/resources/media/media_engagement.js
new file mode 100644
index 0000000..c93a301c
--- /dev/null
+++ b/chrome/browser/resources/media/media_engagement.js
@@ -0,0 +1,136 @@
+// 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.
+
+'use strict';
+
+// Allow a function to be provided by tests, which will be called when
+// the page has been populated with media engagement details.
+var pageIsPopulatedResolver = new PromiseResolver();
+function whenPageIsPopulatedForTest() {
+  return pageIsPopulatedResolver.promise;
+}
+
+(function() {
+
+var uiHandler = null;
+var info = null;
+var engagementTableBody = null;
+var sortReverse = true;
+var sortKey = 'totalScore';
+
+/**
+ * Creates a single row in the engagement table.
+ * @param {!MediaEngagementScoreDetails} rowInfo The info to create the row.
+ * @return {!HTMLElement}
+ */
+function createRow(rowInfo) {
+  var template = $('datarow');
+  var td = template.content.querySelectorAll('td');
+  td[0].textContent = rowInfo.origin.url;
+  td[1].textContent = rowInfo.visits;
+  td[2].textContent = rowInfo.mediaPlaybacks;
+  td[3].textContent = rowInfo.lastMediaPlaybackTime ?
+      new Date(rowInfo.lastMediaPlaybackTime).toISOString() :
+      '';
+  td[4].textContent = rowInfo.totalScore ? rowInfo.totalScore.toFixed(2) : '0';
+  td[5].getElementsByClassName('engagement-bar')[0].style.width =
+      (rowInfo.totalScore * 50) + 'px';
+  return document.importNode(template.content, true);
+}
+
+/**
+ * Remove all rows from the engagement table.
+ */
+function clearTable() {
+  engagementTableBody.innerHTML = '';
+}
+
+/**
+ * Sort the engagement info based on |sortKey| and |sortReverse|.
+ */
+function sortInfo() {
+  info.sort((a, b) => {
+    return (sortReverse ? -1 : 1) * compareTableItem(sortKey, a, b);
+  });
+}
+
+/**
+ * Compares two MediaEngagementScoreDetails objects based on |sortKey|.
+ * @param {string} sortKey The name of the property to sort by.
+ * @param {number|url.mojom.Url} The first object to compare.
+ * @param {number|url.mojom.Url} The second object to compare.
+ * @return {number} A negative number if |a| should be ordered before
+ *     |b|, a positive number otherwise.
+ */
+function compareTableItem(sortKey, a, b) {
+  var val1 = a[sortKey];
+  var val2 = b[sortKey];
+
+  // Compare the hosts of the origin ignoring schemes.
+  if (sortKey == 'origin')
+    return new URL(val1.url).host > new URL(val2.url).host ? 1 : -1;
+
+  if (sortKey == 'visits' || sortKey == 'mediaPlaybacks' ||
+      sortKey == 'lastMediaPlaybackTime' || sortKey == 'totalScore') {
+    return val1 - val2;
+  }
+
+  assertNotReached('Unsupported sort key: ' + sortKey);
+  return 0;
+}
+
+/**
+ * Regenerates the engagement table from |info|.
+ */
+function renderTable() {
+  clearTable();
+  sortInfo();
+  info.forEach(rowInfo => engagementTableBody.appendChild(createRow(rowInfo)));
+}
+
+/**
+ * Retrieve media engagement info and render the engagement table.
+ */
+function updateEngagementTable() {
+  // Populate engagement table.
+  uiHandler.getMediaEngagementScoreDetails().then(response => {
+    info = response.info;
+    renderTable();
+    pageIsPopulatedResolver.resolve();
+  });
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+  uiHandler = new media.mojom.MediaEngagementScoreDetailsProviderPtr;
+  Mojo.bindInterface(
+      media.mojom.MediaEngagementScoreDetailsProvider.name,
+      mojo.makeRequest(uiHandler).handle);
+  updateEngagementTable();
+
+  engagementTableBody = $('engagement-table-body');
+
+  // Set table header sort handlers.
+  var engagementTableHeader = $('engagement-table-header');
+  var headers = engagementTableHeader.children;
+  for (var i = 0; i < headers.length; i++) {
+    headers[i].addEventListener('click', (e) => {
+      var newSortKey = e.target.getAttribute('sort-key');
+      if (sortKey == newSortKey) {
+        sortReverse = !sortReverse;
+      } else {
+        sortKey = newSortKey;
+        sortReverse = false;
+      }
+      var oldSortColumn = document.querySelector('.sort-column');
+      oldSortColumn.classList.remove('sort-column');
+      e.target.classList.add('sort-column');
+      if (sortReverse)
+        e.target.setAttribute('sort-reverse', '');
+      else
+        e.target.removeAttribute('sort-reverse');
+      renderTable();
+    });
+  }
+});
+})();
diff --git a/chrome/browser/search_engines/template_url_parser_unittest.cc b/chrome/browser/search_engines/template_url_parser_unittest.cc
index ea31c628..0f5871f 100644
--- a/chrome/browser/search_engines/template_url_parser_unittest.cc
+++ b/chrome/browser/search_engines/template_url_parser_unittest.cc
@@ -95,27 +95,26 @@
                                            contents.length(), filter);
 }
 
-
 // Actual tests ---------------------------------------------------------------
 
 TEST_F(TemplateURLParserTest, FailOnBogusURL) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("bogus.xml", NULL));
-  EXPECT_FALSE(template_url_.get());
+  ASSERT_NO_FATAL_FAILURE(ParseFile("bogus.xml", nullptr));
+  EXPECT_FALSE(template_url_);
 }
 
 TEST_F(TemplateURLParserTest, PassOnHTTPS) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("https.xml", NULL));
-  EXPECT_TRUE(template_url_.get());
+  ASSERT_NO_FATAL_FAILURE(ParseFile("https.xml", nullptr));
+  EXPECT_TRUE(template_url_);
 }
 
 TEST_F(TemplateURLParserTest, FailOnPost) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("post.xml", NULL));
-  EXPECT_FALSE(template_url_.get());
+  ASSERT_NO_FATAL_FAILURE(ParseFile("post.xml", nullptr));
+  EXPECT_FALSE(template_url_);
 }
 
 TEST_F(TemplateURLParserTest, TestDictionary) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("dictionary.xml", NULL));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_NO_FATAL_FAILURE(ParseFile("dictionary.xml", nullptr));
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("Dictionary.com"), template_url_->short_name());
   EXPECT_EQ(GURL("http://cache.lexico.com/g/d/favicon.ico"),
             template_url_->favicon_url());
@@ -125,8 +124,8 @@
 }
 
 TEST_F(TemplateURLParserTest, TestMSDN) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("msdn.xml", NULL));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_NO_FATAL_FAILURE(ParseFile("msdn.xml", nullptr));
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("Search \" MSDN"), template_url_->short_name());
   EXPECT_EQ(GURL("http://search.msdn.microsoft.com/search/favicon.ico"),
             template_url_->favicon_url());
@@ -137,8 +136,8 @@
 }
 
 TEST_F(TemplateURLParserTest, TestWikipedia) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("wikipedia.xml", NULL));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_NO_FATAL_FAILURE(ParseFile("wikipedia.xml", nullptr));
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("Wikipedia (English)"), template_url_->short_name());
   EXPECT_EQ(GURL("http://en.wikipedia.org/favicon.ico"),
             template_url_->favicon_url());
@@ -157,7 +156,7 @@
 }
 
 TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) {
-  ASSERT_NO_FATAL_FAILURE(ParseFile("url_with_no_attributes.xml", NULL));
+  ASSERT_NO_FATAL_FAILURE(ParseFile("url_with_no_attributes.xml", nullptr));
 }
 
 TEST_F(TemplateURLParserTest, TestFirefoxEbay) {
@@ -165,7 +164,7 @@
   // (see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0)
   ParamFilterImpl filter("ebay", "ebay");
   ASSERT_NO_FATAL_FAILURE(ParseFile("firefox_ebay.xml", &filter));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("eBay"), template_url_->short_name());
   EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData()));
   EXPECT_EQ("http://search.ebay.com/search/search.dll?query={searchTerms}&"
@@ -182,7 +181,7 @@
   // This XML file uses a namespace.
   ParamFilterImpl filter(std::string(), "Mozilla");
   ASSERT_NO_FATAL_FAILURE(ParseFile("firefox_webster.xml", &filter));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("Webster"), template_url_->short_name());
   EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData()));
   EXPECT_EQ("http://www.webster.com/cgi-bin/dictionary?va={searchTerms}",
@@ -197,7 +196,7 @@
   // This XML file uses a namespace.
   ParamFilterImpl filter(std::string(), "Mozilla");
   ASSERT_NO_FATAL_FAILURE(ParseFile("firefox_yahoo.xml", &filter));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("Yahoo"), template_url_->short_name());
   EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData()));
   EXPECT_EQ("http://ff.search.yahoo.com/gossip?"
@@ -217,7 +216,7 @@
   // This XML file uses a namespace.
   ParamFilterImpl filter(std::string(), "Mozilla");
   ASSERT_NO_FATAL_FAILURE(ParseFile("post_suggestion.xml", &filter));
-  ASSERT_TRUE(template_url_.get());
+  ASSERT_TRUE(template_url_);
   EXPECT_EQ(ASCIIToUTF16("Yahoo"), template_url_->short_name());
   EXPECT_TRUE(template_url_->url_ref().SupportsReplacement(SearchTermsData()));
   EXPECT_TRUE(template_url_->suggestions_url().empty());
@@ -228,3 +227,24 @@
   EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
             template_url_->favicon_url());
 }
+
+// <Alias> tags are parsed and used as keyword for the template URL.
+TEST_F(TemplateURLParserTest, TestKeyword) {
+  ASSERT_NO_FATAL_FAILURE(ParseFile("keyword.xml", nullptr));
+  ASSERT_TRUE(template_url_);
+  EXPECT_EQ(ASCIIToUTF16("Example"), template_url_->short_name());
+  EXPECT_EQ("https://www.example.com/search?q={searchTerms}",
+            template_url_->url());
+  EXPECT_EQ(ASCIIToUTF16("moose"), template_url_->keyword());
+}
+
+// Empty <Alias> tags are ignored and the default keyword is used instead
+// (because empty keywords are not allowed).
+TEST_F(TemplateURLParserTest, TestEmptyKeyword) {
+  ASSERT_NO_FATAL_FAILURE(ParseFile("empty_keyword.xml", nullptr));
+  ASSERT_TRUE(template_url_);
+  EXPECT_EQ(ASCIIToUTF16("Example"), template_url_->short_name());
+  EXPECT_EQ("https://www.example.com/search?q={searchTerms}",
+            template_url_->url());
+  EXPECT_EQ(ASCIIToUTF16("example.com"), template_url_->keyword());
+}
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
index bb6f33f8..e802f2cd 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
@@ -93,8 +93,7 @@
         content::BrowserThread::IO);
     worker_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
         {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-    file_task_runner_ = content::BrowserThread::GetTaskRunnerForThread(
-        content::BrowserThread::FILE);
+    file_task_runner_ = io_task_runner_;
     scoped_refptr<base::SequencedTaskRunner> drive_task_runner =
         base::CreateSequencedTaskRunnerWithTraits(
             {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
index bf74fee5..1185cd93 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
@@ -59,9 +59,7 @@
 class LocalFileSyncContextTest : public testing::Test {
  protected:
   LocalFileSyncContextTest()
-      : thread_bundle_(
-            content::TestBrowserThreadBundle::REAL_FILE_THREAD |
-            content::TestBrowserThreadBundle::REAL_IO_THREAD),
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD),
         status_(SYNC_FILE_ERROR_FAILED),
         file_error_(base::File::FILE_ERROR_FAILED),
         async_modify_finished_(false),
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
index e4b5ad43..b7486626 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -108,8 +109,7 @@
       public LocalFileSyncService::Observer {
  protected:
   LocalFileSyncServiceTest()
-      : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD |
-                       content::TestBrowserThreadBundle::REAL_IO_THREAD),
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD),
         num_changes_(0) {}
 
   void SetUp() override {
@@ -119,7 +119,7 @@
     file_system_.reset(new CannedSyncableFileSystem(
         GURL(kOrigin), in_memory_env_.get(),
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
-        BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE)));
+        base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()})));
 
     local_service_ = LocalFileSyncService::CreateForTesting(
         &profile_, in_memory_env_.get());
@@ -145,7 +145,8 @@
     local_service_->Shutdown();
     file_system_->TearDown();
     RevokeSyncableFileSystem();
-    content::RunAllPendingInMessageLoop(BrowserThread::FILE);
+
+    base::TaskScheduler::GetInstance()->FlushForTesting();
     content::RunAllPendingInMessageLoop(BrowserThread::IO);
   }
 
@@ -301,7 +302,7 @@
   CannedSyncableFileSystem file_system2(
       GURL(kOrigin2), in_memory_env_.get(),
       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE));
+      base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()}));
   file_system2.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
 
   base::RunLoop run_loop;
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
index ec053959..f00b719e 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
@@ -128,15 +129,14 @@
 class SyncFileSystemServiceTest : public testing::Test {
  protected:
   SyncFileSystemServiceTest()
-      : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD |
-                       content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
 
   void SetUp() override {
     in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
     file_system_.reset(new CannedSyncableFileSystem(
         GURL(kOrigin), in_memory_env_.get(),
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
-        BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE)));
+        base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()})));
 
     std::unique_ptr<LocalFileSyncService> local_service =
         LocalFileSyncService::CreateForTesting(&profile_, in_memory_env_.get());
@@ -168,7 +168,7 @@
     sync_service_->Shutdown();
     file_system_->TearDown();
     RevokeSyncableFileSystem();
-    content::RunAllPendingInMessageLoop(BrowserThread::FILE);
+    base::TaskScheduler::GetInstance()->FlushForTesting();
   }
 
   void InitializeApp() {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index d5e1265..1405159c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -367,6 +367,8 @@
     "webui/local_state/local_state_ui.h",
     "webui/log_web_ui_url.cc",
     "webui/log_web_ui_url.h",
+    "webui/media/media_engagement_ui.cc",
+    "webui/media/media_engagement_ui.h",
     "webui/metrics_handler.cc",
     "webui/metrics_handler.h",
     "webui/mojo_web_ui_controller.cc",
@@ -479,6 +481,7 @@
     "//chrome/browser:resource_prefetch_predictor_proto",
     "//chrome/browser/devtools",
     "//chrome/browser/engagement:mojo_bindings",
+    "//chrome/browser/media:mojo_bindings",
     "//chrome/browser/safe_browsing",
     "//chrome/browser/ui/webui/omnibox:mojo_bindings",
     "//chrome/browser/ui/webui/usb_internals:mojo_bindings",
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 9e9a644b..234c6ef 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/devtools/devtools_ui_bindings.h"
 #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
+#include "chrome/browser/media/media_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search/suggestions/suggestions_ui.h"
@@ -38,6 +39,7 @@
 #include "chrome/browser/ui/webui/invalidations_ui.h"
 #include "chrome/browser/ui/webui/local_state/local_state_ui.h"
 #include "chrome/browser/ui/webui/log_web_ui_url.h"
+#include "chrome/browser/ui/webui/media/media_engagement_ui.h"
 #include "chrome/browser/ui/webui/net_export_ui.h"
 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
@@ -626,6 +628,11 @@
     return &NewWebUI<SiteEngagementUI>;
   }
 
+  if (MediaEngagementService::IsEnabled() &&
+      url.host_piece() == chrome::kChromeUIMediaEngagementHost) {
+    return &NewWebUI<MediaEngagementUI>;
+  }
+
   return NULL;
 }
 
diff --git a/chrome/browser/ui/webui/media/OWNERS b/chrome/browser/ui/webui/media/OWNERS
new file mode 100644
index 0000000..77384f3
--- /dev/null
+++ b/chrome/browser/ui/webui/media/OWNERS
@@ -0,0 +1,8 @@
+# For Media Engagement
+mlamouri@chromium.org
+beccahughes@chromium.org
+
+# For WebRTC
+per-file webrtc_*=file://third_party/webrtc_overrides/OWNERS
+
+# COMPONENT: Internals>Media>UI
diff --git a/chrome/browser/ui/webui/media/media_engagement_ui.cc b/chrome/browser/ui/webui/media/media_engagement_ui.cc
new file mode 100644
index 0000000..ff0206a
--- /dev/null
+++ b/chrome/browser/ui/webui/media/media_engagement_ui.cc
@@ -0,0 +1,77 @@
+// 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 "chrome/browser/ui/webui/media/media_engagement_ui.h"
+
+#include "base/macros.h"
+#include "chrome/browser/media/media_engagement_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace {
+
+// Implementation of media::mojom::MediaEngagementScoreDetailsProvider that
+// retrieves engagement details from the MediaEngagementService.
+class MediaEngagementScoreDetailsProviderImpl
+    : public media::mojom::MediaEngagementScoreDetailsProvider {
+ public:
+  MediaEngagementScoreDetailsProviderImpl(
+      Profile* profile,
+      mojo::InterfaceRequest<media::mojom::MediaEngagementScoreDetailsProvider>
+          request)
+      : profile_(profile), binding_(this, std::move(request)) {
+    DCHECK(profile_);
+    service_ = MediaEngagementService::Get(profile_);
+  }
+
+  ~MediaEngagementScoreDetailsProviderImpl() override {}
+
+  // media::mojom::MediaEngagementScoreDetailsProvider overrides:
+  void GetMediaEngagementScoreDetails(
+      media::mojom::MediaEngagementScoreDetailsProvider::
+          GetMediaEngagementScoreDetailsCallback callback) override {
+    std::move(callback).Run(service_->GetAllScoreDetails());
+  }
+
+ private:
+  Profile* profile_;
+
+  MediaEngagementService* service_;
+
+  mojo::Binding<media::mojom::MediaEngagementScoreDetailsProvider> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaEngagementScoreDetailsProviderImpl);
+};
+
+}  // namespace
+
+MediaEngagementUI::MediaEngagementUI(content::WebUI* web_ui)
+    : MojoWebUIController<media::mojom::MediaEngagementScoreDetailsProvider>(
+          web_ui) {
+  // Setup the data source behind chrome://media-engagement.
+  std::unique_ptr<content::WebUIDataSource> source(
+      content::WebUIDataSource::Create(chrome::kChromeUIMediaEngagementHost));
+  source->AddResourcePath("media-engagement.js", IDR_MEDIA_ENGAGEMENT_JS);
+  source->AddResourcePath(
+      "chrome/browser/media/media_engagement_score_details.mojom.js",
+      IDR_MEDIA_ENGAGEMENT_MOJO_JS);
+  source->AddResourcePath("url/mojo/url.mojom.js", IDR_URL_MOJO_JS);
+  source->SetDefaultResource(IDR_MEDIA_ENGAGEMENT_HTML);
+  source->UseGzip(std::unordered_set<std::string>());
+  content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release());
+}
+
+MediaEngagementUI::~MediaEngagementUI() = default;
+
+void MediaEngagementUI::BindUIHandler(
+    const service_manager::BindSourceInfo& source_info,
+    media::mojom::MediaEngagementScoreDetailsProviderRequest request) {
+  ui_handler_ = base::MakeUnique<MediaEngagementScoreDetailsProviderImpl>(
+      Profile::FromWebUI(web_ui()), std::move(request));
+}
diff --git a/chrome/browser/ui/webui/media/media_engagement_ui.h b/chrome/browser/ui/webui/media/media_engagement_ui.h
new file mode 100644
index 0000000..3677cfc
--- /dev/null
+++ b/chrome/browser/ui/webui/media/media_engagement_ui.h
@@ -0,0 +1,32 @@
+// 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 CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_ENGAGEMENT_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_ENGAGEMENT_UI_H_
+
+#include "base/macros.h"
+#include "chrome/browser/media/media_engagement_score_details.mojom.h"
+#include "chrome/browser/ui/webui/mojo_web_ui_controller.h"
+
+// The UI for chrome://media-engagement/.
+class MediaEngagementUI
+    : public MojoWebUIController<
+          media::mojom::MediaEngagementScoreDetailsProvider> {
+ public:
+  explicit MediaEngagementUI(content::WebUI* web_ui);
+  ~MediaEngagementUI() override;
+
+ private:
+  // MojoWebUIController overrides:
+  void BindUIHandler(const service_manager::BindSourceInfo& source_info,
+                     media::mojom::MediaEngagementScoreDetailsProviderRequest
+                         request) override;
+
+  std::unique_ptr<media::mojom::MediaEngagementScoreDetailsProvider>
+      ui_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaEngagementUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_ENGAGEMENT_UI_H_
diff --git a/chrome/browser/ui/webui/predictors/predictors_handler.cc b/chrome/browser/ui/webui/predictors/predictors_handler.cc
index 6156657d..e078a66 100644
--- a/chrome/browser/ui/webui/predictors/predictors_handler.cc
+++ b/chrome/browser/ui/webui/predictors/predictors_handler.cc
@@ -99,25 +99,31 @@
   if (enabled) {
     auto* resource_prefetch_predictor =
         loading_predictor_->resource_prefetch_predictor();
-    // URL table cache.
-    auto db = base::MakeUnique<base::ListValue>();
-    AddPrefetchDataMapToListValue(
-        *resource_prefetch_predictor->url_resource_data_->data_cache_,
-        db.get());
-    dict.Set("url_db", std::move(db));
+    const bool initialized =
+        resource_prefetch_predictor->initialization_state_ ==
+        ResourcePrefetchPredictor::INITIALIZED;
 
-    // Host table cache.
-    db = base::MakeUnique<base::ListValue>();
-    AddPrefetchDataMapToListValue(
-        *resource_prefetch_predictor->host_resource_data_->data_cache_,
-        db.get());
-    dict.Set("host_db", std::move(db));
+    if (initialized) {
+      // URL table cache.
+      auto db = base::MakeUnique<base::ListValue>();
+      AddPrefetchDataMapToListValue(
+          *resource_prefetch_predictor->url_resource_data_->data_cache_,
+          db.get());
+      dict.Set("url_db", std::move(db));
 
-    // Origin table cache.
-    db = base::MakeUnique<base::ListValue>();
-    AddOriginDataMapToListValue(
-        *resource_prefetch_predictor->origin_data_->data_cache_, db.get());
-    dict.Set("origin_db", std::move(db));
+      // Host table cache.
+      db = base::MakeUnique<base::ListValue>();
+      AddPrefetchDataMapToListValue(
+          *resource_prefetch_predictor->host_resource_data_->data_cache_,
+          db.get());
+      dict.Set("host_db", std::move(db));
+
+      // Origin table cache.
+      db = base::MakeUnique<base::ListValue>();
+      AddOriginDataMapToListValue(
+          *resource_prefetch_predictor->origin_data_->data_cache_, db.get());
+      dict.Set("origin_db", std::move(db));
+    }
   }
 
   web_ui()->CallJavascriptFunctionUnsafe("updateResourcePrefetchPredictorDb",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 005ffb0..bc9f668 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -96,6 +96,7 @@
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_MACOSX)
 
+// Enables Basic/Advanced tabs in ClearBrowsingData.
 const base::Feature kTabsInCbd {
   "TabsInCBD",
 #if defined(OS_ANDROID)
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 950f544e..0be3dc30 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -221,6 +221,7 @@
 const char kChromeUILocalStateHost[] = "local-state";
 const char kChromeUIMdPolicyHost[] = "md-policy";
 const char kChromeUIMdSettingsHost[] = "md-settings";
+const char kChromeUIMediaEngagementHost[] = "media-engagement";
 const char kChromeUINaClHost[] = "nacl";
 const char kChromeUINetExportHost[] = "net-export";
 const char kChromeUINetInternalsHost[] = "net-internals";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index ec9a397..becff52c 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -62,6 +62,8 @@
 extern const char kChromeUIInterstitialURL[];
 extern const char kChromeUIInvalidationsURL[];
 extern const char kChromeUIMdPolicyURL[];
+extern const char kChromeUIMdSettingsURL[];
+extern const char kChromeUIMediaEngagementHost[];
 extern const char kChromeUINaClURL[];
 extern const char kChromeUINetInternalsURL[];
 extern const char kChromeUINewProfileURL[];
@@ -74,7 +76,6 @@
 extern const char kChromeUIPrintURL[];
 extern const char kChromeUIQuitURL[];
 extern const char kChromeUIRestartURL[];
-extern const char kChromeUIMdSettingsURL[];
 extern const char kChromeUISettingsURL[];
 extern const char kChromeUIContentSettingsURL[];
 // TODO(dbeam): remove settings-frame.
diff --git a/chrome/installer/zucchini/BUILD.gn b/chrome/installer/zucchini/BUILD.gn
index b1fbd88..ce699f0 100644
--- a/chrome/installer/zucchini/BUILD.gn
+++ b/chrome/installer/zucchini/BUILD.gn
@@ -21,6 +21,7 @@
     "io_utils.h",
     "main_utils.cc",
     "main_utils.h",
+    "patch_utils.h",
     "suffix_array.h",
     "typed_value.h",
   ]
@@ -60,6 +61,7 @@
     "buffer_view_unittest.cc",
     "crc32_unittest.cc",
     "io_utils_unittest.cc",
+    "patch_utils_unittest.cc",
     "suffix_array_unittest.cc",
     "typed_value_unittest.cc",
   ]
diff --git a/chrome/installer/zucchini/patch_utils.h b/chrome/installer/zucchini/patch_utils.h
new file mode 100644
index 0000000..27d9bc61
--- /dev/null
+++ b/chrome/installer/zucchini/patch_utils.h
@@ -0,0 +1,143 @@
+// 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 CHROME_INSTALLER_ZUCCHINI_PATCH_UTILS_H_
+#define CHROME_INSTALLER_ZUCCHINI_PATCH_UTILS_H_
+
+#include <cstdint>
+#include <type_traits>
+
+#include "base/logging.h"
+#include "base/optional.h"
+#include "chrome/installer/zucchini/image_utils.h"
+
+namespace zucchini {
+
+// Constants that appear inside a patch.
+enum class PatchType : uint32_t {
+  kRawPatch = 0,
+  kSinglePatch = 1,
+  kEnsemblePatch = 2,
+  kUnrecognisedPatch,
+};
+
+// A Zucchini 'ensemble' patch is the concatenation of a patch header with a
+// list of patch 'elements', each containing data for patching individual
+// elements.
+
+// Supported by MSVC, g++, and clang++. Ensures no gaps in packing.
+#pragma pack(push, 1)
+
+// Header for a Zucchini patch, found at the begining of an ensemble patch.
+struct PatchHeader {
+  // Magic signature at the beginning of a Zucchini patch file.
+  static constexpr uint32_t kMagic = 'Z' | ('u' << 8) | ('c' << 16);
+
+  uint32_t magic = 0;
+  uint32_t old_size = 0;
+  uint32_t old_crc = 0;
+  uint32_t new_size = 0;
+  uint32_t new_crc = 0;
+};
+
+// Sanity check.
+static_assert(sizeof(PatchHeader) == 20, "PatchHeader is 20 bytes");
+
+// Header for a patch element, found at the begining of every patch element.
+struct PatchElementHeader {
+  uint32_t old_offset;
+  uint32_t new_offset;
+  uint64_t old_length;
+  uint64_t new_length;
+  uint32_t exe_type;
+};
+
+// Sanity check.
+static_assert(sizeof(PatchElementHeader) == 28,
+              "PatchElementHeader is 28 bytes");
+
+#pragma pack(pop)
+
+// Descibes a raw FIX operation.
+struct RawDeltaUnit {
+  offset_t copy_offset;  // Offset in copy regions starting from last delta.
+  int8_t diff;           // Bytewise difference.
+};
+
+// A Zucchini patch contains data streams encoded using varint format to reduce
+// uncompressed size. This is a variable-length encoding for integer quantities
+// that strips away leading (most-significant) null bytes.
+
+// Writes |value| as a varint in |dst| and returns an iterator pointing beyond
+// the written region. |dst| is assumed to hold enough space. Typically, this
+// will write to a vector using back insertion, e.g.:
+//   EncodeVarUInt(value, std::back_inserter(vector));
+template <class T, class It>
+It EncodeVarUInt(T value, It dst) {
+  static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
+
+  while (value >= 128) {
+    *dst++ = static_cast<uint8_t>(value) | 128;
+    value >>= 7;
+  }
+  *dst++ = static_cast<uint8_t>(value);
+  return dst;
+}
+
+// Same as EncodeVarUInt(), but for signed values.
+template <class T, class It>
+It EncodeVarInt(T value, It dst) {
+  static_assert(std::is_signed<T>::value, "Value type must be signed");
+
+  using unsigned_value_type = typename std::make_unsigned<T>::type;
+  if (value < 0)
+    return EncodeVarUInt((unsigned_value_type(~value) << 1) | 1, dst);
+  else
+    return EncodeVarUInt(unsigned_value_type(value) << 1, dst);
+}
+
+// Tries to read a varint unsigned integer from [|first|, |last|). If
+// succesfull, writes result into |value| and returns an iterator pointing
+// beyond the formatted varint. Otherwise returns nullopt.
+template <class T, class It>
+base::Optional<It> DecodeVarUInt(It first, It last, T* value) {
+  static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
+
+  uint8_t sh = 0;
+  T val = 0;
+  while (first != last) {
+    val |= T(*first & 0x7F) << sh;
+    if (*(first++) < 0x80) {
+      *value = val;
+      return first;
+    }
+    sh += 7;
+    if (sh >= sizeof(T) * 8) {  // Overflow!
+      LOG(ERROR) << "Overflow encountered.";
+      return base::nullopt;
+    }
+  }
+  LOG(ERROR) << "Exhausted data while reading.";
+  return base::nullopt;
+}
+
+// Same as DecodeVarUInt(), but for signed values.
+template <class T, class It>
+base::Optional<It> DecodeVarInt(It first, It last, T* value) {
+  static_assert(std::is_signed<T>::value, "Value type must be signed");
+
+  typename std::make_unsigned<T>::type tmp = 0;
+  auto res = DecodeVarUInt(first, last, &tmp);
+  if (!res)
+    return res;
+  if (tmp & 1)
+    *value = ~static_cast<T>(tmp >> 1);
+  else
+    *value = static_cast<T>(tmp >> 1);
+  return res;
+}
+
+}  // namespace zucchini
+
+#endif  // CHROME_INSTALLER_ZUCCHINI_PATCH_UTILS_H_
diff --git a/chrome/installer/zucchini/patch_utils_unittest.cc b/chrome/installer/zucchini/patch_utils_unittest.cc
new file mode 100644
index 0000000..3241dc1c
--- /dev/null
+++ b/chrome/installer/zucchini/patch_utils_unittest.cc
@@ -0,0 +1,162 @@
+// 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 "chrome/installer/zucchini/patch_utils.h"
+
+#include <cstdint>
+#include <iterator>
+#include <vector>
+
+#include "base/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace zucchini {
+
+template <class T>
+void TestEncodeDecodeVarUInt(const std::vector<T>& data) {
+  std::vector<uint8_t> buffer;
+
+  std::vector<T> values;
+  for (T basis : data) {
+    // For variety, test the neighborhood values for each case in |data|. Some
+    // test cases may result in overflow when computing |value|, but we don't
+    // care about that.
+    for (int delta = -4; delta <= 4; ++delta) {
+      T value = delta + basis;
+      EncodeVarUInt<T>(value, std::back_inserter(buffer));
+      values.push_back(value);
+
+      value = delta - basis;
+      EncodeVarUInt<T>(value, std::back_inserter(buffer));
+      values.push_back(value);
+    }
+  }
+
+  auto it = buffer.begin();
+  for (T expected : values) {
+    T value = T(-1);
+    auto res = DecodeVarUInt(it, buffer.end(), &value);
+    EXPECT_TRUE(res.has_value());
+    EXPECT_EQ(expected, value);
+    it = res.value();
+  }
+  EXPECT_EQ(it, buffer.end());
+
+  T dummy = T(-1);
+  auto res = DecodeVarUInt(it, buffer.end(), &dummy);
+  EXPECT_EQ(base::nullopt, res);
+  EXPECT_EQ(T(-1), dummy);
+}
+
+template <class T>
+void TestEncodeDecodeVarInt(const std::vector<T>& data) {
+  std::vector<uint8_t> buffer;
+
+  std::vector<T> values;
+  for (T basis : data) {
+    // For variety, test the neighborhood values for each case in |data|. Some
+    // test cases may result in overflow when computing |value|, but we don't
+    // care about that.
+    for (int delta = -4; delta <= 4; ++delta) {
+      T value = delta + basis;
+      EncodeVarInt(value, std::back_inserter(buffer));
+      values.push_back(value);
+
+      value = delta - basis;
+      EncodeVarInt(value, std::back_inserter(buffer));
+      values.push_back(value);
+    }
+  }
+
+  auto it = buffer.begin();
+  for (T expected : values) {
+    T value = T(-1);
+    auto res = DecodeVarInt(it, buffer.end(), &value);
+    EXPECT_TRUE(res.has_value());
+    EXPECT_EQ(expected, value);
+    it = res.value();
+  }
+  T dummy = T(-1);
+  auto res = DecodeVarInt(it, buffer.end(), &dummy);
+  EXPECT_EQ(base::nullopt, res);
+  EXPECT_EQ(T(-1), dummy);
+}
+
+TEST(PatchUtilsTest, EncodeDecodeVarUInt32) {
+  TestEncodeDecodeVarUInt<uint32_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
+                                     1 << 22, 1 << 27, 1 << 28, 0x7FFFFFFF,
+                                     UINT32_MAX});
+}
+
+TEST(PatchUtilsTest, EncodeDecodeVarInt32) {
+  TestEncodeDecodeVarInt<int32_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
+                                   1 << 22, 1 << 27, 1 << 28, -1, INT32_MIN,
+                                   INT32_MAX});
+}
+
+TEST(PatchUtilsTest, EncodeDecodeVarUInt64) {
+  TestEncodeDecodeVarUInt<uint64_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
+                                     1 << 22, 1ULL << 55, 1ULL << 56,
+                                     0x7FFFFFFFFFFFFFFF, UINT64_MAX});
+}
+
+TEST(PatchUtilsTest, EncodeDecodeVarInt64) {
+  TestEncodeDecodeVarInt<int64_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
+                                   1 << 22, 1LL << 55, 1LL << 56, -1, INT64_MIN,
+                                   INT64_MAX});
+}
+
+TEST(PatchUtilsTest, DecodeVarUInt32Malformed) {
+  // Dummy variable to ensure that on failure, the output variable is not
+  // written to.
+  uint32_t dummy = uint32_t(-1);
+
+  auto TestDecodeVarInt = [&dummy](const std::vector<uint8_t>& buffer) {
+    dummy = uint32_t(-1);
+    return DecodeVarUInt(buffer.begin(), buffer.end(), &dummy);
+  };
+
+  // Exhausted.
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt(std::vector<uint8_t>{}));
+  EXPECT_EQ(uint32_t(-1), dummy);
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt(std::vector<uint8_t>(4, 128)));
+  EXPECT_EQ(uint32_t(-1), dummy);
+
+  // Overflow.
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt(std::vector<uint8_t>(6, 128)));
+  EXPECT_EQ(uint32_t(-1), dummy);
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt({128, 128, 128, 128, 128, 42}));
+  EXPECT_EQ(uint32_t(-1), dummy);
+
+  // Following are pathological cases that are not handled for simplicity,
+  // hence decoding is expected to be successful.
+  EXPECT_NE(base::nullopt, TestDecodeVarInt({128, 128, 128, 128, 16}));
+  EXPECT_EQ(uint32_t(0), dummy);
+  EXPECT_NE(base::nullopt, TestDecodeVarInt({128, 128, 128, 128, 32}));
+  EXPECT_EQ(uint32_t(0), dummy);
+  EXPECT_NE(base::nullopt, TestDecodeVarInt({128, 128, 128, 128, 64}));
+  EXPECT_EQ(uint32_t(0), dummy);
+}
+
+TEST(PatchUtilsTest, DecodeVarUInt64Malformed) {
+  uint64_t dummy = uint64_t(-1);
+  auto TestDecodeVarInt = [&dummy](const std::vector<uint8_t>& buffer) {
+    return DecodeVarUInt(buffer.begin(), buffer.end(), &dummy);
+  };
+
+  // Exhausted.
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt(std::vector<uint8_t>{}));
+  EXPECT_EQ(uint64_t(-1), dummy);
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt(std::vector<uint8_t>(9, 128)));
+  EXPECT_EQ(uint64_t(-1), dummy);
+
+  // Overflow.
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt(std::vector<uint8_t>(10, 128)));
+  EXPECT_EQ(uint64_t(-1), dummy);
+  EXPECT_EQ(base::nullopt, TestDecodeVarInt({128, 128, 128, 128, 128, 128, 128,
+                                             128, 128, 128, 42}));
+  EXPECT_EQ(uint64_t(-1), dummy);
+}
+
+}  // namespace zucchini
diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc
index 1cd0c07..d0edd56c 100644
--- a/chrome/test/base/chrome_test_suite.cc
+++ b/chrome/test/base/chrome_test_suite.cc
@@ -24,11 +24,6 @@
 #include "media/base/media.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "chrome/browser/android/chrome_jni_registrar.h"
-#endif
-
 #if defined(OS_CHROMEOS)
 #include "base/process/process_metrics.h"
 #include "chromeos/chromeos_paths.h"
@@ -76,11 +71,6 @@
     PathService::Override(base::DIR_MODULE, browser_dir_);
   }
 
-#if defined(OS_ANDROID)
-  ASSERT_TRUE(
-      android::RegisterBrowserJNI(base::android::AttachCurrentThread()));
-#endif
-
   // Disable external libraries load if we are under python process in
   // ChromeOS.  That means we are autotest and, if ASAN is used,
   // external libraries load crashes.
diff --git a/chrome/test/data/osdd_new/empty_keyword.xml b/chrome/test/data/osdd_new/empty_keyword.xml
new file mode 100644
index 0000000..e7514ca
--- /dev/null
+++ b/chrome/test/data/osdd_new/empty_keyword.xml
@@ -0,0 +1,7 @@
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Example</ShortName>
+<Description>Example Search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Url type="text/html" method="get" template="https://www.example.com/search?q={searchTerms}"/>
+<Alias/>
+</SearchPlugin>
diff --git a/chrome/test/data/osdd_new/keyword.xml b/chrome/test/data/osdd_new/keyword.xml
new file mode 100644
index 0000000..202fe88
--- /dev/null
+++ b/chrome/test/data/osdd_new/keyword.xml
@@ -0,0 +1,7 @@
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Example</ShortName>
+<Description>Example Search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Url type="text/html" method="get" template="https://www.example.com/search?q={searchTerms}"/>
+<Alias>MoOsE</Alias>
+</SearchPlugin>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index cea4894..9661fd7 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -59,6 +59,7 @@
     "md_downloads/downloads_browsertest.js",
     "md_history/md_history_browsertest.js",
     "md_user_manager/user_manager_browsertest.js",
+    "media/media_engagement_browsertest.js",
     "media_router/media_router_elements_browsertest.js",
     "mock4js_browsertest.js",
     "net_internals/bandwidth_view.js",
diff --git a/chrome/test/data/webui/media/media_engagement_browsertest.js b/chrome/test/data/webui/media/media_engagement_browsertest.js
new file mode 100644
index 0000000..74c2527
--- /dev/null
+++ b/chrome/test/data/webui/media/media_engagement_browsertest.js
@@ -0,0 +1,60 @@
+// 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.
+
+/**
+ * @fileoverview Test suite for the Media Engagement WebUI.
+ */
+var ROOT_PATH = '../../../../../';
+var EXAMPLE_URL_1 = 'http://example.com/';
+var EXAMPLE_URL_2 = 'http://shmlexample.com/';
+
+GEN('#include "base/command_line.h"');
+GEN('#include "chrome/browser/media/media_engagement_service.h"');
+GEN('#include "chrome/browser/media/media_engagement_service_factory.h"');
+GEN('#include "chrome/browser/ui/browser.h"');
+
+function MediaEngagementWebUIBrowserTest() {}
+
+MediaEngagementWebUIBrowserTest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  browsePreload: 'chrome://media-engagement',
+
+  commandLineSwitches: [{
+    switchName: 'enable-features',
+    switchValue: 'media-engagement'
+  }],
+
+  runAccessibilityChecks: false,
+
+  isAsync: true,
+
+  testGenPreamble: function() {
+    GEN('MediaEngagementService* service =');
+    GEN('  MediaEngagementServiceFactory::GetForProfile(');
+    GEN('    browser()->profile());');
+    GEN('service->RecordVisit(GURL("' + EXAMPLE_URL_1 + '"));');
+    GEN('service->RecordVisit(GURL("' + EXAMPLE_URL_2 + '"));');
+  },
+
+  extraLibraries: [
+    ROOT_PATH + 'third_party/mocha/mocha.js',
+    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
+  ],
+};
+
+TEST_F('MediaEngagementWebUIBrowserTest', 'All', function() {
+  suiteSetup(function() {
+    return whenPageIsPopulatedForTest();
+  });
+
+  test('check engagement values are loaded', function() {
+    var originCells =
+        Array.from(document.getElementsByClassName('origin-cell'));
+    assertDeepEquals(
+        [EXAMPLE_URL_1, EXAMPLE_URL_2], originCells.map(x => x.textContent));
+  });
+
+  mocha.run();
+});
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index fc417061..924c7120 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -7,8 +7,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <tuple>
-
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
@@ -429,10 +427,21 @@
     const cryptohome::Identification& cryptohome_id,
     const std::string& key_name,
     const BoolDBusMethodCallback& callback) {
+  if (!service_is_available_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_FAILURE, false));
+    return;
+  }
+
   bool result = false;
-  if (key_type == attestation::KEY_USER) {
-    result = base::ContainsKey(user_certificate_map_,
-                               std::make_pair(cryptohome_id, key_name));
+  switch (key_type) {
+    case attestation::KEY_DEVICE:
+      result = base::ContainsKey(device_certificate_map_, key_name);
+      break;
+    case attestation::KEY_USER:
+      result = base::ContainsKey(user_certificate_map_,
+                                 std::make_pair(cryptohome_id, key_name));
+      break;
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -446,11 +455,22 @@
     const DataMethodCallback& callback) {
   bool result = false;
   std::string certificate;
-  if (key_type == attestation::KEY_USER) {
-    const auto it = user_certificate_map_.find({cryptohome_id, key_name});
-    if (it != user_certificate_map_.end()) {
-      result = true;
-      certificate = it->second;
+  switch (key_type) {
+    case attestation::KEY_DEVICE: {
+      const auto it = device_certificate_map_.find(key_name);
+      if (it != device_certificate_map_.end()) {
+        result = true;
+        certificate = it->second;
+      }
+      break;
+    }
+    case attestation::KEY_USER: {
+      const auto it = user_certificate_map_.find({cryptohome_id, key_name});
+      if (it != user_certificate_map_.end()) {
+        result = true;
+        certificate = it->second;
+      }
+      break;
     }
   }
 
@@ -506,9 +526,19 @@
     const cryptohome::Identification& cryptohome_id,
     const std::string& key_name,
     const DataMethodCallback& callback) {
+  bool result = false;
+  std::string payload;
+  if (key_type == attestation::KEY_DEVICE) {
+    const auto it = device_key_payload_map_.find(key_name);
+    if (it != device_key_payload_map_.end()) {
+      result = true;
+      payload = it->second;
+    }
+  }
+
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false, std::string()));
+      base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, result, payload));
 }
 
 void FakeCryptohomeClient::TpmAttestationSetKeyPayload(
@@ -517,8 +547,15 @@
     const std::string& key_name,
     const std::string& payload,
     const BoolDBusMethodCallback& callback) {
+  bool result = false;
+  // Currently only KEY_DEVICE case is supported just because there's no user
+  // for KEY_USER.
+  if (key_type == attestation::KEY_DEVICE) {
+    device_key_payload_map_[key_name] = payload;
+    result = true;
+  }
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false));
+      FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, result));
 }
 
 void FakeCryptohomeClient::TpmAttestationDeleteKeys(
@@ -671,9 +708,27 @@
     const cryptohome::Identification& cryptohome_id,
     const std::string& key_name,
     const std::string& certificate) {
-  user_certificate_map_.emplace(std::piecewise_construct,
-                                std::forward_as_tuple(cryptohome_id, key_name),
-                                std::forward_as_tuple(certificate));
+  user_certificate_map_[std::make_pair(cryptohome_id, key_name)] = certificate;
+}
+
+void FakeCryptohomeClient::SetTpmAttestationDeviceCertificate(
+    const std::string& key_name,
+    const std::string& certificate) {
+  device_certificate_map_[key_name] = certificate;
+}
+
+void FakeCryptohomeClient::SetTpmAttestationDeviceKeyPayload(
+    const std::string& key_name,
+    const std::string& payload) {
+  device_key_payload_map_[key_name] = payload;
+}
+
+base::Optional<std::string>
+FakeCryptohomeClient::GetTpmAttestationDeviceKeyPayload(
+    const std::string& key_name) const {
+  const auto it = device_key_payload_map_.find(key_name);
+  return it == device_key_payload_map_.end() ? base::nullopt
+                                             : base::make_optional(it->second);
 }
 
 // static
diff --git a/chromeos/dbus/fake_cryptohome_client.h b/chromeos/dbus/fake_cryptohome_client.h
index 673fe579..40ee9f1 100644
--- a/chromeos/dbus/fake_cryptohome_client.h
+++ b/chromeos/dbus/fake_cryptohome_client.h
@@ -14,6 +14,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/timer/timer.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome/key.pb.h"
@@ -250,6 +251,15 @@
       const std::string& key_name,
       const std::string& certificate);
 
+  void SetTpmAttestationDeviceCertificate(const std::string& key_name,
+                                          const std::string& certificate);
+
+  base::Optional<std::string> GetTpmAttestationDeviceKeyPayload(
+      const std::string& key_name) const;
+
+  void SetTpmAttestationDeviceKeyPayload(const std::string& key_name,
+                                         const std::string& payload);
+
  private:
   void ReturnProtobufMethodCallback(
       const cryptohome::BaseReply& reply,
@@ -294,6 +304,12 @@
   std::map<std::pair<cryptohome::Identification, std::string>, std::string>
       user_certificate_map_;
 
+  // Device attestation certificate mapped by key_name.
+  std::map<std::string, std::string> device_certificate_map_;
+
+  // Device key payload data mapped by key_name.
+  std::map<std::string, std::string> device_key_payload_map_;
+
   DircryptoMigrationProgessHandler dircrypto_migration_progress_handler_;
   base::RepeatingTimer dircrypto_migration_progress_timer_;
   uint64_t dircrypto_migration_progress_;
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index fc54ee38c..aa11f057 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -24,6 +24,8 @@
     "breaking_news/subscription_json_request.h",
     "breaking_news/subscription_manager.cc",
     "breaking_news/subscription_manager.h",
+    "breaking_news/subscription_manager_impl.cc",
+    "breaking_news/subscription_manager_impl.h",
     "callbacks.h",
     "category.cc",
     "category.h",
@@ -162,7 +164,7 @@
     "bookmarks/bookmark_suggestions_provider_unittest.cc",
     "breaking_news/breaking_news_suggestions_provider_unittest.cc",
     "breaking_news/subscription_json_request_unittest.cc",
-    "breaking_news/subscription_manager_unittest.cc",
+    "breaking_news/subscription_manager_impl_unittest.cc",
     "category_rankers/click_based_category_ranker_unittest.cc",
     "category_rankers/constant_category_ranker_unittest.cc",
     "category_unittest.cc",
diff --git a/components/ntp_snippets/breaking_news/subscription_manager.cc b/components/ntp_snippets/breaking_news/subscription_manager.cc
index 2a10fc45..1dbd535 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager.cc
@@ -4,23 +4,12 @@
 
 #include "components/ntp_snippets/breaking_news/subscription_manager.h"
 
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial_params.h"
-#include "base/strings/stringprintf.h"
-#include "components/ntp_snippets/breaking_news/subscription_json_request.h"
 #include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/access_token_fetcher.h"
-#include "components/signin/core/browser/signin_manager_base.h"
-#include "net/base/url_util.h"
 
 namespace ntp_snippets {
 
-using internal::SubscriptionJsonRequest;
-
 namespace {
 
 // Variation parameter for chrome-push-subscription backend.
@@ -29,245 +18,8 @@
 // Variation parameter for chrome-push-unsubscription backend.
 const char kPushUnsubscriptionBackendParam[] = "push_unsubscription_backend";
 
-const char kApiKeyParamName[] = "key";
-const char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
-
 }  // namespace
 
-class SubscriptionManager::SigninObserver : public SigninManagerBase::Observer {
- public:
-  SigninObserver(SigninManagerBase* signin_manager,
-                 const base::Closure& signin_status_changed_callback)
-      : signin_manager_(signin_manager),
-        signin_status_changed_callback_(signin_status_changed_callback) {
-    signin_manager_->AddObserver(this);
-  }
-
-  ~SigninObserver() override { signin_manager_->RemoveObserver(this); }
-
- private:
-  // SigninManagerBase::Observer implementation.
-  void GoogleSigninSucceeded(const std::string& account_id,
-                             const std::string& username) override {
-    signin_status_changed_callback_.Run();
-  }
-
-  void GoogleSignedOut(const std::string& account_id,
-                       const std::string& username) override {
-    signin_status_changed_callback_.Run();
-  }
-
-  SigninManagerBase* const signin_manager_;
-  base::Closure signin_status_changed_callback_;
-};
-
-SubscriptionManager::SubscriptionManager(
-    scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
-    PrefService* pref_service,
-    SigninManagerBase* signin_manager,
-    OAuth2TokenService* access_token_service,
-    const std::string& api_key,
-    const GURL& subscribe_url,
-    const GURL& unsubscribe_url)
-    : url_request_context_getter_(std::move(url_request_context_getter)),
-      pref_service_(pref_service),
-      signin_manager_(signin_manager),
-      signin_observer_(base::MakeUnique<SigninObserver>(
-          signin_manager,
-          base::Bind(&SubscriptionManager::SigninStatusChanged,
-                     base::Unretained(this)))),
-      access_token_service_(access_token_service),
-      api_key_(api_key),
-      subscribe_url_(subscribe_url),
-      unsubscribe_url_(unsubscribe_url) {}
-
-SubscriptionManager::~SubscriptionManager() = default;
-
-void SubscriptionManager::Subscribe(const std::string& subscription_token) {
-  // If there is a request in flight, cancel it.
-  if (request_) {
-    request_ = nullptr;
-  }
-  if (signin_manager_->IsAuthenticated()) {
-    StartAccessTokenRequest(subscription_token);
-  } else {
-    SubscribeInternal(subscription_token, /*access_token=*/std::string());
-  }
-}
-
-void SubscriptionManager::SubscribeInternal(
-    const std::string& subscription_token,
-    const std::string& access_token) {
-  SubscriptionJsonRequest::Builder builder;
-  builder.SetToken(subscription_token)
-      .SetUrlRequestContextGetter(url_request_context_getter_);
-
-  if (!access_token.empty()) {
-    builder.SetUrl(subscribe_url_);
-    builder.SetAuthenticationHeader(base::StringPrintf(
-        kAuthorizationRequestHeaderFormat, access_token.c_str()));
-  } else {
-    // When not providing OAuth token, we need to pass the Google API key.
-    builder.SetUrl(
-        net::AppendQueryParameter(subscribe_url_, kApiKeyParamName, api_key_));
-  }
-
-  request_ = builder.Build();
-  request_->Start(base::BindOnce(&SubscriptionManager::DidSubscribe,
-                                 base::Unretained(this), subscription_token,
-                                 /*is_authenticated=*/!access_token.empty()));
-}
-
-void SubscriptionManager::StartAccessTokenRequest(
-    const std::string& subscription_token) {
-  // If there is already an ongoing token request, destroy it.
-  if (access_token_fetcher_) {
-    access_token_fetcher_ = nullptr;
-  }
-
-  OAuth2TokenService::ScopeSet scopes = {kContentSuggestionsApiScope};
-  access_token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
-      "ntp_snippets", signin_manager_, access_token_service_, scopes,
-      base::BindOnce(&SubscriptionManager::AccessTokenFetchFinished,
-                     base::Unretained(this), subscription_token));
-}
-
-void SubscriptionManager::AccessTokenFetchFinished(
-    const std::string& subscription_token,
-    const GoogleServiceAuthError& error,
-    const std::string& access_token) {
-  // Delete the fetcher only after we leave this method (which is called from
-  // the fetcher itself).
-  std::unique_ptr<AccessTokenFetcher> access_token_fetcher_deleter(
-      std::move(access_token_fetcher_));
-
-  if (error.state() != GoogleServiceAuthError::NONE) {
-    // In case of error, we will retry on next Chrome restart.
-    return;
-  }
-  DCHECK(!access_token.empty());
-  SubscribeInternal(subscription_token, access_token);
-}
-
-void SubscriptionManager::DidSubscribe(const std::string& subscription_token,
-                                       bool is_authenticated,
-                                       const Status& status) {
-  // Delete the request only after we leave this method (which is called from
-  // the request itself).
-  std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter(
-      std::move(request_));
-
-  switch (status.code) {
-    case StatusCode::SUCCESS:
-      // In case of successful subscription, store the same data used for
-      // subscription in order to be able to resubscribe in case of data
-      // change.
-      // TODO(mamir): Store region and language.
-      pref_service_->SetString(prefs::kBreakingNewsSubscriptionDataToken,
-                               subscription_token);
-      pref_service_->SetBoolean(
-          prefs::kBreakingNewsSubscriptionDataIsAuthenticated,
-          is_authenticated);
-      break;
-    default:
-      // TODO(mamir): Handle failure.
-      break;
-  }
-}
-
-void SubscriptionManager::Unsubscribe() {
-  std::string token =
-      pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
-  ResubscribeInternal(/*old_token=*/token, /*new_token=*/std::string());
-}
-
-void SubscriptionManager::ResubscribeInternal(const std::string& old_token,
-                                              const std::string& new_token) {
-  // If there is an request in flight, cancel it.
-  if (request_) {
-    request_ = nullptr;
-  }
-
-  SubscriptionJsonRequest::Builder builder;
-  builder.SetToken(old_token).SetUrlRequestContextGetter(
-      url_request_context_getter_);
-  builder.SetUrl(
-      net::AppendQueryParameter(unsubscribe_url_, kApiKeyParamName, api_key_));
-
-  request_ = builder.Build();
-  request_->Start(base::BindOnce(&SubscriptionManager::DidUnsubscribe,
-                                 base::Unretained(this), new_token));
-}
-
-bool SubscriptionManager::IsSubscribed() {
-  std::string subscription_token =
-      pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
-  return !subscription_token.empty();
-}
-
-bool SubscriptionManager::NeedsToResubscribe() {
-  // Check if authentication state changed after subscription.
-  bool is_auth_subscribe = pref_service_->GetBoolean(
-      prefs::kBreakingNewsSubscriptionDataIsAuthenticated);
-  bool is_authenticated = signin_manager_->IsAuthenticated();
-  return is_auth_subscribe != is_authenticated;
-}
-
-void SubscriptionManager::Resubscribe(const std::string& new_token) {
-  std::string old_token =
-      pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
-  if (old_token == new_token) {
-    // If the token didn't change, subscribe directly. The server handles the
-    // unsubscription if previous subscriptions exists.
-    Subscribe(old_token);
-  } else {
-    ResubscribeInternal(old_token, new_token);
-  }
-}
-
-void SubscriptionManager::DidUnsubscribe(const std::string& new_token,
-                                         const Status& status) {
-  // Delete the request only after we leave this method (which is called from
-  // the request itself).
-  std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter(
-      std::move(request_));
-
-  switch (status.code) {
-    case StatusCode::SUCCESS:
-      // In case of successful unsubscription, clear the previously stored data.
-      // TODO(mamir): Clear stored region and language.
-      pref_service_->ClearPref(prefs::kBreakingNewsSubscriptionDataToken);
-      pref_service_->ClearPref(
-          prefs::kBreakingNewsSubscriptionDataIsAuthenticated);
-      if (!new_token.empty()) {
-        Subscribe(new_token);
-      }
-      break;
-    default:
-      // TODO(mamir): Handle failure.
-      break;
-  }
-}
-
-void SubscriptionManager::SigninStatusChanged() {
-  // If subscribed already, resubscribe.
-  if (IsSubscribed()) {
-    if (request_) {
-      request_ = nullptr;
-    }
-    std::string token =
-        pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
-    Subscribe(token);
-  }
-}
-
-void SubscriptionManager::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(prefs::kBreakingNewsSubscriptionDataToken,
-                               std::string());
-  registry->RegisterBooleanPref(
-      prefs::kBreakingNewsSubscriptionDataIsAuthenticated, false);
-}
-
 GURL GetPushUpdatesSubscriptionEndpoint(version_info::Channel channel) {
   std::string endpoint = base::GetFieldTrialParamValueByFeature(
       kBreakingNewsPushFeature, kPushSubscriptionBackendParam);
@@ -309,4 +61,5 @@
   NOTREACHED();
   return GURL{kPushUpdatesUnsubscriptionStagingServer};
 }
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/subscription_manager.h b/components/ntp_snippets/breaking_news/subscription_manager.h
index f04bb14..fc2343e 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager.h
+++ b/components/ntp_snippets/breaking_news/subscription_manager.h
@@ -5,17 +5,10 @@
 #ifndef COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_H_
 #define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_H_
 
-#include "components/ntp_snippets/breaking_news/subscription_json_request.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/signin/core/browser/signin_manager_base.h"
-#include "components/version_info/version_info.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "url/gurl.h"
+#include <string>
 
-class AccessTokenFetcher;
-class OAuth2TokenService;
-class PrefRegistrySimple;
-class PrefService;
+#include "components/version_info/version_info.h"
+#include "url/gurl.h"
 
 namespace ntp_snippets {
 
@@ -27,82 +20,23 @@
 // consideration of the channel and field trial parameters.
 GURL GetPushUpdatesUnsubscriptionEndpoint(version_info::Channel channel);
 
-// Class that wraps around the functionality of SubscriptionJsonRequest. It uses
-// the SubscriptionJsonRequest to send subscription and unsubscription requests
-// to the content suggestions server and does the bookkeeping for the data used
-// for subscription. Bookkeeping is required to detect any change (e.g. the
-// token render invalid), and resubscribe accordingly.
+// Handles subscription to content suggestions server for push updates (e.g. via
+// GCM).
 class SubscriptionManager {
  public:
-  SubscriptionManager(
-      scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
-      PrefService* pref_service,
-      SigninManagerBase* signin_manager,
-      OAuth2TokenService* access_token_service,
-      const std::string& api_key,
-      const GURL& subscribe_url,
-      const GURL& unsubscribe_url);
+  virtual ~SubscriptionManager() = default;
 
-  ~SubscriptionManager();
+  virtual void Subscribe(const std::string& token) = 0;
+  virtual void Unsubscribe() = 0;
+  virtual bool IsSubscribed() = 0;
 
-  void Subscribe(const std::string& token);
-  void Unsubscribe();
-  bool IsSubscribed();
-
-  void Resubscribe(const std::string& new_token);
+  virtual void Resubscribe(const std::string& new_token) = 0;
 
   // Checks if some data that has been used when subscribing has changed. For
   // example, the user has signed in.
-  bool NeedsToResubscribe();
-
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- private:
-  class SigninObserver;
-
-  void SigninStatusChanged();
-
-  void DidSubscribe(const std::string& subscription_token,
-                    bool is_authenticated,
-                    const Status& status);
-  void DidUnsubscribe(const std::string& new_token, const Status& status);
-  void SubscribeInternal(const std::string& subscription_token,
-                         const std::string& access_token);
-
-  // If |new_token| is empty, this will just unsubscribe. If |new_token| is
-  // non-empty, a subscription request with the |new_token| will be started upon
-  // successful unsubscription.
-  void ResubscribeInternal(const std::string& old_token,
-                           const std::string& new_token);
-
-  // |subscription_token| is the token when subscribing after obtaining the
-  // access token.
-  void StartAccessTokenRequest(const std::string& subscription_token);
-  void AccessTokenFetchFinished(const std::string& subscription_token,
-                                const GoogleServiceAuthError& error,
-                                const std::string& access_token);
-
-  // Holds the URL request context.
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
-
-  std::unique_ptr<internal::SubscriptionJsonRequest> request_;
-  std::unique_ptr<AccessTokenFetcher> access_token_fetcher_;
-
-  PrefService* pref_service_;
-
-  // Authentication for signed-in users.
-  SigninManagerBase* signin_manager_;
-  std::unique_ptr<SigninObserver> signin_observer_;
-  OAuth2TokenService* access_token_service_;
-
-  // API key to use for non-authenticated requests.
-  const std::string api_key_;
-
-  // API endpoint for subscribing and unsubscribing.
-  const GURL subscribe_url_;
-  const GURL unsubscribe_url_;
-
-  DISALLOW_COPY_AND_ASSIGN(SubscriptionManager);
+  virtual bool NeedsToResubscribe() = 0;
 };
-}
+
+}  // namespace ntp_snippets
+
 #endif  // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_H_
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
new file mode 100644
index 0000000..22fd71a
--- /dev/null
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
@@ -0,0 +1,270 @@
+// 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/ntp_snippets/breaking_news/subscription_manager_impl.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/stringprintf.h"
+#include "components/ntp_snippets/breaking_news/subscription_json_request.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/access_token_fetcher.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "net/base/url_util.h"
+
+namespace ntp_snippets {
+
+using internal::SubscriptionJsonRequest;
+
+namespace {
+
+const char kApiKeyParamName[] = "key";
+const char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
+
+}  // namespace
+
+class SubscriptionManagerImpl::SigninObserver
+    : public SigninManagerBase::Observer {
+ public:
+  SigninObserver(SigninManagerBase* signin_manager,
+                 const base::Closure& signin_status_changed_callback)
+      : signin_manager_(signin_manager),
+        signin_status_changed_callback_(signin_status_changed_callback) {
+    signin_manager_->AddObserver(this);
+  }
+
+  ~SigninObserver() override { signin_manager_->RemoveObserver(this); }
+
+ private:
+  // SigninManagerBase::Observer implementation.
+  void GoogleSigninSucceeded(const std::string& account_id,
+                             const std::string& username) override {
+    signin_status_changed_callback_.Run();
+  }
+
+  void GoogleSignedOut(const std::string& account_id,
+                       const std::string& username) override {
+    signin_status_changed_callback_.Run();
+  }
+
+  SigninManagerBase* const signin_manager_;
+  base::Closure signin_status_changed_callback_;
+};
+
+SubscriptionManagerImpl::SubscriptionManagerImpl(
+    scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
+    PrefService* pref_service,
+    SigninManagerBase* signin_manager,
+    OAuth2TokenService* access_token_service,
+    const std::string& api_key,
+    const GURL& subscribe_url,
+    const GURL& unsubscribe_url)
+    : url_request_context_getter_(std::move(url_request_context_getter)),
+      pref_service_(pref_service),
+      signin_manager_(signin_manager),
+      signin_observer_(base::MakeUnique<SigninObserver>(
+          signin_manager,
+          base::Bind(&SubscriptionManagerImpl::SigninStatusChanged,
+                     base::Unretained(this)))),
+      access_token_service_(access_token_service),
+      api_key_(api_key),
+      subscribe_url_(subscribe_url),
+      unsubscribe_url_(unsubscribe_url) {}
+
+SubscriptionManagerImpl::~SubscriptionManagerImpl() = default;
+
+void SubscriptionManagerImpl::Subscribe(const std::string& subscription_token) {
+  // If there is a request in flight, cancel it.
+  if (request_) {
+    request_ = nullptr;
+  }
+  if (signin_manager_->IsAuthenticated()) {
+    StartAccessTokenRequest(subscription_token);
+  } else {
+    SubscribeInternal(subscription_token, /*access_token=*/std::string());
+  }
+}
+
+void SubscriptionManagerImpl::SubscribeInternal(
+    const std::string& subscription_token,
+    const std::string& access_token) {
+  SubscriptionJsonRequest::Builder builder;
+  builder.SetToken(subscription_token)
+      .SetUrlRequestContextGetter(url_request_context_getter_);
+
+  if (!access_token.empty()) {
+    builder.SetUrl(subscribe_url_);
+    builder.SetAuthenticationHeader(base::StringPrintf(
+        kAuthorizationRequestHeaderFormat, access_token.c_str()));
+  } else {
+    // When not providing OAuth token, we need to pass the Google API key.
+    builder.SetUrl(
+        net::AppendQueryParameter(subscribe_url_, kApiKeyParamName, api_key_));
+  }
+
+  request_ = builder.Build();
+  request_->Start(base::BindOnce(&SubscriptionManagerImpl::DidSubscribe,
+                                 base::Unretained(this), subscription_token,
+                                 /*is_authenticated=*/!access_token.empty()));
+}
+
+void SubscriptionManagerImpl::StartAccessTokenRequest(
+    const std::string& subscription_token) {
+  // If there is already an ongoing token request, destroy it.
+  if (access_token_fetcher_) {
+    access_token_fetcher_ = nullptr;
+  }
+
+  OAuth2TokenService::ScopeSet scopes = {kContentSuggestionsApiScope};
+  access_token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
+      "ntp_snippets", signin_manager_, access_token_service_, scopes,
+      base::BindOnce(&SubscriptionManagerImpl::AccessTokenFetchFinished,
+                     base::Unretained(this), subscription_token));
+}
+
+void SubscriptionManagerImpl::AccessTokenFetchFinished(
+    const std::string& subscription_token,
+    const GoogleServiceAuthError& error,
+    const std::string& access_token) {
+  // Delete the fetcher only after we leave this method (which is called from
+  // the fetcher itself).
+  std::unique_ptr<AccessTokenFetcher> access_token_fetcher_deleter(
+      std::move(access_token_fetcher_));
+
+  if (error.state() != GoogleServiceAuthError::NONE) {
+    // In case of error, we will retry on next Chrome restart.
+    return;
+  }
+  DCHECK(!access_token.empty());
+  SubscribeInternal(subscription_token, access_token);
+}
+
+void SubscriptionManagerImpl::DidSubscribe(
+    const std::string& subscription_token,
+    bool is_authenticated,
+    const Status& status) {
+  // Delete the request only after we leave this method (which is called from
+  // the request itself).
+  std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter(
+      std::move(request_));
+
+  switch (status.code) {
+    case StatusCode::SUCCESS:
+      // In case of successful subscription, store the same data used for
+      // subscription in order to be able to resubscribe in case of data
+      // change.
+      // TODO(mamir): Store region and language.
+      pref_service_->SetString(prefs::kBreakingNewsSubscriptionDataToken,
+                               subscription_token);
+      pref_service_->SetBoolean(
+          prefs::kBreakingNewsSubscriptionDataIsAuthenticated,
+          is_authenticated);
+      break;
+    default:
+      // TODO(mamir): Handle failure.
+      break;
+  }
+}
+
+void SubscriptionManagerImpl::Unsubscribe() {
+  std::string token =
+      pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
+  ResubscribeInternal(/*old_token=*/token, /*new_token=*/std::string());
+}
+
+void SubscriptionManagerImpl::ResubscribeInternal(
+    const std::string& old_token,
+    const std::string& new_token) {
+  // If there is an request in flight, cancel it.
+  if (request_) {
+    request_ = nullptr;
+  }
+
+  SubscriptionJsonRequest::Builder builder;
+  builder.SetToken(old_token).SetUrlRequestContextGetter(
+      url_request_context_getter_);
+  builder.SetUrl(
+      net::AppendQueryParameter(unsubscribe_url_, kApiKeyParamName, api_key_));
+
+  request_ = builder.Build();
+  request_->Start(base::BindOnce(&SubscriptionManagerImpl::DidUnsubscribe,
+                                 base::Unretained(this), new_token));
+}
+
+bool SubscriptionManagerImpl::IsSubscribed() {
+  std::string subscription_token =
+      pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
+  return !subscription_token.empty();
+}
+
+bool SubscriptionManagerImpl::NeedsToResubscribe() {
+  // Check if authentication state changed after subscription.
+  bool is_auth_subscribe = pref_service_->GetBoolean(
+      prefs::kBreakingNewsSubscriptionDataIsAuthenticated);
+  bool is_authenticated = signin_manager_->IsAuthenticated();
+  return is_auth_subscribe != is_authenticated;
+}
+
+void SubscriptionManagerImpl::Resubscribe(const std::string& new_token) {
+  std::string old_token =
+      pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
+  if (old_token == new_token) {
+    // If the token didn't change, subscribe directly. The server handles the
+    // unsubscription if previous subscriptions exists.
+    Subscribe(old_token);
+  } else {
+    ResubscribeInternal(old_token, new_token);
+  }
+}
+
+void SubscriptionManagerImpl::DidUnsubscribe(const std::string& new_token,
+                                             const Status& status) {
+  // Delete the request only after we leave this method (which is called from
+  // the request itself).
+  std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter(
+      std::move(request_));
+
+  switch (status.code) {
+    case StatusCode::SUCCESS:
+      // In case of successful unsubscription, clear the previously stored data.
+      // TODO(mamir): Clear stored region and language.
+      pref_service_->ClearPref(prefs::kBreakingNewsSubscriptionDataToken);
+      pref_service_->ClearPref(
+          prefs::kBreakingNewsSubscriptionDataIsAuthenticated);
+      if (!new_token.empty()) {
+        Subscribe(new_token);
+      }
+      break;
+    default:
+      // TODO(mamir): Handle failure.
+      break;
+  }
+}
+
+void SubscriptionManagerImpl::SigninStatusChanged() {
+  // If subscribed already, resubscribe.
+  if (IsSubscribed()) {
+    if (request_) {
+      request_ = nullptr;
+    }
+    std::string token =
+        pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken);
+    Subscribe(token);
+  }
+}
+
+void SubscriptionManagerImpl::RegisterProfilePrefs(
+    PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(prefs::kBreakingNewsSubscriptionDataToken,
+                               std::string());
+  registry->RegisterBooleanPref(
+      prefs::kBreakingNewsSubscriptionDataIsAuthenticated, false);
+}
+
+}  // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.h b/components/ntp_snippets/breaking_news/subscription_manager_impl.h
new file mode 100644
index 0000000..b1fd05bd
--- /dev/null
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl.h
@@ -0,0 +1,105 @@
+// 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_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_IMPL_H_
+#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "components/ntp_snippets/breaking_news/subscription_json_request.h"
+#include "components/ntp_snippets/breaking_news/subscription_manager.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
+
+class AccessTokenFetcher;
+class OAuth2TokenService;
+class PrefRegistrySimple;
+class PrefService;
+
+namespace ntp_snippets {
+
+// Class that wraps around the functionality of SubscriptionJsonRequest. It uses
+// the SubscriptionJsonRequest to send subscription and unsubscription requests
+// to the content suggestions server and does the bookkeeping for the data used
+// for subscription. Bookkeeping is required to detect any change (e.g. the
+// token render invalid), and resubscribe accordingly.
+class SubscriptionManagerImpl : public SubscriptionManager {
+ public:
+  SubscriptionManagerImpl(
+      scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
+      PrefService* pref_service,
+      SigninManagerBase* signin_manager,
+      OAuth2TokenService* access_token_service,
+      const std::string& api_key,
+      const GURL& subscribe_url,
+      const GURL& unsubscribe_url);
+
+  ~SubscriptionManagerImpl() override;
+
+  // SubscriptionManager implementation.
+  void Subscribe(const std::string& token) override;
+  void Unsubscribe() override;
+  bool IsSubscribed() override;
+
+  void Resubscribe(const std::string& new_token) override;
+
+  // Checks if some data that has been used when subscribing has changed. For
+  // example, the user has signed in.
+  bool NeedsToResubscribe() override;
+
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ private:
+  class SigninObserver;
+
+  void SigninStatusChanged();
+
+  void DidSubscribe(const std::string& subscription_token,
+                    bool is_authenticated,
+                    const Status& status);
+  void DidUnsubscribe(const std::string& new_token, const Status& status);
+  void SubscribeInternal(const std::string& subscription_token,
+                         const std::string& access_token);
+
+  // If |new_token| is empty, this will just unsubscribe. If |new_token| is
+  // non-empty, a subscription request with the |new_token| will be started upon
+  // successful unsubscription.
+  void ResubscribeInternal(const std::string& old_token,
+                           const std::string& new_token);
+
+  // |subscription_token| is the token when subscribing after obtaining the
+  // access token.
+  void StartAccessTokenRequest(const std::string& subscription_token);
+  void AccessTokenFetchFinished(const std::string& subscription_token,
+                                const GoogleServiceAuthError& error,
+                                const std::string& access_token);
+
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+
+  std::unique_ptr<internal::SubscriptionJsonRequest> request_;
+  std::unique_ptr<AccessTokenFetcher> access_token_fetcher_;
+
+  PrefService* pref_service_;
+
+  // Authentication for signed-in users.
+  SigninManagerBase* signin_manager_;
+  std::unique_ptr<SigninObserver> signin_observer_;
+  OAuth2TokenService* access_token_service_;
+
+  // API key to use for non-authenticated requests.
+  const std::string api_key_;
+
+  // API endpoint for subscribing and unsubscribing.
+  const GURL subscribe_url_;
+  const GURL unsubscribe_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(SubscriptionManagerImpl);
+};
+
+}  // namespace ntp_snippets
+
+#endif  // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_IMPL_H_
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_unittest.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
similarity index 79%
rename from components/ntp_snippets/breaking_news/subscription_manager_unittest.cc
rename to components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
index 468988f..2c8cebdb 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_unittest.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/ntp_snippets/breaking_news/subscription_manager.h"
+#include "components/ntp_snippets/breaking_news/subscription_manager_impl.h"
 
 #include "base/message_loop/message_loop.h"
 #include "build/build_config.h"
@@ -31,15 +31,15 @@
 const char kUnsubscriptionUrlSignedOut[] =
     "http://valid-url.test/unsubscribe?key=fakeAPIkey";
 
-class SubscriptionManagerTest : public testing::Test {
+class SubscriptionManagerImplTest : public testing::Test {
  public:
-  SubscriptionManagerTest()
+  SubscriptionManagerImplTest()
       : request_context_getter_(
             new net::TestURLRequestContextGetter(message_loop_.task_runner())) {
   }
 
   void SetUp() override {
-    SubscriptionManager::RegisterProfilePrefs(
+    SubscriptionManagerImpl::RegisterProfilePrefs(
         utils_.pref_service()->registry());
   }
 
@@ -141,19 +141,18 @@
     url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
   }
 
-
   base::MessageLoop message_loop_;
   test::RemoteSuggestionsTestUtils utils_;
   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
   net::TestURLFetcherFactory url_fetcher_factory_;
 };
 
-TEST_F(SubscriptionManagerTest, SubscribeSuccessfully) {
+TEST_F(SubscriptionManagerImplTest, SubscribeSuccessfully) {
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), GetOAuth2TokenService(),
-                              kAPIKey, GURL(kSubscriptionUrl),
-                              GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), GetOAuth2TokenService(),
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(subscription_token);
   RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
   ASSERT_TRUE(manager.IsSubscribed());
@@ -166,7 +165,7 @@
 // This test is relevant only on non-ChromeOS platforms, as the flow being
 // tested here is not possible on ChromeOS.
 #if !defined(OS_CHROMEOS)
-TEST_F(SubscriptionManagerTest,
+TEST_F(SubscriptionManagerImplTest,
        ShouldSubscribeWithAuthenticationWhenAuthenticated) {
   // Sign in.
   FakeProfileOAuth2TokenService* auth_token_service = GetOAuth2TokenService();
@@ -175,9 +174,10 @@
 
   // Create manager and subscribe.
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), auth_token_service, kAPIKey,
-                              GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), auth_token_service,
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(subscription_token);
 
   // Make sure that subscription is pending an access token.
@@ -198,24 +198,24 @@
 }
 #endif
 
-TEST_F(SubscriptionManagerTest, ShouldNotSubscribeIfError) {
+TEST_F(SubscriptionManagerImplTest, ShouldNotSubscribeIfError) {
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), GetOAuth2TokenService(),
-                              kAPIKey, GURL(kSubscriptionUrl),
-                              GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), GetOAuth2TokenService(),
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
 
   manager.Subscribe(subscription_token);
   RespondToSubscriptionWithError(/*is_signed_in=*/false, net::ERR_TIMED_OUT);
   EXPECT_FALSE(manager.IsSubscribed());
 }
 
-TEST_F(SubscriptionManagerTest, UnsubscribeSuccessfully) {
+TEST_F(SubscriptionManagerImplTest, UnsubscribeSuccessfully) {
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), GetOAuth2TokenService(),
-                              kAPIKey, GURL(kSubscriptionUrl),
-                              GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), GetOAuth2TokenService(),
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(subscription_token);
   RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
   ASSERT_TRUE(manager.IsSubscribed());
@@ -226,13 +226,13 @@
       GetPrefService()->HasPrefPath(prefs::kBreakingNewsSubscriptionDataToken));
 }
 
-TEST_F(SubscriptionManagerTest,
+TEST_F(SubscriptionManagerImplTest,
        ShouldRemainSubscribedIfErrorDuringUnsubscribe) {
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), GetOAuth2TokenService(),
-                              kAPIKey, GURL(kSubscriptionUrl),
-                              GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), GetOAuth2TokenService(),
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(subscription_token);
   RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
   ASSERT_TRUE(manager.IsSubscribed());
@@ -246,13 +246,15 @@
 // This test is relevant only on non-ChromeOS platforms, as the flow being
 // tested here is not possible on ChromeOS.
 #if !defined(OS_CHROMEOS)
-TEST_F(SubscriptionManagerTest, ShouldResubscribeIfSignInAfterSubscription) {
+TEST_F(SubscriptionManagerImplTest,
+       ShouldResubscribeIfSignInAfterSubscription) {
   // Create manager and subscribe.
   FakeProfileOAuth2TokenService* auth_token_service = GetOAuth2TokenService();
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), auth_token_service, kAPIKey,
-                              GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), auth_token_service,
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(subscription_token);
   RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
   ASSERT_FALSE(manager.NeedsToResubscribe());
@@ -274,15 +276,17 @@
 // This test is relevant only on non-ChromeOS platforms, as the flow being
 // tested here is not possible on ChromeOS.
 #if !defined(OS_CHROMEOS)
-TEST_F(SubscriptionManagerTest, ShouldResubscribeIfSignOutAfterSubscription) {
+TEST_F(SubscriptionManagerImplTest,
+       ShouldResubscribeIfSignOutAfterSubscription) {
   // Signin and subscribe.
   FakeProfileOAuth2TokenService* auth_token_service = GetOAuth2TokenService();
   SignIn();
   IssueRefreshToken(auth_token_service);
   std::string subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), auth_token_service, kAPIKey,
-                              GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), auth_token_service,
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(subscription_token);
   ASSERT_EQ(1u, auth_token_service->GetPendingRequests().size());
   IssueAccessToken(auth_token_service);
@@ -299,14 +303,14 @@
 }
 #endif
 
-TEST_F(SubscriptionManagerTest,
+TEST_F(SubscriptionManagerImplTest,
        ShouldUpdateTokenInPrefWhenResubscribeWithChangeInToken) {
   // Create manager and subscribe.
   std::string old_subscription_token = "1234567890";
-  SubscriptionManager manager(GetRequestContext(), GetPrefService(),
-                              GetSigninManager(), GetOAuth2TokenService(),
-                              kAPIKey, GURL(kSubscriptionUrl),
-                              GURL(kUnsubscriptionUrl));
+  SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
+                                  GetSigninManager(), GetOAuth2TokenService(),
+                                  kAPIKey, GURL(kSubscriptionUrl),
+                                  GURL(kUnsubscriptionUrl));
   manager.Subscribe(old_subscription_token);
   RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
   EXPECT_EQ(
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
index d9567ba..42a236b 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
@@ -63,7 +63,7 @@
   if (IsValidWebCredential(observed_form)) {
     FacetURI facet_uri(
         FacetURI::FromPotentiallyInvalidSpec(observed_form.signon_realm));
-    affiliation_service_->GetAffiliations(
+    affiliation_service_->GetAffiliationsAndBranding(
         facet_uri, AffiliationService::StrategyOnCacheMiss::FAIL,
         base::Bind(&AffiliatedMatchHelper::CompleteGetAffiliatedAndroidRealms,
                    weak_ptr_factory_.GetWeakPtr(), facet_uri, result_callback));
@@ -76,7 +76,7 @@
     const PasswordStore::FormDigest& android_form,
     const AffiliatedRealmsCallback& result_callback) {
   if (IsValidAndroidCredential(android_form)) {
-    affiliation_service_->GetAffiliations(
+    affiliation_service_->GetAffiliationsAndBranding(
         FacetURI::FromPotentiallyInvalidSpec(android_form.signon_realm),
         AffiliationService::StrategyOnCacheMiss::FETCH_OVER_NETWORK,
         base::Bind(&AffiliatedMatchHelper::CompleteGetAffiliatedWebRealms,
@@ -99,9 +99,7 @@
   base::Closure barrier_closure =
       base::BarrierClosure(android_credentials.size(), on_get_all_realms);
   for (auto* form : android_credentials) {
-    // TODO(crbug.com/628988): Rename |GetAffiliations| to
-    // |GetAffiliationsAndBranding|.
-    affiliation_service_->GetAffiliations(
+    affiliation_service_->GetAffiliationsAndBranding(
         FacetURI::FromPotentiallyInvalidSpec(form->signon_realm),
         AffiliationService::StrategyOnCacheMiss::FAIL,
         base::Bind(&AffiliatedMatchHelper::
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index 0ec75d17..db62fe2e 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -35,34 +35,35 @@
 
   ~MockAffiliationService() override {}
 
-  MOCK_METHOD2(OnGetAffiliationsCalled,
+  MOCK_METHOD2(OnGetAffiliationsAndBrandingCalled,
                AffiliatedFacets(const FacetURI&, StrategyOnCacheMiss));
   MOCK_METHOD2(Prefetch, void(const FacetURI&, const base::Time&));
   MOCK_METHOD2(CancelPrefetch, void(const FacetURI&, const base::Time&));
   MOCK_METHOD1(TrimCacheForFacetURI, void(const FacetURI&));
 
-  void GetAffiliations(const FacetURI& facet_uri,
-                       StrategyOnCacheMiss cache_miss_strategy,
-                       const ResultCallback& result_callback) override {
+  void GetAffiliationsAndBranding(
+      const FacetURI& facet_uri,
+      StrategyOnCacheMiss cache_miss_strategy,
+      const ResultCallback& result_callback) override {
     AffiliatedFacets affiliation =
-        OnGetAffiliationsCalled(facet_uri, cache_miss_strategy);
+        OnGetAffiliationsAndBrandingCalled(facet_uri, cache_miss_strategy);
     result_callback.Run(affiliation, !affiliation.empty());
   }
 
-  void ExpectCallToGetAffiliationsAndSucceedWithResult(
+  void ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
       const FacetURI& expected_facet_uri,
       StrategyOnCacheMiss expected_cache_miss_strategy,
       const AffiliatedFacets& affiliations_to_return) {
-    EXPECT_CALL(*this, OnGetAffiliationsCalled(expected_facet_uri,
-                                               expected_cache_miss_strategy))
+    EXPECT_CALL(*this, OnGetAffiliationsAndBrandingCalled(
+                           expected_facet_uri, expected_cache_miss_strategy))
         .WillOnce(testing::Return(affiliations_to_return));
   }
 
-  void ExpectCallToGetAffiliationsAndEmulateFailure(
+  void ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
       const FacetURI& expected_facet_uri,
       StrategyOnCacheMiss expected_cache_miss_strategy) {
-    EXPECT_CALL(*this, OnGetAffiliationsCalled(expected_facet_uri,
-                                               expected_cache_miss_strategy))
+    EXPECT_CALL(*this, OnGetAffiliationsAndBrandingCalled(
+                           expected_facet_uri, expected_cache_miss_strategy))
         .WillOnce(testing::Return(AffiliatedFacets()));
   }
 
@@ -360,9 +361,10 @@
 // applications, and only if the observed form is a secure HTML login form.
 
 TEST_F(AffiliatedMatchHelperTest, GetAffiliatedAndroidRealmsYieldsResults) {
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1),
-      StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1),
+          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
   EXPECT_THAT(GetAffiliatedAndroidRealms(
                   GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)),
               testing::UnorderedElementsAre(kTestAndroidRealmBeta2,
@@ -371,9 +373,10 @@
 
 TEST_F(AffiliatedMatchHelperTest,
        GetAffiliatedAndroidRealmsYieldsOnlyAndroidApps) {
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
-      StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
+          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
   // This verifies that |kTestWebRealmAlpha2| is not returned.
   EXPECT_THAT(GetAffiliatedAndroidRealms(
                   GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)),
@@ -408,9 +411,10 @@
 
 TEST_F(AffiliatedMatchHelperTest,
        GetAffiliatedAndroidRealmsYieldsEmptyResultsWhenNoPrefetch) {
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure(
-      FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
-      StrategyOnCacheMiss::FAIL);
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
+          FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
+          StrategyOnCacheMiss::FAIL);
   EXPECT_THAT(GetAffiliatedAndroidRealms(
                   GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)),
               testing::IsEmpty());
@@ -421,9 +425,11 @@
 // only web sites, and only if an Android application is queried.
 
 TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsResults) {
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
-      StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
+          StrategyOnCacheMiss::FETCH_OVER_NETWORK,
+          GetTestEquivalenceClassAlpha());
   PasswordStore::FormDigest android_form(
       GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
   EXPECT_THAT(
@@ -432,9 +438,11 @@
 }
 
 TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsOnlyWebsites) {
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
-      StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassBeta());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
+          StrategyOnCacheMiss::FETCH_OVER_NETWORK,
+          GetTestEquivalenceClassBeta());
   PasswordStore::FormDigest android_form(
       GetTestAndroidCredentials(kTestAndroidRealmBeta2));
   // This verifies that |kTestAndroidRealmBeta3| is not returned.
@@ -458,27 +466,31 @@
 
   forms.push_back(base::MakeUnique<autofill::PasswordForm>(
       GetTestAndroidCredentials(kTestAndroidRealmAlpha3)));
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
-      StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
+          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
 
   forms.push_back(base::MakeUnique<autofill::PasswordForm>(
       GetTestAndroidCredentials(kTestAndroidRealmBeta2)));
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
-      StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
+          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
 
   forms.push_back(base::MakeUnique<autofill::PasswordForm>(
       GetTestAndroidCredentials(kTestAndroidRealmBeta3)));
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
-      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
-      StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
+          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
+          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
 
   forms.push_back(base::MakeUnique<autofill::PasswordForm>(
       GetTestAndroidCredentials(kTestAndroidRealmGamma)));
-  mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure(
-      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma),
-      StrategyOnCacheMiss::FAIL);
+  mock_affiliation_service()
+      ->ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
+          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma),
+          StrategyOnCacheMiss::FAIL);
 
   PasswordStore::FormDigest digest =
       GetTestObservedWebForm(kTestWebRealmBeta1, nullptr);
@@ -524,8 +536,9 @@
 
 // Verifies that affiliations for Android applications with pre-existing
 // credentials on start-up are prefetched.
-TEST_F(AffiliatedMatchHelperTest,
-       PrefetchAffiliationsForPreexistingAndroidCredentialsOnStartup) {
+TEST_F(
+    AffiliatedMatchHelperTest,
+    PrefetchAffiliationsAndBrandingForPreexistingAndroidCredentialsOnStartup) {
   AddAndroidAndNonAndroidTestLogins();
 
   match_helper()->Initialize();
@@ -561,7 +574,7 @@
 }
 
 TEST_F(AffiliatedMatchHelperTest,
-       CancelPrefetchingAffiliationsForRemovedAndroidCredentials) {
+       CancelPrefetchingAffiliationsAndBrandingForRemovedAndroidCredentials) {
   AddAndroidAndNonAndroidTestLogins();
   match_helper()->Initialize();
   ExpectPrefetchForAndroidTestLogins();
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc b/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
index 5ea603a..4c6aca9 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
@@ -56,7 +56,7 @@
   cache_->Init(db_path);
 }
 
-void AffiliationBackend::GetAffiliations(
+void AffiliationBackend::GetAffiliationsAndBranding(
     const FacetURI& facet_uri,
     StrategyOnCacheMiss cache_miss_strategy,
     const AffiliationService::ResultCallback& callback,
@@ -65,8 +65,8 @@
 
   FacetManager* facet_manager = GetOrCreateFacetManager(facet_uri);
   DCHECK(facet_manager);
-  facet_manager->GetAffiliations(cache_miss_strategy, callback,
-                                 callback_task_runner);
+  facet_manager->GetAffiliationsAndBranding(cache_miss_strategy, callback,
+                                            callback_task_runner);
 
   if (facet_manager->CanBeDiscarded())
     facet_managers_.erase(facet_uri);
@@ -101,7 +101,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   AffiliatedFacetsWithUpdateTime affiliation;
-  if (cache_->GetAffiliationsForFacetURI(facet_uri, &affiliation))
+  if (cache_->GetAffiliationsAndBrandingForFacetURI(facet_uri, &affiliation))
     DiscardCachedDataIfNoLongerNeeded(affiliation.facets);
 }
 
@@ -135,7 +135,7 @@
   }
 
   CHECK(!affiliated_facets.empty());
-  cache_->DeleteAffiliationsForFacetURI(affiliated_facets[0].uri);
+  cache_->DeleteAffiliationsAndBrandingForFacetURI(affiliated_facets[0].uri);
 }
 
 void AffiliationBackend::OnSendNotification(const FacetURI& facet_uri) {
@@ -150,10 +150,10 @@
     facet_managers_.erase(facet_uri);
 }
 
-bool AffiliationBackend::ReadAffiliationsFromDatabase(
+bool AffiliationBackend::ReadAffiliationsAndBrandingFromDatabase(
     const FacetURI& facet_uri,
     AffiliatedFacetsWithUpdateTime* affiliations) {
-  return cache_->GetAffiliationsForFacetURI(facet_uri, affiliations);
+  return cache_->GetAffiliationsAndBrandingForFacetURI(facet_uri, affiliations);
 }
 
 void AffiliationBackend::SignalNeedNetworkRequest() {
@@ -208,8 +208,9 @@
     }
   }
 
-  // A subsequent fetch may be needed if any additional GetAffiliations()
-  // requests came in while the current fetch was in flight.
+  // A subsequent fetch may be needed if any additional
+  // GetAffiliationsAndBranding() requests came in while the current fetch was
+  // in flight.
   for (const auto& facet_manager_pair : facet_managers_) {
     if (facet_manager_pair.second->DoesRequireFetch()) {
       throttler_->SignalNetworkRequestNeeded();
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend.h b/components/password_manager/core/browser/android_affiliation/affiliation_backend.h
index 39edeb1..dadeb111 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <map>
+#include <memory>
 #include <unordered_map>
 #include <vector>
 
@@ -73,7 +74,7 @@
 
   // Implementations for methods of the same name in AffiliationService. They
   // are not documented here again. See affiliation_service.h for details:
-  void GetAffiliations(
+  void GetAffiliationsAndBranding(
       const FacetURI& facet_uri,
       StrategyOnCacheMiss cache_miss_strategy,
       const AffiliationService::ResultCallback& callback,
@@ -107,7 +108,7 @@
   void OnSendNotification(const FacetURI& facet_uri);
 
   // FacetManagerHost:
-  bool ReadAffiliationsFromDatabase(
+  bool ReadAffiliationsAndBrandingFromDatabase(
       const FacetURI& facet_uri,
       AffiliatedFacetsWithUpdateTime* affiliations) override;
   void SignalNeedNetworkRequest() override;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
index e09a601..ce1bb521 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
@@ -39,7 +39,8 @@
 // flight, and in how it goes back to the idle state afterwards.
 class MockAffiliationFetchThrottler : public AffiliationFetchThrottler {
  public:
-  MockAffiliationFetchThrottler(AffiliationFetchThrottlerDelegate* delegate)
+  explicit MockAffiliationFetchThrottler(
+      AffiliationFetchThrottlerDelegate* delegate)
       : AffiliationFetchThrottler(delegate, nullptr, nullptr),
         signaled_network_request_needed_(false) {
     EXPECT_CALL(*this, OnInformOfNetworkRequestComplete(testing::_)).Times(0);
@@ -100,6 +101,9 @@
 const char kTestFacetURIAlpha1[] = "https://one.alpha.example.com";
 const char kTestFacetURIAlpha2[] = "https://two.alpha.example.com";
 const char kTestFacetURIAlpha3[] = "https://three.alpha.example.com";
+const char kTestFacetURIAlpha4[] = "android://hash@com.example.alpha.android";
+const char kTestFacetNameAlpha4[] = "Facet Name Alpha";
+const char kTestFacetIconURLAlpha4[] = "https://example.com/alpha.png";
 const char kTestFacetURIBeta1[] = "https://one.beta.example.com";
 const char kTestFacetURIBeta2[] = "https://two.beta.example.com";
 const char kTestFacetURIGamma1[] = "https://gamma.example.com";
@@ -109,6 +113,8 @@
       {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)},
       {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)},
       {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha3)},
+      {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha4),
+       FacetBrandingInfo{kTestFacetNameAlpha4, GURL(kTestFacetIconURLAlpha4)}},
   };
 }
 
@@ -153,12 +159,12 @@
   ~AffiliationBackendTest() override {}
 
  protected:
-  void GetAffiliations(MockAffiliationConsumer* consumer,
-                       const FacetURI& facet_uri,
-                       StrategyOnCacheMiss cache_miss_strategy) {
-    backend_->GetAffiliations(facet_uri, cache_miss_strategy,
-                              consumer->GetResultCallback(),
-                              consumer_task_runner());
+  void GetAffiliationsAndBranding(MockAffiliationConsumer* consumer,
+                                  const FacetURI& facet_uri,
+                                  StrategyOnCacheMiss cache_miss_strategy) {
+    backend_->GetAffiliationsAndBranding(facet_uri, cache_miss_strategy,
+                                         consumer->GetResultCallback(),
+                                         consumer_task_runner());
   }
 
   void Prefetch(const FacetURI& facet_uri, base::Time keep_fresh_until) {
@@ -213,11 +219,11 @@
     testing::Mock::VerifyAndClearExpectations(consumer);
   }
 
-  void GetAffiliationsAndExpectFetchAndThenResult(
+  void GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       const FacetURI& facet_uri,
       const AffiliatedFacets& expected_result) {
-    GetAffiliations(mock_consumer(), facet_uri,
-                    StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+    GetAffiliationsAndBranding(mock_consumer(), facet_uri,
+                               StrategyOnCacheMiss::FETCH_OVER_NETWORK);
     ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
     ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri));
     mock_consumer()->ExpectSuccessWithResult(expected_result);
@@ -225,11 +231,11 @@
     testing::Mock::VerifyAndClearExpectations(mock_consumer());
   }
 
-  void GetAffiliationsAndExpectResultWithoutFetch(
+  void GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
       const FacetURI& facet_uri,
       StrategyOnCacheMiss cache_miss_strategy,
       const AffiliatedFacets& expected_result) {
-    GetAffiliations(mock_consumer(), facet_uri, cache_miss_strategy);
+    GetAffiliationsAndBranding(mock_consumer(), facet_uri, cache_miss_strategy);
     ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
     mock_consumer()->ExpectSuccessWithResult(expected_result);
     consumer_task_runner_->RunUntilIdle();
@@ -239,8 +245,10 @@
   // TODO(engedy): Within this test fixture, the word "failure" refers to GTest
   // failures, simulated network failures (above), and also AffiliationService
   // failure callbacks. Make this less ambiguous.
-  void GetAffiliationsAndExpectFailureWithoutFetch(const FacetURI& facet_uri) {
-    GetAffiliations(mock_consumer(), facet_uri, StrategyOnCacheMiss::FAIL);
+  void GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
+      const FacetURI& facet_uri) {
+    GetAffiliationsAndBranding(mock_consumer(), facet_uri,
+                               StrategyOnCacheMiss::FAIL);
     ASSERT_NO_FATAL_FAILURE(ExpectFailureWithoutFetch(mock_consumer()));
   }
 
@@ -251,16 +259,19 @@
     ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri));
   }
 
-  // Verifies that both on-demand and cached-only GetAffiliations() requests for
-  // each facet in |affiliated_facets| are served from cache with no fetches.
+  // Verifies that both on-demand and cached-only GetAffiliationsAndBranding()
+  // requests for each facet in |affiliated_facets| are served from cache with
+  // no fetches.
   void ExpectThatEquivalenceClassIsServedFromCache(
       const AffiliatedFacets& affiliated_facets) {
     for (const Facet& facet : affiliated_facets) {
       SCOPED_TRACE(facet.uri);
-      ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
-          facet.uri, StrategyOnCacheMiss::FAIL, affiliated_facets));
-      ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
-          facet.uri, StrategyOnCacheMiss::FAIL, affiliated_facets));
+      ASSERT_NO_FATAL_FAILURE(
+          GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
+              facet.uri, StrategyOnCacheMiss::FAIL, affiliated_facets));
+      ASSERT_NO_FATAL_FAILURE(
+          GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
+              facet.uri, StrategyOnCacheMiss::FAIL, affiliated_facets));
     }
   }
 
@@ -276,7 +287,7 @@
     AffiliationDatabase database;
     EXPECT_TRUE(database.Init(db_path()));
     std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations;
-    database.GetAllAffiliations(&all_affiliations);
+    database.GetAllAffiliationsAndBranding(&all_affiliations);
     return all_affiliations.size();
   }
 
@@ -350,12 +361,12 @@
 };
 
 TEST_F(AffiliationBackendTest, OnDemandRequestSucceedsWithFetch) {
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
   EXPECT_EQ(0u, backend_facet_manager_count());
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIBeta1),
       GetTestEquivalenceClassBeta()));
   EXPECT_EQ(0u, backend_facet_manager_count());
@@ -363,7 +374,7 @@
 
 // This test also verifies that the FacetManager is immediately discarded.
 TEST_F(AffiliationBackendTest, CachedOnlyRequestFailsDueToCacheMiss) {
-  GetAffiliationsAndExpectFailureWithoutFetch(
+  GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2));
   EXPECT_EQ(0u, backend_facet_manager_count());
 }
@@ -384,13 +395,15 @@
   EXPECT_FALSE(backend_task_runner()->HasPendingTask());
 }
 
-// One additional GetAffiliations() and one Prefetch() request come in, both for
-// unrelated facets, shortly after an initial GetAffiliations() request.
+// One additional GetAffiliationsAndBranding() and one Prefetch() request come
+// in, both for unrelated facets, shortly after an initial
+// GetAffiliationsAndBranding() request.
 //
-// Suppose that the network request triggered by the first GetAffiliations()
-// request has already been initiated when the other requests arrive. As there
-// should be no simultaneous requests, the additional facets should be queried
-// together in a second fetch after the first fetch completes.
+// Suppose that the network request triggered by the first
+// GetAffiliationsAndBranding() request has already been initiated when the
+// other requests arrive. As there should be no simultaneous requests, the
+// additional facets should be queried together in a second fetch after the
+// first fetch completes.
 TEST_F(AffiliationBackendTest, ConcurrentUnrelatedRequests) {
   FacetURI facet_uri_alpha(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
   FacetURI facet_uri_beta(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1));
@@ -398,11 +411,11 @@
 
   // Pretend the fetch is already away when the two other requests come in.
   MockAffiliationConsumer second_consumer;
-  GetAffiliations(mock_consumer(), facet_uri_alpha,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(mock_consumer(), facet_uri_alpha,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
-  GetAffiliations(&second_consumer, facet_uri_beta,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(&second_consumer, facet_uri_beta,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   Prefetch(facet_uri_gamma, base::Time::Max());
 
   std::vector<FacetURI> second_fetch_uris;
@@ -432,10 +445,10 @@
   FacetURI facet_uri_gamma(FacetURI::FromCanonicalSpec(kTestFacetURIGamma1));
 
   MockAffiliationConsumer second_consumer;
-  GetAffiliations(mock_consumer(), facet_uri_alpha,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
-  GetAffiliations(&second_consumer, facet_uri_beta,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(mock_consumer(), facet_uri_alpha,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(&second_consumer, facet_uri_beta,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   Prefetch(facet_uri_gamma, base::Time::Max());
 
   std::vector<FacetURI> fetched_uris;
@@ -460,8 +473,8 @@
 TEST_F(AffiliationBackendTest, RetryIsMadeOnFailedFetch) {
   FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
 
-  GetAffiliations(mock_consumer(), facet_uri,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(mock_consumer(), facet_uri,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
   ASSERT_NO_FATAL_FAILURE(ExpectAndFailFetch(facet_uri));
   EXPECT_EQ(1u, backend_facet_manager_count());
@@ -493,15 +506,15 @@
 }
 
 TEST_F(AffiliationBackendTest, CacheServesSubsequentRequestForSameFacet) {
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha()));
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha()));
 
@@ -509,7 +522,7 @@
 }
 
 TEST_F(AffiliationBackendTest, CacheServesSubsequentRequestForAffiliatedFacet) {
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
 
@@ -523,11 +536,11 @@
   ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha()));
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectResultWithoutFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha()));
 }
@@ -541,9 +554,9 @@
       GetTestEquivalenceClassAlpha()));
 }
 
-// A second GetAffiliations() request for the same facet and a third request
-// for an affiliated facet comes in while the network fetch triggered by the
-// first request is in flight.
+// A second GetAffiliationsAndBranding() request for the same facet and a third
+// request for an affiliated facet comes in while the network fetch triggered by
+// the first request is in flight.
 //
 // There should be no simultaneous requests, and once the fetch completes, all
 // three requests should be served without further fetches (they have the data).
@@ -554,13 +567,13 @@
 
   MockAffiliationConsumer second_consumer;
   MockAffiliationConsumer third_consumer;
-  GetAffiliations(mock_consumer(), facet_uri1,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(mock_consumer(), facet_uri1,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
-  GetAffiliations(&second_consumer, facet_uri1,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
-  GetAffiliations(&third_consumer, facet_uri2,
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(&second_consumer, facet_uri1,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(&third_consumer, facet_uri2,
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
 
   ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri1));
   ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
@@ -598,7 +611,7 @@
 }
 
 TEST_F(AffiliationBackendTest, SimpleCacheExpiryWithoutPrefetches) {
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
 
@@ -615,10 +628,10 @@
   // subsequent on-demand request should fetch the data again and succeed.
   EXPECT_FALSE(IsCachedDataFreshForFacetURI(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
-  GetAffiliationsAndExpectFailureWithoutFetch(
+  GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
       GetTestEquivalenceClassAlpha()));
 
@@ -670,20 +683,22 @@
   EXPECT_EQ(0u, backend_facet_manager_count());
   EXPECT_FALSE(backend_task_runner()->HasPendingTask());
 
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
-      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
-      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)));
+  ASSERT_NO_FATAL_FAILURE(
+      GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
+          FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+  ASSERT_NO_FATAL_FAILURE(
+      GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
+          FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)));
 
   // However, a subsequent on-demand request should be able to trigger a fetch.
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
 }
 
 // Affiliation data for prefetched facets should be automatically refetched once
-// every 23 hours, and GetAffiliations() requests regarding affiliated facets
-// should be continuously served from cache.
+// every 23 hours, and GetAffiliationsAndBranding() requests regarding
+// affiliated facets should be continuously served from cache.
 TEST_F(AffiliationBackendTest, PrefetchTriggersPeriodicRefetch) {
   ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
@@ -715,7 +730,7 @@
 
 TEST_F(AffiliationBackendTest,
        PrefetchTriggersNoInitialFetchIfDataIsAlreadyFresh) {
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
 
@@ -748,10 +763,12 @@
   EXPECT_FALSE(backend_task_runner()->HasPendingTask());
   EXPECT_TRUE(IsCachedDataNearStaleForFacetURI(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
-      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
-      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)));
+  ASSERT_NO_FATAL_FAILURE(
+      GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
+          FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+  ASSERT_NO_FATAL_FAILURE(
+      GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
+          FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)));
 }
 
 TEST_F(AffiliationBackendTest, CancelDuplicatePrefetch) {
@@ -798,10 +815,10 @@
 TEST_F(AffiliationBackendTest,
        TrimCacheForFacetURIOnlyRemovesDataForTheGivenFacet) {
   FacetURI preserved_facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1));
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
       GetTestEquivalenceClassAlpha()));
-  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+  ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndBrandingAndExpectFetchAndThenResult(
       preserved_facet_uri, GetTestEquivalenceClassBeta()));
   EXPECT_EQ(2u, GetNumOfEquivalenceClassInDatabase());
 
@@ -818,13 +835,14 @@
   AdvanceTime(Epsilon());
   EXPECT_FALSE(IsCachedDataFreshForFacetURI(preserved_facet_uri));
   ASSERT_NO_FATAL_FAILURE(
-      GetAffiliationsAndExpectFailureWithoutFetch(preserved_facet_uri));
+      GetAffiliationsAndBrandingAndExpectFailureWithoutFetch(
+          preserved_facet_uri));
 }
 
 TEST_F(AffiliationBackendTest, NothingExplodesWhenShutDownDuringFetch) {
-  GetAffiliations(mock_consumer(),
-                  FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(mock_consumer(),
+                             FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
   mock_fetch_throttler()->reset_signaled_network_request_needed();
   DestroyBackend();
@@ -832,11 +850,12 @@
 
 TEST_F(AffiliationBackendTest,
        FailureCallbacksAreCalledIfBackendIsDestroyedWithPendingRequest) {
-  GetAffiliations(mock_consumer(),
-                  FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
-                  StrategyOnCacheMiss::FETCH_OVER_NETWORK);
-  // Currently, a GetAffiliations() request can only be blocked due to fetch in
-  // flight -- so emulate this condition when destroying the backend.
+  GetAffiliationsAndBranding(mock_consumer(),
+                             FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
+                             StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  // Currently, a GetAffiliationsAndBranding() request can only be blocked due
+  // to fetch in flight -- so emulate this condition when destroying the
+  // backend.
   ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
   mock_fetch_throttler()->reset_signaled_network_request_needed();
   DestroyBackend();
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_database.cc b/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
index 9cc91ce..560fcea6 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
@@ -89,7 +89,7 @@
   return true;
 }
 
-bool AffiliationDatabase::GetAffiliationsForFacetURI(
+bool AffiliationDatabase::GetAffiliationsAndBrandingForFacetURI(
     const FacetURI& facet_uri,
     AffiliatedFacetsWithUpdateTime* result) const {
   DCHECK(result);
@@ -116,7 +116,7 @@
   return !result->facets.empty();
 }
 
-void AffiliationDatabase::GetAllAffiliations(
+void AffiliationDatabase::GetAllAffiliationsAndBranding(
     std::vector<AffiliatedFacetsWithUpdateTime>* results) const {
   DCHECK(results);
   results->clear();
@@ -146,7 +146,7 @@
   }
 }
 
-void AffiliationDatabase::DeleteAffiliationsForFacetURI(
+void AffiliationDatabase::DeleteAffiliationsAndBrandingForFacetURI(
     const FacetURI& facet_uri) {
   sql::Transaction transaction(sql_connection_.get());
   if (!transaction.Begin())
@@ -174,7 +174,7 @@
   transaction.Commit();
 }
 
-void AffiliationDatabase::DeleteAffiliationsOlderThan(
+void AffiliationDatabase::DeleteAffiliationsAndBrandingOlderThan(
     const base::Time& cutoff_threshold) {
   // Children will get deleted due to 'ON DELETE CASCADE'.
   sql::Statement statement_parent(sql_connection_->GetCachedStatement(
@@ -185,7 +185,7 @@
   statement_parent.Run();
 }
 
-void AffiliationDatabase::DeleteAllAffiliations() {
+void AffiliationDatabase::DeleteAllAffiliationsAndBranding() {
   // Children will get deleted due to 'ON DELETE CASCADE'.
   sql::Statement statement_parent(
       sql_connection_->GetUniqueStatement("DELETE FROM eq_classes"));
@@ -242,12 +242,12 @@
 
   for (const Facet& facet : affiliation.facets) {
     AffiliatedFacetsWithUpdateTime old_affiliation;
-    if (GetAffiliationsForFacetURI(facet.uri, &old_affiliation)) {
+    if (GetAffiliationsAndBrandingForFacetURI(facet.uri, &old_affiliation)) {
       if (!AreEquivalenceClassesEqual(old_affiliation.facets,
                                       affiliation.facets)) {
         removed_affiliations->push_back(old_affiliation);
       }
-      DeleteAffiliationsForFacetURI(facet.uri);
+      DeleteAffiliationsAndBrandingForFacetURI(facet.uri);
     }
   }
 
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_database.h b/components/password_manager/core/browser/android_affiliation/affiliation_database.h
index 9637673..b380c96e 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_database.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_database.h
@@ -25,8 +25,9 @@
 namespace password_manager {
 
 // Stores equivalence classes of facets, i.e., facets that are affiliated with
-// each other, in an SQLite database. See affiliation_utils.h for a more
-// detailed definition of what this means.
+// each other, in an SQLite database. In addition, relevant branding information
+// is stored. See affiliation_utils.h for a more detailed definition of what
+// this means.
 //
 // Under the assumption that there is most likely not much the caller can do in
 // case of database errors, most methods silently ignore them. Nevertheless, the
@@ -42,33 +43,39 @@
   bool Init(const base::FilePath& path);
 
   // Looks up the equivalence class containing |facet_uri|, and returns true if
-  // such a class is found, in which case it is also stored into |result|.
-  bool GetAffiliationsForFacetURI(const FacetURI& facet_uri,
-                                  AffiliatedFacetsWithUpdateTime* result) const;
+  // such a class is found, in which case it is also stored into |result|
+  // together with branding information, if applicable.
+  bool GetAffiliationsAndBrandingForFacetURI(
+      const FacetURI& facet_uri,
+      AffiliatedFacetsWithUpdateTime* result) const;
 
-  // Retrieves all stored equivalence classes.
-  void GetAllAffiliations(
+  // Retrieves all stored equivalence classes and branding information.
+  void GetAllAffiliationsAndBranding(
       std::vector<AffiliatedFacetsWithUpdateTime>* results) const;
 
-  // Removes the stored equivalence class, if any, containing |facet_uri|.
-  void DeleteAffiliationsForFacetURI(const FacetURI& facet_uri);
+  // Removes the stored equivalence class and branding information, if any,
+  // containing |facet_uri|.
+  void DeleteAffiliationsAndBrandingForFacetURI(const FacetURI& facet_uri);
 
-  // Removes stored equivalence classes that were last updated before the
-  // |cutoff_threshold|.
-  void DeleteAffiliationsOlderThan(const base::Time& cutoff_threshold);
+  // Removes stored equivalence classes and branding information that were last
+  // updated before the |cutoff_threshold|.
+  void DeleteAffiliationsAndBrandingOlderThan(
+      const base::Time& cutoff_threshold);
 
   // Removes all records from all tables of the database.
-  void DeleteAllAffiliations();
+  void DeleteAllAffiliationsAndBranding();
 
-  // Stores the equivalence class defined by |affiliated_facets| to the DB and
-  // returns true unless it has a non-empty subset with a preexisting class, in
-  // which case no changes are made and the function returns false.
+  // Stores the equivalence class and branding information defined by
+  // |affiliated_facets| to the DB and returns true unless it has a non-empty
+  // subset with a preexisting class, in which case no changes are made and the
+  // function returns false.
   bool Store(const AffiliatedFacetsWithUpdateTime& affiliated_facets);
 
-  // Stores the equivalence class defined by |affiliated_facets| to the DB,
-  // database, and removes any other equivalence classes that are in conflict
-  // with |affiliated_facets|, i.e. those that are neither equal nor disjoint to
-  // it. Removed equivalence classes are stored into |removed_affiliations|.
+  // Stores the equivalence class and branding information defined by
+  // |affiliated_facets| to the database, and removes any other equivalence
+  // classes that are in conflict with |affiliated_facets|, i.e. those that are
+  // neither equal nor disjoint to it. Removed equivalence classes are stored
+  // into |removed_affiliations|.
   void StoreAndRemoveConflicting(
       const AffiliatedFacetsWithUpdateTime& affiliated_facets,
       std::vector<AffiliatedFacetsWithUpdateTime>* removed_affiliations);
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
index 3af5d53..9f6e67a7 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
@@ -144,17 +144,17 @@
   }
 }
 
-TEST_F(AffiliationDatabaseTest, GetAllAffiliations) {
+TEST_F(AffiliationDatabaseTest, GetAllAffiliationsAndBranding) {
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
 
   // Empty database should not return any equivalence classes.
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   EXPECT_EQ(0u, affiliations.size());
 
   ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
 
   // The test data should be returned in order.
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(3u, affiliations.size());
   ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass1(),
                                                         affiliations[0]);
@@ -171,7 +171,8 @@
   // class.
   for (const auto& facet : TestEquivalenceClass1().facets) {
     AffiliatedFacetsWithUpdateTime affiliation;
-    EXPECT_TRUE(db().GetAffiliationsForFacetURI(facet.uri, &affiliation));
+    EXPECT_TRUE(
+        db().GetAffiliationsAndBrandingForFacetURI(facet.uri, &affiliation));
     ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(
         TestEquivalenceClass1(), affiliation);
   }
@@ -180,7 +181,7 @@
   // that class.
   {
     AffiliatedFacetsWithUpdateTime affiliation;
-    EXPECT_TRUE(db().GetAffiliationsForFacetURI(
+    EXPECT_TRUE(db().GetAffiliationsAndBrandingForFacetURI(
         FacetURI::FromCanonicalSpec(kTestAndroidFacetURI), &affiliation));
     ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(
         TestEquivalenceClass3(), affiliation);
@@ -189,7 +190,7 @@
   // Verify that querying a facet not in the database yields no result.
   {
     AffiliatedFacetsWithUpdateTime affiliation;
-    EXPECT_FALSE(db().GetAffiliationsForFacetURI(
+    EXPECT_FALSE(db().GetAffiliationsAndBrandingForFacetURI(
         FacetURI::FromCanonicalSpec(kTestFacetURI6), &affiliation));
     ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(
         AffiliatedFacetsWithUpdateTime(), affiliation);
@@ -210,7 +211,7 @@
     EXPECT_EQ(0u, removed.size());
 
     AffiliatedFacetsWithUpdateTime affiliation;
-    EXPECT_TRUE(db().GetAffiliationsForFacetURI(
+    EXPECT_TRUE(db().GetAffiliationsAndBrandingForFacetURI(
         FacetURI::FromCanonicalSpec(kTestFacetURI1), &affiliation));
     ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(updated, affiliation);
   }
@@ -233,7 +234,7 @@
         TestEquivalenceClass2(), removed[1]);
 
     std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-    db().GetAllAffiliations(&affiliations);
+    db().GetAllAffiliationsAndBranding(&affiliations);
     ASSERT_EQ(2u, affiliations.size());
     ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(
         TestEquivalenceClass3(), affiliations[0]);
@@ -242,36 +243,37 @@
   }
 }
 
-TEST_F(AffiliationDatabaseTest, DeleteAllAffiliations) {
-  db().DeleteAllAffiliations();
+TEST_F(AffiliationDatabaseTest, DeleteAllAffiliationsAndBranding) {
+  db().DeleteAllAffiliationsAndBranding();
 
   ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
 
-  db().DeleteAllAffiliations();
+  db().DeleteAllAffiliationsAndBranding();
 
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(0u, affiliations.size());
 }
 
-TEST_F(AffiliationDatabaseTest, DeleteAffiliationsOlderThan) {
-  db().DeleteAffiliationsOlderThan(base::Time::FromInternalValue(0));
+TEST_F(AffiliationDatabaseTest, DeleteAffiliationsAndBrandingOlderThan) {
+  db().DeleteAffiliationsAndBrandingOlderThan(base::Time::FromInternalValue(0));
 
   ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
 
-  db().DeleteAffiliationsOlderThan(base::Time::FromInternalValue(kTestTimeUs2));
+  db().DeleteAffiliationsAndBrandingOlderThan(
+      base::Time::FromInternalValue(kTestTimeUs2));
 
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(2u, affiliations.size());
   ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass2(),
                                                         affiliations[0]);
   ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass3(),
                                                         affiliations[1]);
 
-  db().DeleteAffiliationsOlderThan(base::Time::Max());
+  db().DeleteAffiliationsAndBrandingOlderThan(base::Time::Max());
 
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(0u, affiliations.size());
 }
 
@@ -284,7 +286,7 @@
 
   // The test data should be returned in order.
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(3u, affiliations.size());
   ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass1(),
                                                         affiliations[0]);
@@ -304,11 +306,11 @@
   ASSERT_NO_FATAL_FAILURE(OpenDatabase());
 
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   EXPECT_EQ(0u, affiliations.size());
 
   ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   EXPECT_EQ(3u, affiliations.size());
 }
 
@@ -321,7 +323,7 @@
 
   EXPECT_FALSE(db().Store(TestEquivalenceClass2()));
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   EXPECT_EQ(0u, affiliations.size());
 }
 
@@ -354,7 +356,7 @@
   // Check that migration was successful and existing data was untouched.
   EXPECT_EQ(2, db().GetDatabaseVersionForTesting());
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(3u, affiliations.size());
 
   // There was no branding information in version 1, thus we expect it to be
@@ -392,7 +394,7 @@
   // Expect the migration to be a no-op that does not modify the existing data.
   OpenDatabase();
   std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliations(&affiliations);
+  db().GetAllAffiliationsAndBranding(&affiliations);
   ASSERT_EQ(3u, affiliations.size());
   ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass1(),
                                                         affiliations[0]);
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service.cc b/components/password_manager/core/browser/android_affiliation/affiliation_service.cc
index c10adbed..620dbdac 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service.cc
@@ -4,6 +4,8 @@
 
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
@@ -48,7 +50,7 @@
                             base::Unretained(backend_), db_path));
 }
 
-void AffiliationService::GetAffiliations(
+void AffiliationService::GetAffiliationsAndBranding(
     const FacetURI& facet_uri,
     StrategyOnCacheMiss cache_miss_strategy,
     const ResultCallback& result_callback) {
@@ -56,7 +58,7 @@
   DCHECK(backend_);
   backend_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&AffiliationBackend::GetAffiliations,
+      base::Bind(&AffiliationBackend::GetAffiliationsAndBranding,
                  base::Unretained(backend_), facet_uri, cache_miss_strategy,
                  result_callback, base::SequencedTaskRunnerHandle::Get()));
 }
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service.h b/components/password_manager/core/browser/android_affiliation/affiliation_service.h
index 2839f45..8c9d8e180 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service.h
@@ -40,7 +40,8 @@
 //       network request to the Affiliation API containing the URI of facet X
 //       is acceptable from the privacy and/or performance perspective.
 //
-//       This mode of operation is achieved by invoking GetAffiliations() with
+//       This mode of operation is achieved by invoking
+//       GetAffiliationsAndBranding() with
 //       StrategyOnCacheMiss::FETCH_OVER_NETWORK.
 //
 //   2.) Proactive fetching: For the compound query that is concerned with
@@ -69,7 +70,7 @@
 //         ~ExampleAffiliatedCredentialFiller() { cancel_handle_.Run(); }
 //
 //         void ShouldFillInto(const FacetURI& wi, FillDelegate* delegate) {
-//           service_->GetAffiliations(wi, StrategyOnCacheMiss::FAIL,
+//           service_->GetAffiliationsAndBranding(wi, StrategyOnCacheMiss::FAIL,
 //               base::Bind(
 //                   &ExampleAffiliatedCredentialFiller::OnAffiliationResult,
 //                   AsWeakPtr(),
@@ -107,18 +108,19 @@
   void Initialize(net::URLRequestContextGetter* request_context_getter,
                   const base::FilePath& db_path);
 
-  // Looks up facets affiliated with the facet identified by |facet_uri|, and
-  // invokes |result_callback| with the results. It is guaranteed that the
-  // results will contain one facet with URI equal to |facet_uri| when
-  // |result_callback| is invoked with success set to true.
+  // Looks up facets affiliated with the facet identified by |facet_uri| and
+  // branding information, and invokes |result_callback| with the results. It is
+  // guaranteed that the results will contain one facet with URI equal to
+  // |facet_uri| when |result_callback| is invoked with success set to true.
   //
-  // If the local cache contains fresh affiliation information for |facet_uri|,
-  // the request will be served from cache. Otherwise, |cache_miss_policy|
-  // controls whether to issue an on-demand network request, or to fail the
-  // request without fetching.
-  virtual void GetAffiliations(const FacetURI& facet_uri,
-                               StrategyOnCacheMiss cache_miss_strategy,
-                               const ResultCallback& result_callback);
+  // If the local cache contains fresh affiliation and branding information for
+  // |facet_uri|, the request will be served from cache. Otherwise,
+  // |cache_miss_policy| controls whether to issue an on-demand network request,
+  // or to fail the request without fetching.
+  virtual void GetAffiliationsAndBranding(
+      const FacetURI& facet_uri,
+      StrategyOnCacheMiss cache_miss_strategy,
+      const ResultCallback& result_callback);
 
   // Prefetches affiliation information for the facet identified by |facet_uri|,
   // and keeps the information fresh by periodic re-fetches (as needed) until
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
index 77311bc..4b98c8f5 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
@@ -101,12 +101,13 @@
   DISALLOW_COPY_AND_ASSIGN(AffiliationServiceTest);
 };
 
-TEST_F(AffiliationServiceTest, GetAffiliations) {
+TEST_F(AffiliationServiceTest, GetAffiliationsAndBranding) {
   // The first request allows on-demand fetching, and should trigger a fetch.
   // Then, it should succeed after the fetch is complete.
-  service()->GetAffiliations(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
-                             StrategyOnCacheMiss::FETCH_OVER_NETWORK,
-                             mock_consumer()->GetResultCallback());
+  service()->GetAffiliationsAndBranding(
+      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+      StrategyOnCacheMiss::FETCH_OVER_NETWORK,
+      mock_consumer()->GetResultCallback());
 
   background_task_runner()->RunUntilIdle();
   ASSERT_TRUE(fake_affiliation_api()->HasPendingRequest());
@@ -123,9 +124,9 @@
   testing::Mock::VerifyAndClearExpectations(mock_consumer());
 
   // The second request should be (and can be) served from cache.
-  service()->GetAffiliations(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
-                             StrategyOnCacheMiss::FAIL,
-                             mock_consumer()->GetResultCallback());
+  service()->GetAffiliationsAndBranding(
+      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+      StrategyOnCacheMiss::FAIL, mock_consumer()->GetResultCallback());
 
   background_task_runner()->RunUntilIdle();
   ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
@@ -136,9 +137,9 @@
 
   // The third request is also restricted to the cache, but cannot be served
   // from cache, thus it should fail.
-  service()->GetAffiliations(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1),
-                             StrategyOnCacheMiss::FAIL,
-                             mock_consumer()->GetResultCallback());
+  service()->GetAffiliationsAndBranding(
+      FacetURI::FromCanonicalSpec(kTestFacetURIBeta1),
+      StrategyOnCacheMiss::FAIL, mock_consumer()->GetResultCallback());
 
   background_task_runner()->RunUntilIdle();
   ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
@@ -149,9 +150,10 @@
 }
 
 TEST_F(AffiliationServiceTest, ShutdownWhileTasksArePosted) {
-  service()->GetAffiliations(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
-                             StrategyOnCacheMiss::FETCH_OVER_NETWORK,
-                             mock_consumer()->GetResultCallback());
+  service()->GetAffiliationsAndBranding(
+      FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+      StrategyOnCacheMiss::FETCH_OVER_NETWORK,
+      mock_consumer()->GetResultCallback());
   EXPECT_TRUE(background_task_runner()->HasPendingTask());
 
   DestroyService();
diff --git a/components/password_manager/core/browser/android_affiliation/facet_manager.cc b/components/password_manager/core/browser/android_affiliation/facet_manager.cc
index 68ed9c8..af4c891 100644
--- a/components/password_manager/core/browser/android_affiliation/facet_manager.cc
+++ b/components/password_manager/core/browser/android_affiliation/facet_manager.cc
@@ -7,10 +7,10 @@
 //
 // On-demand fetching strategy
 //
-// A GetAffiliations() request concerning facet X will be served from the cache
-// as long as the cache contains fresh affiliation information for facet X, that
-// is, if there is an equivalence class in the cache that contains X and has
-// been fetched less than |kCacheHardExpiryInHours| hours ago.
+// A GetAffiliationsAndBranding() request concerning facet X will be served from
+// the cache as long as the cache contains fresh affiliation information for
+// facet X, that is, if there is an equivalence class in the cache that contains
+// X and has been fetched less than |kCacheHardExpiryInHours| hours ago.
 //
 // Otherwise, a network request is issued against the Affiliation API as soon as
 // possible, that is, immediately if there is no fetch in flight, or right after
@@ -87,7 +87,7 @@
         FacetManager::kCacheHardExpiryInHours,
     "Soft expiry period must be longer than half of the hard expiry period.");
 
-// Encapsulates the details of a pending GetAffiliations() request.
+// Encapsulates the details of a pending GetAffiliationsAndBranding() request.
 struct FacetManager::RequestInfo {
   AffiliationService::ResultCallback callback;
   scoped_refptr<base::TaskRunner> callback_task_runner;
@@ -98,7 +98,8 @@
                            base::Clock* clock)
     : facet_uri_(facet_uri), backend_(backend), clock_(clock) {
   AffiliatedFacetsWithUpdateTime affiliations;
-  if (backend_->ReadAffiliationsFromDatabase(facet_uri_, &affiliations))
+  if (backend_->ReadAffiliationsAndBrandingFromDatabase(facet_uri_,
+                                                        &affiliations))
     last_update_time_ = affiliations.last_update_time;
 }
 
@@ -109,7 +110,7 @@
     ServeRequestWithFailure(request_info);
 }
 
-void FacetManager::GetAffiliations(
+void FacetManager::GetAffiliationsAndBranding(
     StrategyOnCacheMiss cache_miss_strategy,
     const AffiliationService::ResultCallback& callback,
     const scoped_refptr<base::TaskRunner>& callback_task_runner) {
@@ -118,7 +119,8 @@
   request_info.callback_task_runner = callback_task_runner;
   if (IsCachedDataFresh()) {
     AffiliatedFacetsWithUpdateTime affiliation;
-    if (!backend_->ReadAffiliationsFromDatabase(facet_uri_, &affiliation)) {
+    if (!backend_->ReadAffiliationsAndBrandingFromDatabase(facet_uri_,
+                                                           &affiliation)) {
       ServeRequestWithFailure(request_info);
       return;
     }
diff --git a/components/password_manager/core/browser/android_affiliation/facet_manager.h b/components/password_manager/core/browser/android_affiliation/facet_manager.h
index 916e6c4..ef26ec94 100644
--- a/components/password_manager/core/browser/android_affiliation/facet_manager.h
+++ b/components/password_manager/core/browser/android_affiliation/facet_manager.h
@@ -39,7 +39,7 @@
 
   // Facet-specific implementations for methods in AffiliationService of the
   // same name. See documentation in affiliation_service.h for details:
-  void GetAffiliations(
+  void GetAffiliationsAndBranding(
       StrategyOnCacheMiss cache_miss_strategy,
       const AffiliationService::ResultCallback& callback,
       const scoped_refptr<base::TaskRunner>& callback_task_runner);
@@ -116,8 +116,8 @@
   // in the database should match this value; it is stored to reduce disk I/O.
   base::Time last_update_time_;
 
-  // Contains information about the GetAffiliations() requests that are waiting
-  // for the result of looking up this facet.
+  // Contains information about the GetAffiliationsAndBranding() requests that
+  // are waiting for the result of looking up this facet.
   std::vector<RequestInfo> pending_requests_;
 
   // Keeps track of |keep_fresh_until| thresholds corresponding to Prefetch()
diff --git a/components/password_manager/core/browser/android_affiliation/facet_manager_host.h b/components/password_manager/core/browser/android_affiliation/facet_manager_host.h
index 7536b07..21c12e3 100644
--- a/components/password_manager/core/browser/android_affiliation/facet_manager_host.h
+++ b/components/password_manager/core/browser/android_affiliation/facet_manager_host.h
@@ -18,7 +18,7 @@
 
   // Reads the equivalence class containing |facet_uri| from the database and
   // returns true if found; returns false otherwise.
-  virtual bool ReadAffiliationsFromDatabase(
+  virtual bool ReadAffiliationsAndBrandingFromDatabase(
       const FacetURI& facet_uri,
       AffiliatedFacetsWithUpdateTime* affiliations) = 0;
 
diff --git a/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc b/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
index 154bd2f4..45fd0df5 100644
--- a/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
@@ -98,7 +98,8 @@
   const FacetURI& expected_facet_uri() const { return expected_facet_uri_; }
 
   // Sets up fake |database_content| as the canned response to be returned to
-  // the FacetManager every time it calls ReadAffiliationsFromDatabase().
+  // the FacetManager every time it calls
+  // ReadAffiliationsAndBrandingFromDatabase().
   void set_fake_database_content(
       const AffiliatedFacetsWithUpdateTime& database_content) {
     fake_database_content_ = database_content;
@@ -117,7 +118,7 @@
 
  private:
   // FacetManagerHost:
-  bool ReadAffiliationsFromDatabase(
+  bool ReadAffiliationsAndBrandingFromDatabase(
       const FacetURI& facet_uri,
       AffiliatedFacetsWithUpdateTime* affiliations) override {
     EXPECT_EQ(expected_facet_uri_, facet_uri);
@@ -262,10 +263,10 @@
   // Returns the elapsed time since CreateFacetManager() was last called.
   base::TimeDelta DeltaNow() { return Now() - facet_manager_creation_; }
 
-  void GetAffiliations(StrategyOnCacheMiss cache_miss_strategy) {
-    facet_manager()->GetAffiliations(cache_miss_strategy,
-                                     mock_consumer()->GetResultCallback(),
-                                     consumer_task_runner());
+  void GetAffiliationsAndBranding(StrategyOnCacheMiss cache_miss_strategy) {
+    facet_manager()->GetAffiliationsAndBranding(
+        cache_miss_strategy, mock_consumer()->GetResultCallback(),
+        consumer_task_runner());
   }
 
   void Prefetch(base::Time until) { facet_manager()->Prefetch(until); }
@@ -376,7 +377,7 @@
 
   void ExpectRequestsServedFromCache() {
     EXPECT_TRUE(facet_manager()->IsCachedDataFresh());
-    GetAffiliations(StrategyOnCacheMiss::FAIL);
+    GetAffiliationsAndBranding(StrategyOnCacheMiss::FAIL);
     ExpectConsumerSuccessCallback();
   }
 
@@ -433,9 +434,10 @@
   EXPECT_FALSE(main_task_runner()->HasPendingTask());
 }
 
-// Both cached-only and on-demand GetAffiliations() requests should be served
-// from cache if it contains fresh data. Nothing should happen on cache expiry.
-TEST_F(FacetManagerTest, GetAffiliationsServedFromCache) {
+// Both cached-only and on-demand GetAffiliationsAndBranding() requests should
+// be served from cache if it contains fresh data. Nothing should happen on
+// cache expiry.
+TEST_F(FacetManagerTest, GetAffiliationsAndBrandingServedFromCache) {
   fake_facet_manager_host()->set_fake_database_content(
       GetTestEquivalenceClassWithUpdateTime(Now()));
   AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
@@ -443,12 +445,12 @@
   CreateFacetManager();
   EXPECT_TRUE(facet_manager()->IsCachedDataFresh());
 
-  GetAffiliations(StrategyOnCacheMiss::FAIL);
+  GetAffiliationsAndBranding(StrategyOnCacheMiss::FAIL);
   ExpectConsumerSuccessCallback();
   EXPECT_TRUE(facet_manager()->CanBeDiscarded());
   ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
 
-  GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ExpectConsumerSuccessCallback();
   EXPECT_TRUE(facet_manager()->CanBeDiscarded());
   ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
@@ -461,10 +463,11 @@
   EXPECT_FALSE(main_task_runner()->HasPendingTask());
 }
 
-// On-demand GetAffiliations() requests should trigger a fetch if the cache has
-// already stale data, or no corresponding data whatsoever. Nothing should
-// happen once the newly fetched data expires.
-TEST_F(FacetManagerTest, OnDemandGetAffiliationsRequestTriggersFetch) {
+// On-demand GetAffiliationsAndBranding() requests should trigger a fetch if the
+// cache has already stale data, or no corresponding data whatsoever. Nothing
+// should happen once the newly fetched data expires.
+TEST_F(FacetManagerTest,
+       OnDemandGetAffiliationsAndBrandingRequestTriggersFetch) {
   for (const bool cache_initially_has_stale_data : kFalseTrue) {
     SCOPED_TRACE(cache_initially_has_stale_data);
 
@@ -479,7 +482,7 @@
     CreateFacetManager();
     EXPECT_FALSE(facet_manager()->IsCachedDataFresh());
 
-    GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+    GetAffiliationsAndBranding(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
     ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
     EXPECT_FALSE(facet_manager()->CanBeDiscarded());
     ASSERT_NO_FATAL_FAILURE(CompleteFetch());
@@ -488,12 +491,12 @@
     AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
     EXPECT_TRUE(facet_manager()->IsCachedDataFresh());
 
-    GetAffiliations(StrategyOnCacheMiss::FAIL);
+    GetAffiliationsAndBranding(StrategyOnCacheMiss::FAIL);
     ExpectConsumerSuccessCallback();
     EXPECT_TRUE(facet_manager()->CanBeDiscarded());
     ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
 
-    GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+    GetAffiliationsAndBranding(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
     ExpectConsumerSuccessCallback();
     EXPECT_TRUE(facet_manager()->CanBeDiscarded());
     ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
@@ -507,22 +510,24 @@
   }
 }
 
-TEST_F(FacetManagerTest, CachedOnlyGetAffiliationsFailsDueToStaleCache) {
+TEST_F(FacetManagerTest,
+       CachedOnlyGetAffiliationsAndBrandingFailsDueToStaleCache) {
   CreateFacetManager();
   EXPECT_FALSE(facet_manager()->IsCachedDataFresh());
 
-  GetAffiliations(StrategyOnCacheMiss::FAIL);
+  GetAffiliationsAndBranding(StrategyOnCacheMiss::FAIL);
   ExpectConsumerFailureCallback();
   ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
   EXPECT_TRUE(facet_manager()->CanBeDiscarded());
   EXPECT_FALSE(main_task_runner()->HasPendingTask());
 }
 
-TEST_F(FacetManagerTest, GetAffiliationsFailureCallbackInvokedOnDestruction) {
+TEST_F(FacetManagerTest,
+       GetAffiliationsAndBrandingFailureCallbackInvokedOnDestruction) {
   CreateFacetManager();
   EXPECT_FALSE(facet_manager()->IsCachedDataFresh());
 
-  GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
   EXPECT_FALSE(facet_manager()->CanBeDiscarded());
 
@@ -1452,7 +1457,7 @@
   CreateFacetManager();
   ASSERT_FALSE(facet_manager()->IsCachedDataFresh());
 
-  GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
   EXPECT_FALSE(facet_manager()->CanBeDiscarded());
   EXPECT_TRUE(facet_manager()->CanCachedDataBeDiscarded());
@@ -1464,7 +1469,7 @@
   CreateFacetManager();
   ASSERT_FALSE(facet_manager()->IsCachedDataFresh());
 
-  GetAffiliations(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+  GetAffiliationsAndBranding(StrategyOnCacheMiss::FETCH_OVER_NETWORK);
   ASSERT_NO_FATAL_FAILURE(ExpectFetchNeeded());
   ASSERT_NO_FATAL_FAILURE(CompleteFetch());
   ExpectConsumerSuccessCallback();
diff --git a/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h b/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h
index c597bc2f..d9945553 100644
--- a/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h
+++ b/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h
@@ -12,7 +12,7 @@
 
 namespace password_manager {
 
-// A mock consumer of AffiliationService::GetAffiliations().
+// A mock consumer of AffiliationService::GetAffiliationsAndBranding().
 class MockAffiliationConsumer {
  public:
   MockAffiliationConsumer();
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 217acff..41318159 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -370,6 +370,8 @@
     "background_fetch/background_fetch_cross_origin_filter.h",
     "background_fetch/background_fetch_data_manager.cc",
     "background_fetch/background_fetch_data_manager.h",
+    "background_fetch/background_fetch_delegate_proxy.cc",
+    "background_fetch/background_fetch_delegate_proxy.h",
     "background_fetch/background_fetch_event_dispatcher.cc",
     "background_fetch/background_fetch_event_dispatcher.h",
     "background_fetch/background_fetch_job_controller.cc",
diff --git a/content/browser/android/content_view_render_view.cc b/content/browser/android/content_view_render_view.cc
index 8c4d4d3c..4a5e9aa 100644
--- a/content/browser/android/content_view_render_view.cc
+++ b/content/browser/android/content_view_render_view.cc
@@ -112,6 +112,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     bool enabled) {
+  compositor_->SetRequiresAlphaChannel(enabled);
   compositor_->SetHasTransparentBackground(enabled);
   compositor_->SetNeedsComposite();
 }
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index 32bfb9f..90b1be1e3 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -12,7 +12,6 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/public/browser/blob_handle.h"
 #include "content/public/browser/browser_context.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/origin.h"
 
@@ -144,39 +143,12 @@
     const BackgroundFetchOptions& options) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("background_fetch_context", R"(
-        semantics {
-          sender: "Background Fetch API"
-          description:
-            "The Background Fetch API enables developers to upload or download "
-            "files on behalf of the user. Such fetches will yield a user "
-            "visible notification to inform the user of the operation, through "
-            "which it can be suspended, resumed and/or cancelled. The "
-            "developer retains control of the file once the fetch is "
-            "completed,  similar to XMLHttpRequest and other mechanisms for "
-            "fetching resources using JavaScript."
-          trigger:
-            "When the website uses the Background Fetch API to request "
-            "fetching a file and/or a list of files. This is a Web Platform "
-            "API for which no express user permission is required."
-          data:
-            "The request headers and data as set by the website's developer."
-          destination: WEBSITE
-        }
-        policy {
-          cookies_allowed: true
-          cookies_store: "user"
-          setting: "This feature cannot be disabled in settings."
-          policy_exception_justification: "Not implemented."
-        })");
   std::unique_ptr<BackgroundFetchJobController> controller =
       base::MakeUnique<BackgroundFetchJobController>(
           registration_id, options, data_manager_.get(), browser_context_,
           request_context_getter_,
           base::BindOnce(&BackgroundFetchContext::DidCompleteJob,
-                         weak_factory_.GetWeakPtr()),
-          traffic_annotation);
+                         weak_factory_.GetWeakPtr()));
 
   // TODO(peter): We should actually be able to use Background Fetch in layout
   // tests. That requires a download manager and a request context.
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
new file mode 100644
index 0000000..4963425a4
--- /dev/null
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -0,0 +1,307 @@
+// 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 "content/browser/background_fetch/background_fetch_delegate_proxy.h"
+
+#include "base/memory/ptr_util.h"
+#include "build/build_config.h"
+#include "content/browser/background_fetch/background_fetch_job_controller.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/download_item.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_url_parameters.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/path_utils.h"
+#include "base/files/file_path.h"
+#include "base/guid.h"
+#endif
+
+namespace content {
+
+#if defined(OS_ANDROID)
+namespace {
+
+// Prefix for files stored in the Chromium-internal download directory to
+// indicate files thta were fetched through Background Fetch.
+const char kBackgroundFetchFilePrefix[] = "BGFetch-";
+
+}  // namespace
+#endif  // defined(OS_ANDROID)
+
+// Internal functionality of the BackgroundFetchDelegateProxy that lives on the
+// UI thread, where all interaction with the download manager must happen.
+class BackgroundFetchDelegateProxy::Core : public DownloadItem::Observer {
+ public:
+  Core(const base::WeakPtr<BackgroundFetchDelegateProxy>& io_parent,
+       const BackgroundFetchRegistrationId& registration_id,
+       BrowserContext* browser_context,
+       scoped_refptr<net::URLRequestContextGetter> request_context)
+      : io_parent_(io_parent),
+        registration_id_(registration_id),
+        browser_context_(browser_context),
+        request_context_(std::move(request_context)),
+        weak_ptr_factory_(this) {
+    // Although the Core lives only on the UI thread, it is constructed on IO.
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  }
+
+  ~Core() final {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    for (const auto& pair : downloads_)
+      pair.first->RemoveObserver(this);
+  }
+
+  base::WeakPtr<Core> GetWeakPtrOnUI() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+  void StartRequest(
+      scoped_refptr<BackgroundFetchRequestInfo> request,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(request_context_);
+    DCHECK(request);
+
+    DownloadManager* download_manager =
+        BrowserContext::GetDownloadManager(browser_context_);
+    DCHECK(download_manager);
+
+    const ServiceWorkerFetchRequest& fetch_request = request->fetch_request();
+
+    std::unique_ptr<DownloadUrlParameters> download_parameters(
+        base::MakeUnique<DownloadUrlParameters>(
+            fetch_request.url, request_context_.get(), traffic_annotation));
+
+    // TODO(peter): The |download_parameters| should be populated with all the
+    // properties set in the |fetch_request| structure.
+
+    for (const auto& pair : fetch_request.headers)
+      download_parameters->add_request_header(pair.first, pair.second);
+
+    // Append the Origin header for requests whose CORS flag is set, or whose
+    // request method is not GET or HEAD. See section 3.1 of the standard:
+    // https://fetch.spec.whatwg.org/#origin-header
+    if (fetch_request.mode == FETCH_REQUEST_MODE_CORS ||
+        fetch_request.mode == FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT ||
+        (fetch_request.method != "GET" && fetch_request.method != "POST")) {
+      download_parameters->add_request_header(
+          "Origin", registration_id_.origin().Serialize());
+    }
+
+    // TODO(peter): Background Fetch responses should not end up in the user's
+    // download folder on any platform. Find an appropriate solution for desktop
+    // too. The Android internal directory is not scoped to a profile.
+
+    download_parameters->set_transient(true);
+
+#if defined(OS_ANDROID)
+    base::FilePath download_directory;
+    if (base::android::GetDownloadInternalDirectory(&download_directory)) {
+      download_parameters->set_file_path(download_directory.Append(
+          std::string(kBackgroundFetchFilePrefix) + base::GenerateGUID()));
+    }
+#endif  // defined(OS_ANDROID)
+
+    download_parameters->set_callback(base::Bind(&Core::DidStartRequest,
+                                                 weak_ptr_factory_.GetWeakPtr(),
+                                                 std::move(request)));
+
+    download_manager->DownloadUrl(std::move(download_parameters));
+  }
+
+  // DownloadItem::Observer overrides:
+  void OnDownloadUpdated(DownloadItem* download_item) override {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+    auto iter = downloads_.find(download_item);
+    DCHECK(iter != downloads_.end());
+
+    scoped_refptr<BackgroundFetchRequestInfo> request = iter->second;
+
+    switch (download_item->GetState()) {
+      case DownloadItem::DownloadState::COMPLETE:
+        request->PopulateResponseFromDownloadItemOnUI(download_item);
+        BrowserThread::PostTask(
+            BrowserThread::IO, FROM_HERE,
+            base::Bind(&BackgroundFetchRequestInfo::SetResponseDataPopulated,
+                       request));
+        download_item->RemoveObserver(this);
+
+        // Inform the host about |host| having completed.
+        BrowserThread::PostTask(
+            BrowserThread::IO, FROM_HERE,
+            base::Bind(&BackgroundFetchDelegateProxy::DidCompleteRequest,
+                       io_parent_, std::move(request)));
+
+        // Clear the local state for the |request|, it no longer is our concern.
+        downloads_.erase(iter);
+        break;
+      case DownloadItem::DownloadState::CANCELLED:
+        // TODO(harkness): Consider how we want to handle cancelled downloads.
+        break;
+      case DownloadItem::DownloadState::INTERRUPTED:
+        // TODO(harkness): Just update the notification that it is paused.
+        break;
+      case DownloadItem::DownloadState::IN_PROGRESS:
+        // TODO(harkness): If the download was previously paused, this should
+        // now unpause the notification.
+        break;
+      case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  void OnDownloadDestroyed(DownloadItem* download_item) override {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK_EQ(downloads_.count(download_item), 1u);
+    downloads_.erase(download_item);
+
+    download_item->RemoveObserver(this);
+  }
+
+ private:
+  // Called when the download manager has started the given |request|. The
+  // |download_item| continues to be owned by the download system. The
+  // |interrupt_reason| will indicate when a request could not be started.
+  void DidStartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
+                       DownloadItem* download_item,
+                       DownloadInterruptReason interrupt_reason) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK_EQ(interrupt_reason, DOWNLOAD_INTERRUPT_REASON_NONE);
+    DCHECK(download_item);
+
+    request->PopulateDownloadStateOnUI(download_item, interrupt_reason);
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&BackgroundFetchRequestInfo::SetDownloadStatePopulated,
+                   request));
+
+    // TODO(peter): The above two DCHECKs are assumptions our implementation
+    // currently makes, but are not fit for production. We need to handle such
+    // failures gracefully.
+
+    // Register for updates on the download's progress.
+    download_item->AddObserver(this);
+
+    // Inform the host about the |request| having started.
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&BackgroundFetchDelegateProxy::DidStartRequest, io_parent_,
+                   request, download_item->GetGuid()));
+
+    // Associate the |download_item| with the |request| so that we can retrieve
+    // it's information when further updates happen.
+    downloads_.insert(std::make_pair(download_item, std::move(request)));
+  }
+
+  // Weak reference to the BackgroundFetchJobController instance that owns us.
+  base::WeakPtr<BackgroundFetchDelegateProxy> io_parent_;
+
+  // The Background Fetch registration Id for which this request is being made.
+  BackgroundFetchRegistrationId registration_id_;
+
+  // The BrowserContext that owns the JobController, and thereby us.
+  BrowserContext* browser_context_;
+
+  // The URL request context to use when issuing the requests.
+  scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+  // Map from DownloadItem* to the request info for the in-progress downloads.
+  std::unordered_map<DownloadItem*, scoped_refptr<BackgroundFetchRequestInfo>>
+      downloads_;
+
+  base::WeakPtrFactory<Core> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(Core);
+};
+
+BackgroundFetchDelegateProxy::BackgroundFetchDelegateProxy(
+    BackgroundFetchJobController* job_controller,
+    const BackgroundFetchRegistrationId& registration_id,
+    BrowserContext* browser_context,
+    scoped_refptr<net::URLRequestContextGetter> request_context)
+    : job_controller_(job_controller),
+      traffic_annotation_(
+          net::DefineNetworkTrafficAnnotation("background_fetch_context", R"(
+            semantics {
+              sender: "Background Fetch API"
+              description:
+                "The Background Fetch API enables developers to upload or "
+                "download files on behalf of the user. Such fetches will yield "
+                "a user visible notification to inform the user of the "
+                "operation, through which it can be suspended, resumed and/or "
+                "cancelled. The developer retains control of the file once the "
+                "fetch is completed,  similar to XMLHttpRequest and other "
+                "mechanisms for fetching resources using JavaScript."
+              trigger:
+                "When the website uses the Background Fetch API to request "
+                "fetching a file and/or a list of files. This is a Web "
+                "Platform API for which no express user permission is required."
+              data:
+                "The request headers and data as set by the website's "
+                "developer."
+              destination: WEBSITE
+            }
+            policy {
+              cookies_allowed: true
+              cookies_store: "user"
+              setting: "This feature cannot be disabled in settings."
+              policy_exception_justification: "Not implemented."
+            })")),
+      weak_ptr_factory_(this) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  ui_core_.reset(new Core(weak_ptr_factory_.GetWeakPtr(), registration_id,
+                          browser_context, request_context));
+
+  // Get a WeakPtr over which we can talk to the |ui_core_|. Normally it
+  // would be unsafe to obtain a weak pointer on the IO thread from a
+  // factory that lives on the UI thread, but it's ok in this constructor
+  // since the Core can't be destroyed before this constructor finishes.
+  ui_core_ptr_ = ui_core_->GetWeakPtrOnUI();
+}
+
+BackgroundFetchDelegateProxy::~BackgroundFetchDelegateProxy() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+void BackgroundFetchDelegateProxy::StartRequest(
+    scoped_refptr<BackgroundFetchRequestInfo> request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&Core::StartRequest, ui_core_ptr_,
+                                     std::move(request), traffic_annotation_));
+}
+
+void BackgroundFetchDelegateProxy::UpdateUI(const std::string& title) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  // TODO(delphick): Update the user interface with |title|.
+}
+
+void BackgroundFetchDelegateProxy::Abort() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  // TODO(delphick): Abort all in-progress downloads.
+}
+
+void BackgroundFetchDelegateProxy::DidStartRequest(
+    scoped_refptr<BackgroundFetchRequestInfo> request,
+    const std::string& download_guid) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  job_controller_->DidStartRequest(request, download_guid);
+}
+
+void BackgroundFetchDelegateProxy::DidCompleteRequest(
+    scoped_refptr<BackgroundFetchRequestInfo> request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  job_controller_->DidCompleteRequest(request);
+}
+
+}  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.h b/content/browser/background_fetch/background_fetch_delegate_proxy.h
new file mode 100644
index 0000000..b0aebfa
--- /dev/null
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -0,0 +1,83 @@
+// 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 CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DELEGATE_PROXY_H_
+#define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DELEGATE_PROXY_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/background_fetch/background_fetch_registration_id.h"
+#include "content/browser/background_fetch/background_fetch_request_info.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace content {
+
+class BackgroundFetchJobController;
+class BrowserContext;
+
+// Proxy class for passing messages between BackgroundFetchJobController on the
+// IO thread to and BackgroundFetchDelegate on the UI thread.
+// TODO(delphick): Create BackgroundFetchDelegate.
+class BackgroundFetchDelegateProxy {
+ public:
+  BackgroundFetchDelegateProxy(
+      BackgroundFetchJobController* job_controller,
+      const BackgroundFetchRegistrationId& registration_id,
+      BrowserContext* browser_context,
+      scoped_refptr<net::URLRequestContextGetter> request_context);
+
+  ~BackgroundFetchDelegateProxy();
+
+  // Requests that the download manager start fetching |request|.
+  // Should only be called from the BackgroundFetchJobController (on the IO
+  // thread).
+  void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request);
+
+  // Updates the representation of this Background Fetch in the user interface
+  // to match the given |title|.
+  // Should only be called from the BackgroundFetchJobController (on the IO
+  // thread).
+  void UpdateUI(const std::string& title);
+
+  // Immediately aborts this Background Fetch by request of the developer.
+  // Should only be called from the BackgroundFetchJobController (on the IO
+  // thread).
+  void Abort();
+
+ private:
+  class Core;
+
+  // Called when the download manager has started the given |request|. The
+  // |download_item| continues to be owned by the download system. The
+  // |interrupt_reason| will indicate when a request could not be started.
+  // Should only be called from the BackgroundFetchDelegate (on the IO thread).
+  void DidStartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
+                       const std::string& download_guid);
+
+  // Called when the given |request| has been completed.
+  // Should only be called from the BackgroundFetchDelegate (on the IO thread).
+  void DidCompleteRequest(scoped_refptr<BackgroundFetchRequestInfo> request);
+
+  // Parent job controller that owns |this|.
+  BackgroundFetchJobController* const job_controller_;
+
+  std::unique_ptr<Core, BrowserThread::DeleteOnUIThread> ui_core_;
+  base::WeakPtr<Core> ui_core_ptr_;
+
+  // Traffic annotation for network request.
+  const net::NetworkTrafficAnnotationTag traffic_annotation_;
+
+  base::WeakPtrFactory<BackgroundFetchDelegateProxy> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundFetchDelegateProxy);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DELEGATE_PROXY_H_
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index c8a75672..9165857 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -4,256 +4,27 @@
 
 #include "content/browser/background_fetch/background_fetch_job_controller.h"
 
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "content/browser/background_fetch/background_fetch_constants.h"
 #include "content/browser/background_fetch/background_fetch_data_manager.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/download_interrupt_reasons.h"
-#include "content/public/browser/download_manager.h"
 #include "net/url_request/url_request_context_getter.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/path_utils.h"
-#include "base/files/file_path.h"
-#include "base/guid.h"
-#endif
-
 namespace content {
 
-#if defined(OS_ANDROID)
-namespace {
-
-// Prefix for files stored in the Chromium-internal download directory to
-// indicate files thta were fetched through Background Fetch.
-const char kBackgroundFetchFilePrefix[] = "BGFetch-";
-
-}  // namespace
-#endif  // defined(OS_ANDROID)
-
-// Internal functionality of the BackgroundFetchJobController that lives on the
-// UI thread, where all interaction with the download manager must happen.
-class BackgroundFetchJobController::Core : public DownloadItem::Observer {
- public:
-  Core(const base::WeakPtr<BackgroundFetchJobController>& io_parent,
-       const BackgroundFetchRegistrationId& registration_id,
-       BrowserContext* browser_context,
-       scoped_refptr<net::URLRequestContextGetter> request_context)
-      : io_parent_(io_parent),
-        registration_id_(registration_id),
-        browser_context_(browser_context),
-        request_context_(std::move(request_context)),
-        weak_ptr_factory_(this) {
-    // Although the Core lives only on the UI thread, it is constructed on IO.
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  }
-
-  ~Core() final {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    for (const auto& pair : downloads_)
-      pair.first->RemoveObserver(this);
-  }
-
-  // Returns a weak pointer that can be used to talk to |this|. Must only be
-  // called on the UI thread, unless the Core is guaranteed not to be destroyed
-  // in parallel with this call.
-  base::WeakPtr<Core> GetWeakPtrOnUI() {
-    return weak_ptr_factory_.GetWeakPtr();
-  }
-
-  // Starts fetching the |request| with the download manager.
-  void StartRequest(
-      scoped_refptr<BackgroundFetchRequestInfo> request,
-      const net::NetworkTrafficAnnotationTag& traffic_annotation) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    DCHECK(request_context_);
-    DCHECK(request);
-
-    DownloadManager* download_manager =
-        BrowserContext::GetDownloadManager(browser_context_);
-    DCHECK(download_manager);
-
-    const ServiceWorkerFetchRequest& fetch_request = request->fetch_request();
-
-    std::unique_ptr<DownloadUrlParameters> download_parameters(
-        base::MakeUnique<DownloadUrlParameters>(
-            fetch_request.url, request_context_.get(), traffic_annotation));
-
-    // TODO(peter): The |download_parameters| should be populated with all the
-    // properties set in the |fetch_request| structure.
-
-    for (const auto& pair : fetch_request.headers)
-      download_parameters->add_request_header(pair.first, pair.second);
-
-    // Append the Origin header for requests whose CORS flag is set, or whose
-    // request method is not GET or HEAD. See section 3.1 of the standard:
-    // https://fetch.spec.whatwg.org/#origin-header
-    if (fetch_request.mode == FETCH_REQUEST_MODE_CORS ||
-        fetch_request.mode == FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT ||
-        (fetch_request.method != "GET" && fetch_request.method != "POST")) {
-      download_parameters->add_request_header(
-          "Origin", registration_id_.origin().Serialize());
-    }
-
-    // TODO(peter): Background Fetch responses should not end up in the user's
-    // download folder on any platform. Find an appropriate solution for desktop
-    // too. The Android internal directory is not scoped to a profile.
-
-    download_parameters->set_transient(true);
-
-#if defined(OS_ANDROID)
-    base::FilePath download_directory;
-    if (base::android::GetDownloadInternalDirectory(&download_directory)) {
-      download_parameters->set_file_path(download_directory.Append(
-          std::string(kBackgroundFetchFilePrefix) + base::GenerateGUID()));
-    }
-#endif  // defined(OS_ANDROID)
-
-    download_parameters->set_callback(base::Bind(&Core::DidStartRequest,
-                                                 weak_ptr_factory_.GetWeakPtr(),
-                                                 std::move(request)));
-
-    download_manager->DownloadUrl(std::move(download_parameters));
-  }
-
-  // DownloadItem::Observer overrides:
-  void OnDownloadUpdated(DownloadItem* download_item) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-    auto iter = downloads_.find(download_item);
-    DCHECK(iter != downloads_.end());
-
-    scoped_refptr<BackgroundFetchRequestInfo> request = iter->second;
-
-    switch (download_item->GetState()) {
-      case DownloadItem::DownloadState::COMPLETE:
-        request->PopulateResponseFromDownloadItemOnUI(download_item);
-        BrowserThread::PostTask(
-            BrowserThread::IO, FROM_HERE,
-            base::Bind(&BackgroundFetchRequestInfo::SetResponseDataPopulated,
-                       request));
-        download_item->RemoveObserver(this);
-
-        // Inform the host about |host| having completed.
-        BrowserThread::PostTask(
-            BrowserThread::IO, FROM_HERE,
-            base::Bind(&BackgroundFetchJobController::DidCompleteRequest,
-                       io_parent_, std::move(request)));
-
-        // Clear the local state for the |request|, it no longer is our concern.
-        downloads_.erase(iter);
-        break;
-      case DownloadItem::DownloadState::CANCELLED:
-        // TODO(harkness): Consider how we want to handle cancelled downloads.
-        break;
-      case DownloadItem::DownloadState::INTERRUPTED:
-        // TODO(harkness): Just update the notification that it is paused.
-        break;
-      case DownloadItem::DownloadState::IN_PROGRESS:
-        // TODO(harkness): If the download was previously paused, this should
-        // now unpause the notification.
-        break;
-      case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  void OnDownloadDestroyed(DownloadItem* download_item) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    DCHECK_EQ(downloads_.count(download_item), 1u);
-    downloads_.erase(download_item);
-
-    download_item->RemoveObserver(this);
-  }
-
- private:
-  // Called when the download manager has started the given |request|. The
-  // |download_item| continues to be owned by the download system. The
-  // |interrupt_reason| will indicate when a request could not be started.
-  void DidStartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
-                       DownloadItem* download_item,
-                       DownloadInterruptReason interrupt_reason) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    DCHECK_EQ(interrupt_reason, DOWNLOAD_INTERRUPT_REASON_NONE);
-    DCHECK(download_item);
-
-    request->PopulateDownloadStateOnUI(download_item, interrupt_reason);
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&BackgroundFetchRequestInfo::SetDownloadStatePopulated,
-                   request));
-
-    // TODO(peter): The above two DCHECKs are assumptions our implementation
-    // currently makes, but are not fit for production. We need to handle such
-    // failures gracefully.
-
-    // Register for updates on the download's progress.
-    download_item->AddObserver(this);
-
-    // Inform the host about the |request| having started.
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&BackgroundFetchJobController::DidStartRequest, io_parent_,
-                   request, download_item->GetGuid()));
-
-    // Associate the |download_item| with the |request| so that we can retrieve
-    // it's information when further updates happen.
-    downloads_.insert(std::make_pair(download_item, std::move(request)));
-  }
-
-  // Weak reference to the BackgroundFetchJobController instance that owns us.
-  base::WeakPtr<BackgroundFetchJobController> io_parent_;
-
-  // The Background Fetch registration Id for which this request is being made.
-  BackgroundFetchRegistrationId registration_id_;
-
-  // The BrowserContext that owns the JobController, and thereby us.
-  BrowserContext* browser_context_;
-
-  // The URL request context to use when issuing the requests.
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
-
-  // Map from DownloadItem* to the request info for the in-progress downloads.
-  std::unordered_map<DownloadItem*, scoped_refptr<BackgroundFetchRequestInfo>>
-      downloads_;
-
-  base::WeakPtrFactory<Core> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(Core);
-};
-
 BackgroundFetchJobController::BackgroundFetchJobController(
     const BackgroundFetchRegistrationId& registration_id,
     const BackgroundFetchOptions& options,
     BackgroundFetchDataManager* data_manager,
     BrowserContext* browser_context,
     scoped_refptr<net::URLRequestContextGetter> request_context,
-    CompletedCallback completed_callback,
-    const net::NetworkTrafficAnnotationTag& traffic_annotation)
+    CompletedCallback completed_callback)
     : registration_id_(registration_id),
       options_(options),
       data_manager_(data_manager),
+      delegate_proxy_(this, registration_id, browser_context, request_context),
       completed_callback_(std::move(completed_callback)),
-      traffic_annotation_(traffic_annotation),
       weak_ptr_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  // Create the core, containing the internal functionality that will have to
-  // be run on the UI thread. It will respond to this class with a weak pointer.
-  ui_core_.reset(new Core(weak_ptr_factory_.GetWeakPtr(), registration_id,
-                          browser_context, std::move(request_context)));
-
-  // Get a WeakPtr over which we can talk to the |ui_core_|. Normally it would
-  // be unsafe to obtain a weak pointer on the IO thread from a factory that
-  // lives on the UI thread, but it's ok in this constructor since the Core
-  // can't be destroyed before this constructor finishes.
-  ui_core_ptr_ = ui_core_->GetWeakPtrOnUI();
 }
 
 BackgroundFetchJobController::~BackgroundFetchJobController() {
@@ -287,9 +58,8 @@
     // none left.
     return;
   }
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                          base::Bind(&Core::StartRequest, ui_core_ptr_,
-                                     std::move(request), traffic_annotation_));
+
+  delegate_proxy_.StartRequest(request);
 }
 
 void BackgroundFetchJobController::DidStartRequest(
@@ -335,7 +105,7 @@
 void BackgroundFetchJobController::UpdateUI(const std::string& title) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  // TODO(harkness): Update the user interface with |title|.
+  delegate_proxy_.UpdateUI(title);
 }
 
 void BackgroundFetchJobController::Abort() {
@@ -350,7 +120,7 @@
       return;  // Ignore attempt to abort after completion/abort.
   }
 
-  // TODO(harkness): Abort all in-progress downloads.
+  delegate_proxy_.Abort();
 
   state_ = State::ABORTED;
   // Inform the owner of the controller about the job having aborted.
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h
index a944352b0..f9867e7 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -12,12 +12,12 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "content/browser/background_fetch/background_fetch_delegate_proxy.h"
 #include "content/browser/background_fetch/background_fetch_registration_id.h"
 #include "content/browser/background_fetch/background_fetch_request_info.h"
 #include "content/common/background_fetch/background_fetch_types.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class URLRequestContextGetter;
@@ -44,8 +44,7 @@
       BackgroundFetchDataManager* data_manager,
       BrowserContext* browser_context,
       scoped_refptr<net::URLRequestContextGetter> request_context,
-      CompletedCallback completed_callback,
-      const net::NetworkTrafficAnnotationTag& traffic_annotation);
+      CompletedCallback completed_callback);
   ~BackgroundFetchJobController();
 
   // Starts fetching the first few requests. The controller will continue to
@@ -70,12 +69,6 @@
   // Returns the options with which this job is fetching data.
   const BackgroundFetchOptions& options() const { return options_; }
 
- private:
-  class Core;
-
-  // Requests the download manager to start fetching |request|.
-  void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request);
-
   // Called when the given |request| has started fetching, after having been
   // assigned the |download_guid| by the download system.
   void DidStartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
@@ -84,6 +77,10 @@
   // Called when the given |request| has been completed.
   void DidCompleteRequest(scoped_refptr<BackgroundFetchRequestInfo> request);
 
+ private:
+  // Requests the download manager to start fetching |request|.
+  void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request);
+
   // Called when a completed download has been marked as such in DataManager.
   void DidMarkRequestCompleted(bool has_pending_or_active_requests);
 
@@ -96,20 +93,17 @@
   // The current state of this Job Controller.
   State state_ = State::INITIALIZED;
 
-  // Inner core of this job controller which lives on the UI thread.
-  std::unique_ptr<Core, BrowserThread::DeleteOnUIThread> ui_core_;
-  base::WeakPtr<Core> ui_core_ptr_;
-
   // The DataManager's lifetime is controlled by the BackgroundFetchContext and
   // will be kept alive until after the JobController is destroyed.
   BackgroundFetchDataManager* data_manager_;
 
+  // Proxy for interacting with the BackgroundFetchDelegate across thread
+  // boundaries.
+  BackgroundFetchDelegateProxy delegate_proxy_;
+
   // Callback for when all fetches have been completed.
   CompletedCallback completed_callback_;
 
-  // Traffic annotation for network request.
-  const net::NetworkTrafficAnnotationTag traffic_annotation_;
-
   base::WeakPtrFactory<BackgroundFetchJobController> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchJobController);
diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
index b2e3e3e..c73cae1a 100644
--- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -20,7 +20,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/fake_download_item.h"
 #include "content/public/test/mock_download_manager.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -87,8 +86,7 @@
         browser_context(),
         make_scoped_refptr(storage_partition->GetURLRequestContext()),
         base::BindOnce(&BackgroundFetchJobControllerTest::DidCompleteJob,
-                       base::Unretained(this)),
-        TRAFFIC_ANNOTATION_FOR_TESTS);
+                       base::Unretained(this)));
   }
 
  protected:
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 1728928c..a2c016b 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -170,7 +170,7 @@
 
 gpu::gles2::ContextCreationAttribHelper GetCompositorContextAttributes(
     const gfx::ColorSpace& display_color_space,
-    bool has_transparent_background) {
+    bool requires_alpha_channel) {
   // This is used for the browser compositor (offscreen) and for the display
   // compositor (onscreen), so ask for capabilities needed by either one.
   // The default framebuffer for an offscreen context is not used, so it does
@@ -197,7 +197,7 @@
     }
   }
 
-  if (has_transparent_background) {
+  if (requires_alpha_channel) {
     attributes.alpha_size = 8;
   } else if (base::SysInfo::AmountOfPhysicalMemoryMB() <= 512) {
     // In this case we prefer to use RGB565 format instead of RGBA8888 if
@@ -571,7 +571,6 @@
   host_->SetRootLayer(root_window_->GetLayer());
   host_->SetFrameSinkId(frame_sink_id_);
   host_->SetViewportSize(size_);
-  SetHasTransparentBackground(false);
   host_->SetDeviceScaleFactor(1);
 
   if (needs_animate_)
@@ -618,19 +617,21 @@
 }
 
 void CompositorImpl::SetHasTransparentBackground(bool transparent) {
-  has_transparent_background_ = transparent;
-  if (host_) {
-    host_->set_has_transparent_background(transparent);
+  DCHECK(host_);
+  host_->set_has_transparent_background(transparent);
 
-    // Give a delay in setting the background color to avoid the color for
-    // the normal mode (white) affecting the UI transition.
-    base::ThreadTaskRunnerHandle::Get().get()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&CompositorImpl::SetBackgroundColor,
-                   weak_factory_.GetWeakPtr(),
-                   transparent ? SK_ColorBLACK : SK_ColorWHITE),
-        base::TimeDelta::FromMilliseconds(500));
-  }
+  // Give a delay in setting the background color to avoid the color for
+  // the normal mode (white) affecting the UI transition.
+  base::ThreadTaskRunnerHandle::Get().get()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&CompositorImpl::SetBackgroundColor,
+                 weak_factory_.GetWeakPtr(),
+                 transparent ? SK_ColorBLACK : SK_ColorWHITE),
+      base::TimeDelta::FromMilliseconds(500));
+}
+
+void CompositorImpl::SetRequiresAlphaChannel(bool flag) {
+  requires_alpha_channel_ = flag;
 }
 
 void CompositorImpl::SetBackgroundColor(int color) {
@@ -778,7 +779,7 @@
           automatic_flushes, support_locking,
           GetCompositorContextSharedMemoryLimits(root_window_),
           GetCompositorContextAttributes(display_color_space_,
-                                         has_transparent_background_),
+                                         requires_alpha_channel_),
           shared_context,
           ui::command_buffer_metrics::DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT);
   if (!context_provider->BindToCurrentThread()) {
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index b55dc2a..dc7f8b0 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -79,6 +79,7 @@
   void SetSurface(jobject surface) override;
   void SetWindowBounds(const gfx::Size& size) override;
   void SetHasTransparentBackground(bool flag) override;
+  void SetRequiresAlphaChannel(bool flag) override;
   void SetNeedsComposite() override;
   ui::UIResourceProvider& GetUIResourceProvider() override;
   ui::ResourceManager& GetResourceManager() override;
@@ -158,7 +159,7 @@
 
   gfx::ColorSpace display_color_space_;
   gfx::Size size_;
-  bool has_transparent_background_;
+  bool requires_alpha_channel_ = false;
 
   ANativeWindow* window_;
   gpu::SurfaceHandle surface_handle_;
diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h
index 618bbf5..0c8bdaf 100644
--- a/content/public/browser/android/compositor.h
+++ b/content/public/browser/android/compositor.h
@@ -74,6 +74,11 @@
   // Tells the view tree to assume a transparent background when rendering.
   virtual void SetHasTransparentBackground(bool flag) = 0;
 
+  // Tells the compositor to allocate an alpha channel.  This won't take effect
+  // until the compositor selects a new egl config, usually when the underlying
+  // Android Surface changes format.
+  virtual void SetRequiresAlphaChannel(bool flag) = 0;
+
   // Request layout and draw. You only need to call this if you need to trigger
   // Composite *without* having modified the layer tree.
   virtual void SetNeedsComposite() = 0;
diff --git a/content/public/test/test_browser_thread_bundle.cc b/content/public/test/test_browser_thread_bundle.cc
index 10f5e578..bf3737da 100644
--- a/content/public/test/test_browser_thread_bundle.cc
+++ b/content/public/test/test_browser_thread_bundle.cc
@@ -63,20 +63,28 @@
   ui_thread_->Stop();
   base::RunLoop().RunUntilIdle();
 
-  // This is required to ensure we run all remaining tasks in an atomic step
-  // (instead of ~ScopedAsyncTaskScheduler() followed by another
-  // RunLoop().RunUntilIdle()). Otherwise If a pending task in
-  // |scoped_async_task_scheduler_| posts to |message_loop_|, that task can then
-  // post back to |scoped_async_task_scheduler_| after the former was destroyed.
-  // This is a bit different than production where the main thread is not
-  // flushed after it's done running but this approach is preferred in unit
-  // tests as running more tasks can merely uncover more issues (e.g. if a bad
-  // tasks is posted but never blocked upon it could make a test flaky whereas
-  // by flushing we guarantee it will blow up).
-  RunAllBlockingPoolTasksUntilIdle();
+  // Skip the following step when TaskScheduler isn't managed by this
+  // TestBrowserThreadBundle, otherwise it can hang (e.g.
+  // RunAllBlockingPoolTasksUntilIdle() hangs when the TaskScheduler is managed
+  // by a ScopedTaskEnvironment with ExecutionMode::QUEUED). This is fine as (1)
+  // it's rare and (2) it mimics production where BrowserThreads are shutdown
+  // before TaskScheduler.
+  if (scoped_async_task_scheduler_) {
+    // This is required to ensure we run all remaining tasks in an atomic step
+    // (instead of ~ScopedAsyncTaskScheduler() followed by another
+    // RunLoop().RunUntilIdle()). Otherwise If a pending task in
+    // |scoped_async_task_scheduler_| posts to |message_loop_|, that task can
+    // then post back to |scoped_async_task_scheduler_| after the former was
+    // destroyed. This is a bit different than production where the main thread
+    // is not flushed after it's done running but this approach is preferred in
+    // unit tests as running more tasks can merely uncover more issues (e.g. if
+    // a bad tasks is posted but never blocked upon it could make a test flaky
+    // whereas by flushing we guarantee it will blow up).
+    RunAllBlockingPoolTasksUntilIdle();
 
-  scoped_async_task_scheduler_.reset();
-  CHECK(base::MessageLoop::current()->IsIdleForTesting());
+    scoped_async_task_scheduler_.reset();
+    CHECK(base::MessageLoop::current()->IsIdleForTesting());
+  }
 
   // |message_loop_| needs to explicitly go away before fake threads in order
   // for DestructionObservers hooked to |message_loop_| to be able to invoke
diff --git a/content/public/test/test_browser_thread_bundle_unittest.cc b/content/public/test/test_browser_thread_bundle_unittest.cc
index 85d9244..b403225 100644
--- a/content/public/test/test_browser_thread_bundle_unittest.cc
+++ b/content/public/test/test_browser_thread_bundle_unittest.cc
@@ -4,16 +4,42 @@
 
 #include "content/public/test/test_browser_thread_bundle.h"
 
+#include "base/bind_helpers.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/test/scoped_task_environment.h"
+#include "content/public/browser/browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::test::ScopedTaskEnvironment;
+
 namespace content {
 
-TEST(TestBrowserThreadBundle, ScopedTaskEnvironmentAndTestBrowserThreadBundle) {
-  base::test::ScopedTaskEnvironment scoped_task_environment(
-      base::test::ScopedTaskEnvironment::MainThreadType::UI);
+TEST(TestBrowserThreadBundleTest,
+     ScopedTaskEnvironmentAndTestBrowserThreadBundle) {
+  ScopedTaskEnvironment scoped_task_environment(
+      ScopedTaskEnvironment::MainThreadType::UI);
   TestBrowserThreadBundle test_browser_thread_bundle;
+  base::PostTaskAndReply(
+      FROM_HERE, base::BindOnce(&base::DoNothing),
+      base::BindOnce([]() { DCHECK_CURRENTLY_ON(BrowserThread::UI); }));
+  scoped_task_environment.RunUntilIdle();
+}
+
+// Regression test to verify that ~TestBrowserThreadBundle() doesn't hang when
+// the TaskScheduler is owned by a QUEUED ScopedTaskEnvironment with pending
+// tasks.
+TEST(TestBrowserThreadBundleTest,
+     QueuedScopedTaskEnvironmentAndTestBrowserThreadBundle) {
+  ScopedTaskEnvironment queued_scoped_task_environment(
+      ScopedTaskEnvironment::MainThreadType::UI,
+      ScopedTaskEnvironment::ExecutionMode::QUEUED);
+  base::PostTask(FROM_HERE, base::BindOnce(&base::DoNothing));
+
+  {
+    TestBrowserThreadBundle test_browser_thread_bundle;
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  }  // Would hang here prior to fix.
 }
 
 TEST(TestBrowserThreadBundleTest, MessageLoopTypeMismatch) {
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index 6d42912..3644c11 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -118,6 +118,7 @@
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui:ui_internal",
     "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/main",
     "//ios/chrome/common/app_group:main_app",
     "//ios/net",
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index d36f0ff..9d83c2a 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -39,6 +39,7 @@
 #import "ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.h"
 #include "ios/chrome/browser/ui/background_generator.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/main/browser_view_information.h"
 #include "ios/net/cookies/cookie_store_ios.h"
 #include "ios/net/cookies/system_cookie_util.h"
@@ -356,7 +357,11 @@
                                                  browserViewInformation]];
   } else if (_shouldOpenNTPTabOnActive &&
              ![tabSwitcher openNewTabFromTabSwitcher]) {
-    [[[_browserLauncher browserViewInformation] currentBVC] newTab:nil];
+    BrowserViewController* bvc =
+        [[_browserLauncher browserViewInformation] currentBVC];
+    BOOL incognito = bvc == [[_browserLauncher browserViewInformation] otrBVC];
+    [bvc.dispatcher
+        openNewTab:[OpenNewTabCommand commandWithIncognito:incognito]];
   }
   _shouldOpenNTPTabOnActive = NO;
 
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm
index 15de111c..cfe1e128 100644
--- a/ios/chrome/app/application_delegate/app_state_unittest.mm
+++ b/ios/chrome/app/application_delegate/app_state_unittest.mm
@@ -663,12 +663,16 @@
   id mainTabModel = [OCMockObject mockForClass:[TabModel class]];
   [[mainTabModel expect] resetSessionMetrics];
 
+  id dispatcher = [OCMockObject mockForProtocol:@protocol(BrowserCommands)];
+  [[dispatcher expect] openNewTab:[OCMArg any]];
+
   id currentBVC = [OCMockObject mockForClass:[BrowserViewController class]];
-  [[currentBVC expect] newTab:nil];
   stubNullBrowserState(currentBVC);
+  [[[currentBVC stub] andReturn:dispatcher] dispatcher];
 
   [[[browserViewInformation stub] andReturn:mainTabModel] mainTabModel];
   [[[browserViewInformation stub] andReturn:currentBVC] currentBVC];
+  [[[browserViewInformation stub] andReturn:nil] otrBVC];
 
   // TabSwitcher.
   id tabSwitcher = [OCMockObject mockForProtocol:@protocol(TabSwitching)];
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 6e06305..b511fa6 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -106,6 +106,7 @@
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/contextual_search/contextual_search_metrics.h"
@@ -1253,7 +1254,9 @@
   if (_tabSwitcherIsActive)
     [self dismissTabSwitcherWithoutAnimationInModel:self.mainTabModel];
   if (firstRun || [self shouldOpenNTPTabOnActivationOfTabModel:tabModel]) {
-    [self.currentBVC newTab:nil];
+    OpenNewTabCommand* command = [OpenNewTabCommand
+        commandWithIncognito:(self.currentBVC == self.otrBVC)];
+    [self.currentBVC.dispatcher openNewTab:command];
   }
 
   if (firstRun) {
@@ -1373,18 +1376,22 @@
                            completion:nil];
 }
 
+#pragma mark - ApplicationCommands
+
+- (void)switchModesAndOpenNewTab:(OpenNewTabCommand*)command {
+  BrowserViewController* bvc = command.incognito ? self.otrBVC : self.mainBVC;
+  DCHECK(bvc);
+  [bvc expectNewForegroundTab];
+  self.currentBVC = bvc;
+  [self.currentBVC.dispatcher openNewTab:command];
+}
+
 #pragma mark - chromeExecuteCommand
 
 - (IBAction)chromeExecuteCommand:(id)sender {
   NSInteger command = [sender tag];
 
   switch (command) {
-    case IDC_NEW_TAB:
-      [self createNewTabInBVC:self.mainBVC sender:sender];
-      break;
-    case IDC_NEW_INCOGNITO_TAB:
-      [self createNewTabInBVC:self.otrBVC sender:sender];
-      break;
     case IDC_OPEN_URL:
       [self openUrl:base::mac::ObjCCast<OpenUrlCommand>(sender)];
       break;
@@ -1683,14 +1690,6 @@
   [self switchGlobalStateToMode:mode];
 }
 
-// Set |bvc| as the current BVC and then creates a new tab.
-- (void)createNewTabInBVC:(BrowserViewController*)bvc sender:(id)sender {
-  DCHECK(bvc);
-  [bvc expectNewForegroundTab];
-  self.currentBVC = bvc;
-  [self.currentBVC newTab:sender];
-}
-
 - (void)displayCurrentBVC {
   self.mainViewController.activeViewController = self.currentBVC;
 }
@@ -1726,10 +1725,11 @@
   if (!_tabSwitcherController) {
     if (IsIPadIdiom()) {
       _tabSwitcherController = [[TabSwitcherController alloc]
-          initWithBrowserState:_mainBrowserState
-                  mainTabModel:self.mainTabModel
-                   otrTabModel:self.otrTabModel
-                activeTabModel:self.currentTabModel];
+                initWithBrowserState:_mainBrowserState
+                        mainTabModel:self.mainTabModel
+                         otrTabModel:self.otrTabModel
+                      activeTabModel:self.currentTabModel
+          applicationCommandEndpoint:self];
     } else {
       _tabSwitcherController =
           [[StackViewController alloc] initWithMainTabModel:self.mainTabModel
@@ -2437,7 +2437,8 @@
 - (void)closeSettingsAndOpenNewIncognitoTab {
   [self closeSettingsAnimated:NO
                    completion:^{
-                     [self createNewTabInBVC:self.otrBVC sender:nil];
+                     [self switchModesAndOpenNewTab:[OpenNewTabCommand
+                                                        incognitoTabCommand]];
                    }];
 }
 
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
index 7d71d326e..ec1f7fa4 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
@@ -33,7 +33,7 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
@@ -346,8 +346,7 @@
                    didTriggerAction:(OverscrollAction)action {
   switch (action) {
     case OverscrollAction::NEW_TAB: {
-      NewTabCommand* command = [[NewTabCommand alloc] initWithIncognito:NO];
-      [self.suggestionsViewController chromeExecuteCommand:command];
+      [_dispatcher openNewTab:[OpenNewTabCommand command]];
     } break;
     case OverscrollAction::CLOSE_TAB: {
       [_dispatcher closeCurrentTab];
diff --git a/ios/chrome/browser/tabs/tab.h b/ios/chrome/browser/tabs/tab.h
index a768a15..8bc94fba 100644
--- a/ios/chrome/browser/tabs/tab.h
+++ b/ios/chrome/browser/tabs/tab.h
@@ -17,8 +17,10 @@
 #import "ios/web/public/web_state/ui/crw_web_delegate.h"
 #include "ui/base/page_transition_types.h"
 
+@protocol ApplicationCommands;
 @class AutofillController;
 @class AutoReloadBridge;
+@protocol BrowserCommands;
 @class CastController;
 @class CRWWebController;
 @class ExternalAppLauncher;
@@ -161,6 +163,10 @@
 // |YES| if the tab has finished loading.
 @property(nonatomic, readonly) BOOL loadFinished;
 
+// Dispatcher that the tab can use to send commands. This should be set
+// when other delegates are set.
+@property(nonatomic, weak) id<ApplicationCommands, BrowserCommands> dispatcher;
+
 // Creates a new Tab with the given WebState.
 - (instancetype)initWithWebState:(web::WebState*)webState;
 
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 6a75c95..e2a51f6e 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -83,8 +83,10 @@
 #include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/u2f/u2f_controller.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/downloads/download_manager_controller.h"
@@ -438,6 +440,7 @@
 @synthesize tabSnapshottingDelegate = tabSnapshottingDelegate_;
 @synthesize tabHeadersDelegate = tabHeadersDelegate_;
 @synthesize fullScreenControllerDelegate = fullScreenControllerDelegate_;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithWebState:(web::WebState*)webState {
   DCHECK(webState);
@@ -1775,9 +1778,7 @@
             appendTo:kLastTab];
     [self.view chromeExecuteCommand:command];
   } else {
-    GenericChromeCommand* command =
-        [[GenericChromeCommand alloc] initWithTag:IDC_NEW_INCOGNITO_TAB];
-    [self.view chromeExecuteCommand:command];
+    [self.dispatcher openNewTab:[OpenNewTabCommand command]];
   }
 }
 
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
index 3478315..005c837d 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
@@ -17,14 +17,6 @@
 namespace ios {
 class ChromeBrowserState;
 
-// Enums to choose which histograms is used to record the user actions.
-enum class SigninPromoViewHistograms {
-  // No histograms.
-  None,
-  // Histograms: MobileSignInPromo.BookmarkManager.*.
-  Bookmarks,
-};
-
 // Enums for the sign-in promo view state.
 enum class SigninPromoViewState {
   // None of the buttons has been used yet.
@@ -53,17 +45,6 @@
 // contains nil.
 @property(nonatomic, readonly, strong) ChromeIdentity* defaultIdentity;
 
-// Access point used to send user action metrics.
-@property(nonatomic) signin_metrics::AccessPoint accessPoint;
-
-// Preference key to count how many time the sign-in promo view is seen. The
-// value should point to static storage.
-@property(nonatomic) const char* displayedCountPreferenceKey;
-// Preference key, set to true when the sign-in promo view is seen too much. The
-// value should point to static storage.
-@property(nonatomic) const char* alreadySeenSigninViewPreferenceKey;
-// Histograms to use for the user actions.
-@property(nonatomic) ios::SigninPromoViewHistograms histograms;
 // Sign-in promo view state.
 @property(nonatomic) ios::SigninPromoViewState signinPromoViewState;
 
@@ -71,7 +52,11 @@
 - (instancetype)init NS_UNAVAILABLE;
 
 // Initialises with browser state.
+// * |browserState| is the current browser state.
+// * |accessPoint| only ACCESS_POINT_SETTINGS, ACCESS_POINT_BOOKMARK_MANAGER,
+// ACCESS_POINT_RECENT_TABS, ACCESS_POINT_TAB_SWITCHER are supported.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
+                         accessPoint:(signin_metrics::AccessPoint)accessPoint
     NS_DESIGNATED_INITIALIZER;
 
 - (SigninPromoViewConfigurator*)createConfigurator;
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
index 47c59e6..8b2f647 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -34,6 +34,20 @@
 namespace {
 const int kAutomaticSigninPromoViewDismissCount = 20;
 
+#if DCHECK_IS_ON()
+bool IsSupportedAccessPoint(signin_metrics::AccessPoint access_point) {
+  switch (access_point) {
+    case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS:
+    case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+    case signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // DCHECK_IS_ON()
+
 void RecordSigninUserActionForAccessPoint(
     signin_metrics::AccessPoint access_point) {
   switch (access_point) {
@@ -121,6 +135,56 @@
       break;
   }
 }
+
+void RecordImpressionsTilSigninButtonsHistogramForAccessPoint(
+    signin_metrics::AccessPoint access_point,
+    int displayed_count) {
+  DCHECK_EQ(signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER,
+            access_point);
+  UMA_HISTOGRAM_COUNTS_100(
+      "MobileSignInPromo.BookmarkManager.ImpressionsTilSigninButtons",
+      displayed_count);
+}
+
+void RecordImpressionsTilDismissHistogramForAccessPoint(
+    signin_metrics::AccessPoint access_point,
+    int displayed_count) {
+  DCHECK_EQ(signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER,
+            access_point);
+  UMA_HISTOGRAM_COUNTS_100(
+      "MobileSignInPromo.BookmarkManager.ImpressionsTilDismiss",
+      displayed_count);
+}
+
+void RecordImpressionsTilXButtonHistogramForAccessPoint(
+    signin_metrics::AccessPoint access_point,
+    int displayed_count) {
+  DCHECK_EQ(signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER,
+            access_point);
+  UMA_HISTOGRAM_COUNTS_100(
+      "MobileSignInPromo.BookmarkManager.ImpressionsTilXButton",
+      displayed_count);
+}
+
+const char* DisplayedCountPreferenceKey(
+    signin_metrics::AccessPoint access_point) {
+  switch (access_point) {
+    case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+      return prefs::kIosBookmarkSigninPromoDisplayedCount;
+    default:
+      return nullptr;
+  }
+}
+
+const char* AlreadySeenSigninViewPreferenceKey(
+    signin_metrics::AccessPoint access_point) {
+  switch (access_point) {
+    case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+      return prefs::kIosBookmarkPromoAlreadySeen;
+    default:
+      return nullptr;
+  }
+}
 }  // namespace
 
 @interface SigninPromoViewMediator ()<ChromeIdentityServiceObserver,
@@ -129,6 +193,7 @@
 
 @implementation SigninPromoViewMediator {
   ios::ChromeBrowserState* _browserState;
+  signin_metrics::AccessPoint _accessPoint;
   std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
   std::unique_ptr<ChromeBrowserProviderObserverBridge> _browserProviderObserver;
   UIImage* _identityAvatar;
@@ -137,16 +202,16 @@
 
 @synthesize consumer = _consumer;
 @synthesize defaultIdentity = _defaultIdentity;
-@synthesize accessPoint = _accessPoint;
-@synthesize displayedCountPreferenceKey = _displayedCountPreferenceKey;
-@synthesize alreadySeenSigninViewPreferenceKey =
-    _alreadySeenSigninViewPreferenceKey;
-@synthesize histograms = _histograms;
 @synthesize signinPromoViewState = _signinPromoViewState;
 
-- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
+                         accessPoint:(signin_metrics::AccessPoint)accessPoint {
   self = [super init];
   if (self) {
+#if DCHECK_IS_ON()
+    DCHECK(IsSupportedAccessPoint(accessPoint));
+#endif  // DCHECK_IS_ON()
+    _accessPoint = accessPoint;
     _browserState = browserState;
     NSArray* identities = ios::GetChromeBrowserProvider()
                               ->GetChromeIdentityService()
@@ -215,19 +280,14 @@
   DCHECK(![self isInvalidOrClosed] ||
          _signinPromoViewState != ios::SigninPromoViewState::Unused);
   _signinPromoViewState = ios::SigninPromoViewState::SigninStarted;
-  if (!_displayedCountPreferenceKey)
+  const char* displayedCountPreferenceKey =
+      DisplayedCountPreferenceKey(_accessPoint);
+  if (!displayedCountPreferenceKey)
     return;
   PrefService* prefs = _browserState->GetPrefs();
-  int displayedCount = prefs->GetInteger(_displayedCountPreferenceKey);
-  switch (_histograms) {
-    case ios::SigninPromoViewHistograms::Bookmarks:
-      UMA_HISTOGRAM_COUNTS_100(
-          "MobileSignInPromo.BookmarkManager.ImpressionsTilSigninButtons",
-          displayedCount);
-      break;
-    case ios::SigninPromoViewHistograms::None:
-      break;
-  }
+  int displayedCount = prefs->GetInteger(displayedCountPreferenceKey);
+  RecordImpressionsTilSigninButtonsHistogramForAccessPoint(_accessPoint,
+                                                           displayedCount);
 }
 
 - (void)signinPromoViewVisible {
@@ -235,15 +295,19 @@
   if (_isSigninPromoViewVisible)
     return;
   _isSigninPromoViewVisible = YES;
-  if (!_displayedCountPreferenceKey)
+  const char* displayedCountPreferenceKey =
+      DisplayedCountPreferenceKey(_accessPoint);
+  if (!displayedCountPreferenceKey)
     return;
   PrefService* prefs = _browserState->GetPrefs();
-  int displayedCount = prefs->GetInteger(_displayedCountPreferenceKey);
+  int displayedCount = prefs->GetInteger(displayedCountPreferenceKey);
   ++displayedCount;
-  prefs->SetInteger(_displayedCountPreferenceKey, displayedCount);
+  prefs->SetInteger(displayedCountPreferenceKey, displayedCount);
+  const char* alreadySeenSigninViewPreferenceKey =
+      AlreadySeenSigninViewPreferenceKey(_accessPoint);
   if (displayedCount >= kAutomaticSigninPromoViewDismissCount &&
-      _alreadySeenSigninViewPreferenceKey) {
-    prefs->SetBoolean(prefs::kIosBookmarkPromoAlreadySeen, true);
+      alreadySeenSigninViewPreferenceKey) {
+    prefs->SetBoolean(alreadySeenSigninViewPreferenceKey, true);
   }
 }
 
@@ -255,19 +319,14 @@
 - (void)signinPromoViewClosed {
   DCHECK(_isSigninPromoViewVisible && ![self isInvalidOrClosed]);
   _signinPromoViewState = ios::SigninPromoViewState::Closed;
-  if (!_displayedCountPreferenceKey)
+  const char* displayedCountPreferenceKey =
+      DisplayedCountPreferenceKey(_accessPoint);
+  if (!displayedCountPreferenceKey)
     return;
   PrefService* prefs = _browserState->GetPrefs();
-  int displayedCount = prefs->GetInteger(_displayedCountPreferenceKey);
-  switch (_histograms) {
-    case ios::SigninPromoViewHistograms::Bookmarks:
-      UMA_HISTOGRAM_COUNTS_100(
-          "MobileSignInPromo.BookmarkManager.ImpressionsTilXButton",
-          displayedCount);
-      break;
-    case ios::SigninPromoViewHistograms::None:
-      break;
-  }
+  int displayedCount = prefs->GetInteger(displayedCountPreferenceKey);
+  RecordImpressionsTilXButtonHistogramForAccessPoint(_accessPoint,
+                                                     displayedCount);
 }
 
 - (void)signinPromoViewRemoved {
@@ -276,7 +335,9 @@
   _signinPromoViewState = ios::SigninPromoViewState::Invalid;
   // If the sign-in promo view has been used at least once, it should not be
   // counted as dismissed (even if the sign-in has been canceled).
-  if (!_displayedCountPreferenceKey || !wasUnused)
+  const char* displayedCountPreferenceKey =
+      DisplayedCountPreferenceKey(_accessPoint);
+  if (!displayedCountPreferenceKey || !wasUnused)
     return;
   // If the sign-in view is removed when the user is authenticated, then the
   // sign-in has been done by another view, and this mediator cannot be counted
@@ -286,16 +347,9 @@
   if (authService->IsAuthenticated())
     return;
   PrefService* prefs = _browserState->GetPrefs();
-  int displayedCount = prefs->GetInteger(_displayedCountPreferenceKey);
-  switch (_histograms) {
-    case ios::SigninPromoViewHistograms::Bookmarks:
-      UMA_HISTOGRAM_COUNTS_100(
-          "MobileSignInPromo.BookmarkManager.ImpressionsTilDismiss",
-          displayedCount);
-      break;
-    case ios::SigninPromoViewHistograms::None:
-      break;
-  }
+  int displayedCount = prefs->GetInteger(displayedCountPreferenceKey);
+  RecordImpressionsTilDismissHistogramForAccessPoint(_accessPoint,
+                                                     displayedCount);
 }
 
 - (void)signinCallback {
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
index 3f5cbe86..d71522b 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
@@ -26,7 +26,10 @@
  protected:
   void SetUp() override {
     consumer_ = OCMStrictProtocolMock(@protocol(SigninPromoViewConsumer));
-    mediator_ = [[SigninPromoViewMediator alloc] initWithBrowserState:nil];
+    mediator_ = [[SigninPromoViewMediator alloc]
+        initWithBrowserState:nil
+                 accessPoint:signin_metrics::AccessPoint::
+                                 ACCESS_POINT_SETTINGS];
     mediator_.consumer = consumer_;
 
     signin_promo_view_ = OCMStrictClassMock([SigninPromoView class]);
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm
index 4e5c759..c736e3e 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm
@@ -354,17 +354,11 @@
       [_signinPromoViewMediator signinPromoViewRemoved];
       _signinPromoViewMediator = nil;
     } else {
-      _signinPromoViewMediator =
-          [[SigninPromoViewMediator alloc] initWithBrowserState:_browserState];
+      _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
+          initWithBrowserState:_browserState
+                   accessPoint:signin_metrics::AccessPoint::
+                                   ACCESS_POINT_BOOKMARK_MANAGER];
       _signinPromoViewMediator.consumer = self;
-      _signinPromoViewMediator.displayedCountPreferenceKey =
-          prefs::kIosBookmarkSigninPromoDisplayedCount;
-      _signinPromoViewMediator.alreadySeenSigninViewPreferenceKey =
-          prefs::kIosBookmarkPromoAlreadySeen;
-      _signinPromoViewMediator.histograms =
-          ios::SigninPromoViewHistograms::Bookmarks;
-      _signinPromoViewMediator.accessPoint =
-          signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER;
       [_signinPromoViewMediator signinPromoViewVisible];
     }
   }
diff --git a/ios/chrome/browser/ui/browser_view_controller.h b/ios/chrome/browser/ui/browser_view_controller.h
index 6cf1927d..60e55dd 100644
--- a/ios/chrome/browser/ui/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view_controller.h
@@ -10,14 +10,14 @@
 #import <UIKit/UIKit.h>
 
 #import "base/ios/block_types.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/side_swipe/side_swipe_controller.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_owner.h"
 #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 #import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/public/provider/chrome/browser/voice/voice_search_presenter.h"
 
-@protocol ApplicationCommands;
-@protocol BrowserCommands;
 @class BrowserContainerView;
 @class BrowserViewControllerDependencyFactory;
 @class ContextualSearchController;
@@ -104,9 +104,6 @@
 // Called when the typing shield is tapped.
 - (void)shieldWasTapped:(id)sender;
 
-// Called when a UI element to create a new tab is triggered.
-- (void)newTab:(id)sender;
-
 // Called when the browser state provided to this instance is being destroyed.
 // At this point the browser will no longer ever be active, and will likely be
 // deallocated soon.
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 2ff7fe56..f2775a49 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -101,7 +101,7 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 #import "ios/chrome/browser/ui/commands/show_mail_composer_command.h"
@@ -790,9 +790,9 @@
 // to download the image.
 - (void)saveImageAtURL:(const GURL&)url referrer:(const web::Referrer&)referrer;
 
-// Determines the center of |sender| if it's a view or a toolbar item, and save
-// the CGPoint and timestamp.
-- (void)setLastTapPoint:(id)sender;
+// Record the last tap point based on the |originPoint| (if any) passed in
+// |command|.
+- (void)setLastTapPoint:(OpenNewTabCommand*)command;
 // Get return the last stored |_lastTapPoint| if it's been set within the past
 // second.
 - (CGPoint)lastTapPoint;
@@ -1182,34 +1182,6 @@
   [_toolbarController cancelOmniboxEdit];
 }
 
-- (void)newTab:(id)sender {
-  // Observe the timing of the new tab creation, both MainController
-  // and BrowserViewController call into this method on the correct BVC to
-  // create new tabs making it preferable to doing this in
-  // |chromeExecuteCommand:|.
-  NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
-  BOOL offTheRecord = self.isOffTheRecord;
-  self.foregroundTabWasAddedCompletionBlock = ^{
-    double duration = [NSDate timeIntervalSinceReferenceDate] - startTime;
-    base::TimeDelta timeDelta = base::TimeDelta::FromSecondsD(duration);
-    if (offTheRecord) {
-      UMA_HISTOGRAM_TIMES("Toolbar.Menu.NewIncognitoTabPresentationDuration",
-                          timeDelta);
-    } else {
-      UMA_HISTOGRAM_TIMES("Toolbar.Menu.NewTabPresentationDuration", timeDelta);
-    }
-  };
-
-  [self setLastTapPoint:sender];
-  DCHECK(self.visible || self.dismissingModal);
-  Tab* currentTab = [_model currentTab];
-  if (currentTab) {
-    [currentTab updateSnapshotWithOverlay:YES visibleFrameOnly:YES];
-  }
-  [self addSelectedTabWithURL:GURL(kChromeUINewTabURL)
-                   transition:ui::PAGE_TRANSITION_TYPED];
-}
-
 #pragma mark - UIViewController methods
 
 // Perform additional set up after loading the view, typically from a nib.
@@ -1686,6 +1658,7 @@
   _browserState = browserState;
   _isOffTheRecord = browserState->IsOffTheRecord() ? YES : NO;
   _model = model;
+
   [_model addObserver:self];
 
   if (!_isOffTheRecord) {
@@ -1783,7 +1756,8 @@
   // If needed, create the tabstrip.
   if (IsIPadIdiom()) {
     _tabStripController =
-        [_dependencyFactory newTabStripControllerWithTabModel:_model];
+        [_dependencyFactory newTabStripControllerWithTabModel:_model
+                                                   dispatcher:self.dispatcher];
     _tabStripController.fullscreenDelegate = self;
   }
 
@@ -1978,11 +1952,7 @@
 
 #pragma mark - Tap handling
 
-- (void)setLastTapPoint:(id)sender {
-  NewTabCommand* command = base::mac::ObjCCast<NewTabCommand>(sender);
-  if (!command)
-    return;
-
+- (void)setLastTapPoint:(OpenNewTabCommand*)command {
   if (CGPointEqualToPoint(command.originPoint, CGPointZero)) {
     _lastTapPoint = CGPointZero;
   } else {
@@ -2120,6 +2090,7 @@
 
 - (void)installDelegatesForTab:(Tab*)tab {
   // Unregistration happens when the Tab is removed from the TabModel.
+  tab.dispatcher = self.dispatcher;
   tab.dialogDelegate = self;
   tab.snapshotOverlayProvider = self;
   tab.passKitDialogProvider = self;
@@ -2141,6 +2112,7 @@
 }
 
 - (void)uninstallDelegatesForTab:(Tab*)tab {
+  tab.dispatcher = nil;
   tab.dialogDelegate = nil;
   tab.snapshotOverlayProvider = nil;
   tab.passKitDialogProvider = nil;
@@ -2932,7 +2904,9 @@
                    didTriggerAction:(OverscrollAction)action {
   switch (action) {
     case OverscrollAction::NEW_TAB:
-      [self newTab:nil];
+      [self.dispatcher
+          openNewTab:[OpenNewTabCommand
+                         commandWithIncognito:self.isOffTheRecord]];
       break;
     case OverscrollAction::CLOSE_TAB:
       [self.dispatcher closeCurrentTab];
@@ -3622,7 +3596,7 @@
   if (entry->type != sessions::TabRestoreService::TAB)
     return;
 
-  [self chromeExecuteCommand:[[NewTabCommand alloc] initWithIncognito:NO]];
+  [self.dispatcher openNewTab:[OpenNewTabCommand command]];
   TabRestoreServiceDelegateImplIOS* const delegate =
       TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState(
           _browserState);
@@ -4026,6 +4000,36 @@
   }
 }
 
+- (void)openNewTab:(OpenNewTabCommand*)command {
+  if (self.isOffTheRecord != command.incognito) {
+    // Not for this browser state, send it on its way.
+    [self.dispatcher switchModesAndOpenNewTab:command];
+    return;
+  }
+
+  NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
+  BOOL offTheRecord = self.isOffTheRecord;
+  self.foregroundTabWasAddedCompletionBlock = ^{
+    double duration = [NSDate timeIntervalSinceReferenceDate] - startTime;
+    base::TimeDelta timeDelta = base::TimeDelta::FromSecondsD(duration);
+    if (offTheRecord) {
+      UMA_HISTOGRAM_TIMES("Toolbar.Menu.NewIncognitoTabPresentationDuration",
+                          timeDelta);
+    } else {
+      UMA_HISTOGRAM_TIMES("Toolbar.Menu.NewTabPresentationDuration", timeDelta);
+    }
+  };
+
+  [self setLastTapPoint:command];
+  DCHECK(self.visible || self.dismissingModal);
+  Tab* currentTab = [_model currentTab];
+  if (currentTab) {
+    [currentTab updateSnapshotWithOverlay:YES visibleFrameOnly:YES];
+  }
+  [self addSelectedTabWithURL:GURL(kChromeUINewTabURL)
+                   transition:ui::PAGE_TRANSITION_TYPED];
+}
+
 #pragma mark - Command Handling
 
 - (IBAction)chromeExecuteCommand:(id)sender {
@@ -4066,28 +4070,12 @@
     case IDC_HELP_PAGE_VIA_MENU:
       [self showHelpPage];
       break;
-    case IDC_NEW_TAB:
-      if (_isOffTheRecord) {
-        // Not for this browser state, send it on its way.
-        [super chromeExecuteCommand:sender];
-      } else {
-        [self newTab:sender];
-      }
-      break;
     case IDC_PRELOAD_VOICE_SEARCH:
       // Preload VoiceSearchController and views and view controllers needed
       // for voice search.
       [self ensureVoiceSearchControllerCreated];
       _voiceSearchController->PrepareToAppear();
       break;
-    case IDC_NEW_INCOGNITO_TAB:
-      if (_isOffTheRecord) {
-        [self newTab:sender];
-      } else {
-        // Not for this browser state, send it on its way.
-        [super chromeExecuteCommand:sender];
-      }
-      break;
     case IDC_SHOW_MAIL_COMPOSER:
       [self showMailComposer:sender];
       break;
diff --git a/ios/chrome/browser/ui/browser_view_controller_dependency_factory.h b/ios/chrome/browser/ui/browser_view_controller_dependency_factory.h
index 4dd19e7..de44054 100644
--- a/ios/chrome/browser/ui/browser_view_controller_dependency_factory.h
+++ b/ios/chrome/browser/ui/browser_view_controller_dependency_factory.h
@@ -59,7 +59,10 @@
 // Caller is responsible for releasing all of the created objects.
 - (PreloadController*)newPreloadController;
 
-- (TabStripController*)newTabStripControllerWithTabModel:(TabModel*)model;
+- (TabStripController*)
+newTabStripControllerWithTabModel:(TabModel*)model
+                       dispatcher:
+                           (id<ApplicationCommands, BrowserCommands>)dispatcher;
 
 - (ToolbarModelIOS*)newToolbarModelIOSWithDelegate:
     (ToolbarModelDelegateIOS*)delegate;
diff --git a/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm b/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm
index f843303..b5fd7b7 100644
--- a/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_dependency_factory.mm
@@ -66,11 +66,16 @@
   return [[PreloadController alloc] initWithBrowserState:browserState_];
 }
 
-- (TabStripController*)newTabStripControllerWithTabModel:(TabModel*)model {
+- (TabStripController*)
+newTabStripControllerWithTabModel:(TabModel*)model
+                       dispatcher:(id<ApplicationCommands, BrowserCommands>)
+                                      dispatcher {
   TabStrip::Style style = TabStrip::kStyleDark;
   if (browserState_ && browserState_->IsOffTheRecord())
     style = TabStrip::kStyleIncognito;
-  return [[TabStripController alloc] initWithTabModel:model style:style];
+  return [[TabStripController alloc] initWithTabModel:model
+                                                style:style
+                                           dispatcher:dispatcher];
 }
 
 - (ToolbarModelIOS*)newToolbarModelIOSWithDelegate:
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index 32f1d717..17fe03a 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -229,7 +229,8 @@
     id factory = [OCMockObject
         mockForClass:[BrowserViewControllerDependencyFactory class]];
     [[[factory stub] andReturn:nil]
-        newTabStripControllerWithTabModel:[OCMArg any]];
+        newTabStripControllerWithTabModel:[OCMArg any]
+                               dispatcher:[OCMArg any]];
     [[[factory stub] andReturn:nil] newPreloadController];
     [[[factory stub] andReturnValue:OCMOCK_VALUE(toolbarModelIOS_)]
         newToolbarModelIOSWithDelegate:static_cast<ToolbarModelDelegateIOS*>(
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn
index 2d90b7f..78cc897c 100644
--- a/ios/chrome/browser/ui/commands/BUILD.gn
+++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -14,8 +14,8 @@
     "generic_chrome_command.h",
     "generic_chrome_command.mm",
     "ios_command_ids.h",
-    "new_tab_command.h",
-    "new_tab_command.mm",
+    "open_new_tab_command.h",
+    "open_new_tab_command.mm",
     "open_url_command.h",
     "open_url_command.mm",
     "reading_list_add_command.h",
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h
index 1740cda7..eea29e8e 100644
--- a/ios/chrome/browser/ui/commands/application_commands.h
+++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -7,6 +7,8 @@
 
 #import <Foundation/Foundation.h>
 
+@class OpenNewTabCommand;
+
 // Protocol for commands that will generally be handled by the application,
 // rather than a specific tab; in practice this means the MainController
 // instance.
@@ -16,6 +18,11 @@
 // Shows the Settings UI.
 - (void)showSettings;
 
+// Switches to show either regular or incognito tabs, and then opens
+// a new oen of those tabs. |newTabCommand|'s |incognito| property inidcates
+// the type of tab to open.
+- (void)switchModesAndOpenNewTab:(OpenNewTabCommand*)newTabCommand;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_APPLICATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 96c689d..e6cabf672 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -7,6 +7,8 @@
 
 #import <Foundation/Foundation.h>
 
+@class OpenNewTabCommand;
+
 // Protocol for commands that will generally be handled by the "current tab",
 // which in practice is the BrowserViewController instance displaying the tab.
 @protocol BrowserCommands<NSObject>
@@ -35,6 +37,9 @@
 // Shows the tools menu.
 - (void)showToolsMenu;
 
+// Opens a new tab as specified by |newTabCommand|.
+- (void)openNewTab:(OpenNewTabCommand*)newTabCommand;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 7f181bd..941ed2b 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -13,7 +13,6 @@
 // also need to be updated.
 
 // clang-format off
-#define IDC_NEW_TAB                                    34014
 #define IDC_VIEW_SOURCE                                35002
 #define IDC_PRINT                                      35003
 #define IDC_FIND                                       37000
@@ -24,7 +23,6 @@
 #define IDC_HELP_PAGE_VIA_MENU                         40020
 #define IDC_TOGGLE_TAB_SWITCHER                        40901
 #define IDC_VOICE_SEARCH                               40902
-#define IDC_NEW_INCOGNITO_TAB                          40903
 #define IDC_CLOSE_ALL_TABS                             40904
 #define IDC_SHOW_SIGNIN_IOS                            40905
 #define IDC_FIND_CLOSE                                 40907
diff --git a/ios/chrome/browser/ui/commands/new_tab_command.h b/ios/chrome/browser/ui/commands/new_tab_command.h
deleted file mode 100644
index 1b24cdc..0000000
--- a/ios/chrome/browser/ui/commands/new_tab_command.h
+++ /dev/null
@@ -1,32 +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 IOS_CHROME_BROWSER_UI_COMMANDS_NEW_TAB_COMMAND_H_
-#define IOS_CHROME_BROWSER_UI_COMMANDS_NEW_TAB_COMMAND_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
-
-// Command sent to open a new tab, optionally including a point (in UIWindow
-// coordinates).
-@interface NewTabCommand : GenericChromeCommand
-
-- (instancetype)initWithIncognito:(BOOL)incognito
-                      originPoint:(CGPoint)originPoint
-    NS_DESIGNATED_INITIALIZER;
-
-// Create a NewTabCommand with an OriginPoint of CGPointZero.
-- (instancetype)initWithIncognito:(BOOL)incognito;
-
-// Mark inherited initializer as unavailable to prevent calling it by mistake.
-- (instancetype)initWithTag:(NSInteger)tag NS_UNAVAILABLE;
-
-@property(nonatomic, readonly) BOOL incognito;
-
-@property(nonatomic, readonly) CGPoint originPoint;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_COMMANDS_NEW_TAB_COMMAND_H_
diff --git a/ios/chrome/browser/ui/commands/new_tab_command.mm b/ios/chrome/browser/ui/commands/new_tab_command.mm
deleted file mode 100644
index 5a0951c..0000000
--- a/ios/chrome/browser/ui/commands/new_tab_command.mm
+++ /dev/null
@@ -1,32 +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.
-
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
-
-#import "ios/chrome/browser/ui/commands/ios_command_ids.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation NewTabCommand
-
-@synthesize incognito = _incognito;
-@synthesize originPoint = _originPoint;
-
-- (instancetype)initWithIncognito:(BOOL)incognito
-                      originPoint:(CGPoint)originPoint {
-  int tag = incognito ? IDC_NEW_INCOGNITO_TAB : IDC_NEW_TAB;
-  if ((self = [super initWithTag:tag])) {
-    _incognito = incognito;
-    _originPoint = originPoint;
-  }
-  return self;
-}
-
-- (instancetype)initWithIncognito:(BOOL)incognito {
-  return [self initWithIncognito:incognito originPoint:CGPointZero];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/commands/open_new_tab_command.h b/ios/chrome/browser/ui/commands/open_new_tab_command.h
new file mode 100644
index 0000000..9e3af58
--- /dev/null
+++ b/ios/chrome/browser/ui/commands/open_new_tab_command.h
@@ -0,0 +1,43 @@
+// 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 IOS_CHROME_BROWSER_UI_COMMANDS_OPEN_NEW_TAB_COMMAND_H_
+#define IOS_CHROME_BROWSER_UI_COMMANDS_OPEN_NEW_TAB_COMMAND_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
+
+// Command sent to open a new tab, optionally including a point (in UIWindow
+// coordinates).
+@interface OpenNewTabCommand : GenericChromeCommand
+
+- (instancetype)initWithIncognito:(BOOL)incognito
+                      originPoint:(CGPoint)originPoint
+    NS_DESIGNATED_INITIALIZER;
+
+// Mark inherited initializer as unavailable to prevent calling it by mistake.
+- (instancetype)initWithTag:(NSInteger)tag NS_UNAVAILABLE;
+
+// Convenience initializers
+
+// Creates an OpenTabCommand with |incognito| and an |originPoint| of
+// CGPointZero.
++ (instancetype)commandWithIncognito:(BOOL)incognito;
+
+// Creates an OpenTabCommand with |incognito| NO and an |originPoint| of
+// CGPointZero.
++ (instancetype)command;
+
+// Creates an OpenTabCommand with |incognito| YES and an |originPoint| of
+// CGPointZero.
++ (instancetype)incognitoTabCommand;
+
+@property(nonatomic, readonly) BOOL incognito;
+
+@property(nonatomic, readonly) CGPoint originPoint;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_COMMANDS_OPEN_NEW_TAB_COMMAND_H_
diff --git a/ios/chrome/browser/ui/commands/open_new_tab_command.mm b/ios/chrome/browser/ui/commands/open_new_tab_command.mm
new file mode 100644
index 0000000..e261e41
--- /dev/null
+++ b/ios/chrome/browser/ui/commands/open_new_tab_command.mm
@@ -0,0 +1,37 @@
+// 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.
+
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation OpenNewTabCommand
+
+@synthesize incognito = _incognito;
+@synthesize originPoint = _originPoint;
+
+- (instancetype)initWithIncognito:(BOOL)incognito
+                      originPoint:(CGPoint)originPoint {
+  if ((self = [super initWithTag:0])) {
+    _incognito = incognito;
+    _originPoint = originPoint;
+  }
+  return self;
+}
+
++ (instancetype)commandWithIncognito:(BOOL)incognito {
+  return [[self alloc] initWithIncognito:incognito originPoint:CGPointZero];
+}
+
++ (instancetype)command {
+  return [self commandWithIncognito:NO];
+}
+
++ (instancetype)incognitoTabCommand {
+  return [self commandWithIncognito:YES];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/key_commands_provider.mm b/ios/chrome/browser/ui/key_commands_provider.mm
index 8a67be2..8947b51 100644
--- a/ios/chrome/browser/ui/key_commands_provider.mm
+++ b/ios/chrome/browser/ui/key_commands_provider.mm
@@ -8,7 +8,7 @@
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -67,15 +67,11 @@
 
   // New tab blocks.
   void (^newTab)() = ^{
-    [weakConsumer
-        chromeExecuteCommand:[[NewTabCommand alloc]
-                                 initWithIncognito:[weakConsumer
-                                                       isOffTheRecord]]];
+    [weakDispatcher openNewTab:[OpenNewTabCommand command]];
   };
 
   void (^newIncognitoTab)() = ^{
-    [weakConsumer
-        chromeExecuteCommand:[[NewTabCommand alloc] initWithIncognito:YES]];
+    [weakDispatcher openNewTab:[OpenNewTabCommand incognitoTabCommand]];
   };
 
   const int browseLeftDescriptionID = useRTLLayout
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index 24cc4ab..10dc669 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -274,5 +274,6 @@
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/test:perf_test_support",
     "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/commands",
   ]
 }
diff --git a/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
index ed05e34..f94466a 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
@@ -14,7 +14,7 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_data_source.h"
@@ -1222,8 +1222,8 @@
                    didTriggerAction:(OverscrollAction)action {
   switch (action) {
     case OverscrollAction::NEW_TAB: {
-      NewTabCommand* command = [[NewTabCommand alloc] initWithIncognito:NO];
-      [[self view] chromeExecuteCommand:command];
+      OpenNewTabCommand* command = [OpenNewTabCommand command];
+      [self.dispatcher openNewTab:command];
     } break;
     case OverscrollAction::CLOSE_TAB:
       [self.dispatcher closeCurrentTab];
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_perftest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_perftest.mm
index 5f952fa..1e37daf 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_perftest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_perftest.mm
@@ -8,6 +8,7 @@
 #include "ios/chrome/browser/test/perf_test_with_bvc_ios.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
 #import "ios/chrome/browser/ui/browser_view_controller_dependency_factory.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -37,7 +38,7 @@
   }
   base::TimeDelta TimedNewTab() {
     base::Time startTime = base::Time::NowFromSystemTime();
-    [bvc_ newTab:nil];
+    [[bvc_ dispatcher] openNewTab:[OpenNewTabCommand command]];
     return base::Time::NowFromSystemTime() - startTime;
   }
   void SettleUI() {
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index abbdbbc..deaffd0 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -826,10 +826,10 @@
     case CELL_OTHER_DEVICES_SIGNIN_PROMO: {
       if (!_signinPromoViewMediator) {
         _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
-            initWithBrowserState:_browserState];
+            initWithBrowserState:_browserState
+                     accessPoint:signin_metrics::AccessPoint::
+                                     ACCESS_POINT_RECENT_TABS];
         _signinPromoViewMediator.consumer = self;
-        _signinPromoViewMediator.accessPoint =
-            signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS;
       }
       contentViewTopMargin = kSigninPromoViewTopMargin;
       SigninPromoView* signinPromoView =
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
index d8255d0..0a24ee54 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -341,7 +341,9 @@
         displayedCount < kAutomaticSigninPromoViewDismissCount) {
       if (!_signinPromoViewMediator) {
         _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
-            initWithBrowserState:_browserState];
+            initWithBrowserState:_browserState
+                     accessPoint:signin_metrics::AccessPoint::
+                                     ACCESS_POINT_SETTINGS];
         _signinPromoViewMediator.consumer = self;
         prefs->SetInteger(prefs::kIosSettingsSigninPromoDisplayedCount,
                           displayedCount + 1);
diff --git a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
index a263b028..0bc5627e 100644
--- a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
+++ b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
@@ -32,7 +32,7 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h"
 #import "ios/chrome/browser/ui/reversed_animation.h"
@@ -2016,11 +2016,7 @@
                                transition:transition];
 }
 
-- (void)setLastTapPoint:(id)sender {
-  NewTabCommand* command = base::mac::ObjCCast<NewTabCommand>(sender);
-  if (!command)
-    return;
-
+- (void)setLastTapPoint:(OpenNewTabCommand*)command {
   if (CGPointEqualToPoint(command.originPoint, CGPointZero)) {
     _lastTapPoint = CGPointZero;
   } else {
@@ -2713,6 +2709,16 @@
   [_toolbarController showToolsMenuPopupWithConfiguration:configuration];
 }
 
+- (void)openNewTab:(OpenNewTabCommand*)command {
+  // Ensure that the right mode is showing.
+  if ([self isCurrentSetIncognito] != command.incognito)
+    [self setActiveCardSet:[self inactiveCardSet]];
+  [self setLastTapPoint:command];
+  [self dismissWithNewTabAnimation:GURL(kChromeUINewTabURL)
+                           atIndex:NSNotFound
+                        transition:ui::PAGE_TRANSITION_TYPED];
+}
+
 - (IBAction)chromeExecuteCommand:(id)sender {
   int command = [sender tag];
 
@@ -2728,16 +2734,6 @@
       DCHECK([self isCurrentSetIncognito]);
       [self removeAllCardsFromSet:_activeCardSet];
       break;
-    case IDC_NEW_INCOGNITO_TAB:
-    case IDC_NEW_TAB:
-      // Ensure that the right mode is showing.
-      if ([self isCurrentSetIncognito] != (command == IDC_NEW_INCOGNITO_TAB))
-        [self setActiveCardSet:[self inactiveCardSet]];
-      [self setLastTapPoint:sender];
-      [self dismissWithNewTabAnimation:GURL(kChromeUINewTabURL)
-                               atIndex:NSNotFound
-                            transition:ui::PAGE_TRANSITION_TYPED];
-      break;
     case IDC_TOGGLE_TAB_SWITCHER:
       [self dismissWithSelectedTabAnimation];
       break;
@@ -3482,16 +3478,11 @@
 
   // New tab blocks.
   void (^newTab)() = ^{
-    [weakSelf
-        chromeExecuteCommand:[[NewTabCommand alloc]
-                                 initWithIncognito:[weakSelf
-                                                       isCurrentSetIncognito]]];
-
+    [weakSelf.dispatcher openNewTab:[OpenNewTabCommand command]];
   };
 
   void (^newIncognitoTab)() = ^{
-    [weakSelf
-        chromeExecuteCommand:[[NewTabCommand alloc] initWithIncognito:YES]];
+    [weakSelf.dispatcher openNewTab:[OpenNewTabCommand incognitoTabCommand]];
   };
 
   return @[
diff --git a/ios/chrome/browser/ui/stack_view/stack_view_toolbar_controller.mm b/ios/chrome/browser/ui/stack_view/stack_view_toolbar_controller.mm
index a2fbe78..5b581e3 100644
--- a/ios/chrome/browser/ui/stack_view/stack_view_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/stack_view/stack_view_toolbar_controller.mm
@@ -7,9 +7,11 @@
 #include "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/image_util.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
-#include "ios/chrome/browser/ui/toolbar/new_tab_button.h"
+#import "ios/chrome/browser/ui/toolbar/new_tab_button.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -27,6 +29,7 @@
 @implementation StackViewToolbarController {
   UIView* _stackViewToolbar;
   NewTabButton* _openNewTabButton;
+  __weak id<ApplicationCommands, BrowserCommands> _dispatcher;
 }
 
 - (instancetype)initWithDispatcher:
@@ -34,6 +37,7 @@
   self = [super initWithStyle:ToolbarControllerStyleDarkMode
                    dispatcher:dispatcher];
   if (self) {
+    _dispatcher = dispatcher;
     _stackViewToolbar =
         [[UIView alloc] initWithFrame:[self specificControlsArea]];
     [_stackViewToolbar setAutoresizingMask:UIViewAutoresizingFlexibleHeight |
@@ -50,7 +54,10 @@
         kNewTabLeadingOffset, [_stackViewToolbar bounds].size.width, 0,
         buttonSize, buttonSize);
     [_openNewTabButton setFrame:LayoutRectGetRect(newTabButtonLayout)];
-    // Set additional button action.
+    // Set button actions.
+    [_openNewTabButton addTarget:self
+                          action:@selector(sendNewTabCommand:)
+                forControlEvents:UIControlEventTouchUpInside];
     [_openNewTabButton addTarget:self
                           action:@selector(recordUserMetrics:)
                 forControlEvents:UIControlEventTouchUpInside];
@@ -70,6 +77,19 @@
   return _openNewTabButton;
 }
 
+- (void)sendNewTabCommand:(id)sender {
+  if (sender != _openNewTabButton)
+    return;
+
+  CGPoint center =
+      [_openNewTabButton.superview convertPoint:_openNewTabButton.center
+                                         toView:_openNewTabButton.window];
+  OpenNewTabCommand* command =
+      [[OpenNewTabCommand alloc] initWithIncognito:_openNewTabButton.isIncognito
+                                       originPoint:center];
+  [_dispatcher openNewTab:command];
+}
+
 - (IBAction)recordUserMetrics:(id)sender {
   if (sender == _openNewTabButton)
     base::RecordAction(UserMetricsAction("MobileToolbarStackViewNewTab"));
diff --git a/ios/chrome/browser/ui/tab_switcher/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
index acb9b00..bd190e6c 100644
--- a/ios/chrome/browser/ui/tab_switcher/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
@@ -86,6 +86,7 @@
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/common:ios_app_bundle_id_prefix_header",
     "//ios/public/provider/chrome/browser",
+    "//ios/shared/chrome/browser/ui/commands",
     "//ios/third_party/material_components_ios",
     "//ios/third_party/material_roboto_font_loader_ios",
     "//ios/third_party/material_text_accessibility_ios",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.h
index 4dd0237..a2dd83cd 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.h
@@ -9,6 +9,8 @@
 
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher.h"
 
+@protocol ApplicationCommands;
+
 namespace ios {
 class ChromeBrowserState;
 }
@@ -18,7 +20,8 @@
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                         mainTabModel:(TabModel*)mainTabModel
                          otrTabModel:(TabModel*)otrTabModel
-                      activeTabModel:(TabModel*)activeTabModel;
+                      activeTabModel:(TabModel*)activeTabModel
+          applicationCommandEndpoint:(id<ApplicationCommands>)endpoint;
 
 @end
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
index 9b958c7..ef8ded5 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
@@ -22,9 +22,11 @@
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#include "ios/chrome/browser/ui/commands/application_commands.h"
+#include "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h"
@@ -46,6 +48,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
+#import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/referrer.h"
@@ -113,6 +116,8 @@
   // added.
   BOOL _shouldRemovePromoPanelHeaderCell;
   BOOL _shouldAddPromoPanelHeaderCell;
+  // Handles command dispatching.
+  CommandDispatcher* _dispatcher;
 }
 
 // Updates the window background color to the tab switcher's background color.
@@ -188,13 +193,25 @@
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                         mainTabModel:(TabModel*)mainTabModel
                          otrTabModel:(TabModel*)otrTabModel
-                      activeTabModel:(TabModel*)activeTabModel {
+                      activeTabModel:(TabModel*)activeTabModel
+          applicationCommandEndpoint:(id<ApplicationCommands>)endpoint {
   DCHECK(mainTabModel);
   DCHECK(otrTabModel);
   DCHECK(activeTabModel == otrTabModel || activeTabModel == mainTabModel);
   self = [super initWithNibName:nil bundle:nil];
   if (self) {
     _browserState = browserState;
+
+    _dispatcher = [[CommandDispatcher alloc] init];
+    [_dispatcher startDispatchingToTarget:self
+                              forProtocol:@protocol(BrowserCommands)];
+    [_dispatcher startDispatchingToTarget:endpoint
+                              forProtocol:@protocol(ApplicationCommands)];
+    // self.dispatcher shouldn't be used in this init method, so duplicate the
+    // typecast to pass dispatcher into child objects.
+    id<ApplicationCommands, BrowserCommands> passableDispatcher =
+        static_cast<id<ApplicationCommands, BrowserCommands>>(_dispatcher);
+
     _onLoadActiveModel = activeTabModel;
     _cache = [[TabSwitcherCache alloc] init];
     [_cache setMainTabModel:mainTabModel otrTabModel:otrTabModel];
@@ -210,13 +227,15 @@
                 initWithModel:_tabSwitcherModel
         forLocalSessionOfType:TabSwitcherSessionType::REGULAR_SESSION
                     withCache:_cache
-                 browserState:_browserState];
+                 browserState:_browserState
+                   dispatcher:passableDispatcher];
     [_onTheRecordSession setDelegate:self];
     _offTheRecordSession = [[TabSwitcherPanelController alloc]
                 initWithModel:_tabSwitcherModel
         forLocalSessionOfType:TabSwitcherSessionType::OFF_THE_RECORD_SESSION
                     withCache:_cache
-                 browserState:_browserState];
+                 browserState:_browserState
+                   dispatcher:passableDispatcher];
     [_offTheRecordSession setDelegate:self];
     [_tabSwitcherView addPanelView:[_offTheRecordSession view]
                            atIndex:kLocalTabsOffTheRecordPanelIndex];
@@ -376,34 +395,31 @@
 }
 
 - (id<ApplicationCommands, BrowserCommands>)dispatcher {
-  // TODO(crbug.com/738881) add a dispatcher instance to this class and
-  // return it here when needed.
-  return nil;
+  return static_cast<id<ApplicationCommands, BrowserCommands>>(_dispatcher);
+}
+
+#pragma mark - BrowserCommands
+
+- (void)openNewTab:(OpenNewTabCommand*)command {
+  // Ensure that the right mode is showing.
+  NSInteger panelIndex = command.incognito ? kLocalTabsOffTheRecordPanelIndex
+                                           : kLocalTabsOnTheRecordPanelIndex;
+  [_tabSwitcherView selectPanelAtIndex:panelIndex];
+
+  const TabSwitcherSessionType panelSessionType =
+      (command.incognito) ? TabSwitcherSessionType::OFF_THE_RECORD_SESSION
+                          : TabSwitcherSessionType::REGULAR_SESSION;
+
+  TabModel* model = [self tabModelForSessionType:panelSessionType];
+  [self dismissWithNewTabAnimation:GURL(kChromeUINewTabURL)
+                           atIndex:NSNotFound
+                        transition:ui::PAGE_TRANSITION_TYPED
+                          tabModel:model];
 }
 
 - (IBAction)chromeExecuteCommand:(id)sender {
   int command = [sender tag];
-
   switch (command) {
-    case IDC_NEW_INCOGNITO_TAB:  // fallthrough
-    case IDC_NEW_TAB: {
-      // Ensure that the right mode is showing.
-      NSInteger panelIndex = (command == IDC_NEW_TAB)
-                                 ? kLocalTabsOnTheRecordPanelIndex
-                                 : kLocalTabsOffTheRecordPanelIndex;
-      [_tabSwitcherView selectPanelAtIndex:panelIndex];
-
-      const TabSwitcherSessionType panelSessionType =
-          (command == IDC_NEW_TAB)
-              ? TabSwitcherSessionType::REGULAR_SESSION
-              : TabSwitcherSessionType::OFF_THE_RECORD_SESSION;
-
-      TabModel* model = [self tabModelForSessionType:panelSessionType];
-      [self dismissWithNewTabAnimation:GURL(kChromeUINewTabURL)
-                               atIndex:NSNotFound
-                            transition:ui::PAGE_TRANSITION_TYPED
-                              tabModel:model];
-    } break;
     case IDC_TOGGLE_TAB_SWITCHER:
       [self tabSwitcherDismissWithCurrentSelectedModel];
       break;
@@ -928,8 +944,7 @@
   if (entry->type != sessions::TabRestoreService::TAB)
     return;
 
-  NewTabCommand* command = [[NewTabCommand alloc] initWithIncognito:NO];
-  [self chromeExecuteCommand:command];
+  [self.dispatcher openNewTab:[OpenNewTabCommand command]];
   TabRestoreServiceDelegateImplIOS* const delegate =
       TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState(
           _browserState);
@@ -958,7 +973,8 @@
     TabSwitcherPanelController* panelController =
         [[TabSwitcherPanelController alloc] initWithModel:_tabSwitcherModel
                                  forDistantSessionWithTag:tag
-                                             browserState:_browserState];
+                                             browserState:_browserState
+                                               dispatcher:self.dispatcher];
     [panelController setDelegate:self];
     [_tabSwitcherView addPanelView:[panelController view]
                            atIndex:index + offset];
@@ -1011,7 +1027,8 @@
   if (panelType != TabSwitcherSignInPanelsType::NO_PANEL) {
     TabSwitcherPanelOverlayView* panelView =
         [[TabSwitcherPanelOverlayView alloc] initWithFrame:CGRectZero
-                                              browserState:_browserState];
+                                              browserState:_browserState
+                                                dispatcher:self.dispatcher];
     [panelView setOverlayType:PanelOverlayTypeFromSignInPanelsType(panelType)];
     [_tabSwitcherView addPanelView:panelView atIndex:kSignInPromoPanelIndex];
   }
@@ -1124,8 +1141,8 @@
         base::UserMetricsAction("MobileTabSwitcherCreateNonIncognitoTab"));
   }
   // Create and execute command to create the tab.
-  NewTabCommand* command = [[NewTabCommand alloc] initWithIncognito:incognito];
-  [self chromeExecuteCommand:command];
+  [self.dispatcher
+      openNewTab:[OpenNewTabCommand commandWithIncognito:incognito]];
 }
 
 - (ios_internal::NewTabButtonStyle)buttonStyleForPanelAtIndex:
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h
index d09ebc9..141cc540 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h
@@ -11,6 +11,9 @@
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_model.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h"
 
+@protocol ApplicationCommands;
+@protocol BrowserCommands;
+
 namespace ios {
 class ChromeBrowserState;
 }
@@ -54,6 +57,8 @@
 @property(nonatomic, unsafe_unretained) id<TabSwitcherPanelControllerDelegate>
     delegate;
 @property(nonatomic, readonly) TabSwitcherSessionType sessionType;
+@property(nonatomic, readonly, weak) id<ApplicationCommands, BrowserCommands>
+    dispatcher;
 
 // Initializes a controller for a view showing local tabs. |offTheRecord|
 // determines whether the tabs will be shown for the incognito browser state or
@@ -61,13 +66,17 @@
 - (instancetype)initWithModel:(TabSwitcherModel*)model
         forLocalSessionOfType:(TabSwitcherSessionType)type
                     withCache:(TabSwitcherCache*)cache
-                 browserState:(ios::ChromeBrowserState*)browserState;
+                 browserState:(ios::ChromeBrowserState*)browserState
+                   dispatcher:
+                       (id<ApplicationCommands, BrowserCommands>)dispatcher;
 
 // Initializes a controller for a view showing the tabs of a distant session.
 // |model| is used to populate the view and must not be nil.
 - (instancetype)initWithModel:(TabSwitcherModel*)model
      forDistantSessionWithTag:(std::string const&)sessionTag
-                 browserState:(ios::ChromeBrowserState*)browserState;
+                 browserState:(ios::ChromeBrowserState*)browserState
+                   dispatcher:
+                       (id<ApplicationCommands, BrowserCommands>)dispatcher;
 
 // Tells the controller that the collectionview's content may need to be
 // updated.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
index f9fee57d..a2cd683 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
@@ -56,13 +56,17 @@
 
 @synthesize delegate = _delegate;
 @synthesize sessionType = _sessionType;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithModel:(TabSwitcherModel*)model
      forDistantSessionWithTag:(std::string const&)sessionTag
-                 browserState:(ios::ChromeBrowserState*)browserState {
+                 browserState:(ios::ChromeBrowserState*)browserState
+                   dispatcher:
+                       (id<ApplicationCommands, BrowserCommands>)dispatcher {
   self = [super init];
   if (self) {
     DCHECK(model);
+    _dispatcher = dispatcher;
     _sessionType = TabSwitcherSessionType::DISTANT_SESSION;
     _model = model;
     _distantSession = [model distantSessionForTag:sessionTag];
@@ -76,10 +80,13 @@
 - (instancetype)initWithModel:(TabSwitcherModel*)model
         forLocalSessionOfType:(TabSwitcherSessionType)sessionType
                     withCache:(TabSwitcherCache*)cache
-                 browserState:(ios::ChromeBrowserState*)browserState {
+                 browserState:(ios::ChromeBrowserState*)browserState
+                   dispatcher:
+                       (id<ApplicationCommands, BrowserCommands>)dispatcher {
   self = [super init];
   if (self) {
     DCHECK(model);
+    _dispatcher = dispatcher;
     _sessionType = sessionType;
     _model = model;
     _localSession = [model tabModelSnapshotForLocalSession:sessionType];
@@ -316,7 +323,8 @@
   if (!_overlayView) {
     _overlayView =
         [[TabSwitcherPanelOverlayView alloc] initWithFrame:[_panelView bounds]
-                                              browserState:_browserState];
+                                              browserState:_browserState
+                                                dispatcher:self.dispatcher];
     [_overlayView
         setOverlayType:
             (_sessionType == TabSwitcherSessionType::OFF_THE_RECORD_SESSION)
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h
index e672a1c9..3178310 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol BrowserCommands;
+
 namespace ios {
 class ChromeBrowserState;
 }
@@ -29,9 +31,11 @@
 @interface TabSwitcherPanelOverlayView : UIView
 
 @property(nonatomic, assign) TabSwitcherPanelOverlayType overlayType;
+@property(nonatomic, readonly, weak) id<BrowserCommands> dispatcher;
 
 - (instancetype)initWithFrame:(CGRect)frame
-                 browserState:(ios::ChromeBrowserState*)browserState;
+                 browserState:(ios::ChromeBrowserState*)browserState
+                   dispatcher:(id<BrowserCommands>)dispatcher;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_SWITCHER_PANEL_OVERLAY_VIEW_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm
index f3d6ceef..968d76c 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm
@@ -15,8 +15,9 @@
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/material_components/activity_indicator.h"
 #import "ios/chrome/browser/ui/sync/sync_util.h"
@@ -86,12 +87,15 @@
 }
 
 @synthesize overlayType = _overlayType;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithFrame:(CGRect)frame
-                 browserState:(ios::ChromeBrowserState*)browserState {
+                 browserState:(ios::ChromeBrowserState*)browserState
+                   dispatcher:(id<BrowserCommands>)dispatcher {
   self = [super initWithFrame:frame];
   if (self) {
     _browserState = browserState;
+    _dispatcher = dispatcher;
     // Create and add container. Will be vertically and horizontally centered.
     _container = [[UIView alloc] initWithFrame:CGRectZero];
     [_container setTranslatesAutoresizingMaskIntoConstraints:NO];
@@ -242,10 +246,10 @@
       constraintEqualToAnchor:self.centerYAnchor
                      constant:kContainerOriginYOffset]
       .active = YES;
-  _signinPromoViewMediator =
-      [[SigninPromoViewMediator alloc] initWithBrowserState:_browserState];
-  _signinPromoViewMediator.accessPoint =
-      signin_metrics::AccessPoint::ACCESS_POINT_TAB_SWITCHER;
+  _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
+      initWithBrowserState:_browserState
+               accessPoint:signin_metrics::AccessPoint::
+                               ACCESS_POINT_TAB_SWITCHER];
   _signinPromoView.delegate = _signinPromoViewMediator;
   _signinPromoViewMediator.consumer = self;
   [[_signinPromoViewMediator createConfigurator]
@@ -464,17 +468,17 @@
 - (void)sendNewTabCommand:(id)sender {
   UIView* view = base::mac::ObjCCast<UIView>(sender);
   CGPoint center = [view.superview convertPoint:view.center toView:view.window];
-  NewTabCommand* command =
-      [[NewTabCommand alloc] initWithIncognito:NO originPoint:center];
-  [self chromeExecuteCommand:command];
+  OpenNewTabCommand* command =
+      [[OpenNewTabCommand alloc] initWithIncognito:NO originPoint:center];
+  [self.dispatcher openNewTab:command];
 }
 
 - (void)sendNewIncognitoTabCommand:(id)sender {
   UIView* view = base::mac::ObjCCast<UIView>(sender);
   CGPoint center = [view.superview convertPoint:view.center toView:view.window];
-  NewTabCommand* command =
-      [[NewTabCommand alloc] initWithIncognito:YES originPoint:center];
-  [self chromeExecuteCommand:command];
+  OpenNewTabCommand* command =
+      [[OpenNewTabCommand alloc] initWithIncognito:YES originPoint:center];
+  [self.dispatcher openNewTab:command];
 }
 
 - (void)recordMetrics {
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.h b/ios/chrome/browser/ui/tabs/tab_strip_controller.h
index b8ac80e..a5c7b11 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.h
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.h
@@ -7,9 +7,11 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol ApplicationCommands;
+@protocol BrowserCommands;
+@protocol FullScreenControllerDelegate;
 @class TabModel;
 @class TabView;
-@protocol FullScreenControllerDelegate;
 
 namespace TabStrip {
 enum Style { kStyleDark, kStyleIncognito };
@@ -35,6 +37,8 @@
 @property(nonatomic, assign) BOOL highlightsSelectedTab;
 @property(nonatomic, readonly, retain) UIView* view;
 
+@property(nonatomic, readonly, weak) id<BrowserCommands> dispatcher;
+
 // Used to check if the tabstrip is visible before starting an animation.
 @property(nonatomic, assign) id<FullScreenControllerDelegate>
     fullscreenDelegate;
@@ -42,6 +46,7 @@
 // Designated initializer.
 - (instancetype)initWithTabModel:(TabModel*)tabModel
                            style:(TabStrip::Style)style
+                      dispatcher:(id<BrowserCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index ae9c0b6..b7e2d3e 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -21,8 +21,9 @@
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_model_observer.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/fullscreen_controller.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/tab_switcher/tab_switcher_tab_strip_placeholder_view.h"
@@ -326,9 +327,11 @@
 @synthesize highlightsSelectedTab = _highlightsSelectedTab;
 @synthesize tabStripView = _tabStripView;
 @synthesize view = _view;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithTabModel:(TabModel*)tabModel
-                           style:(TabStrip::Style)style {
+                           style:(TabStrip::Style)style
+                      dispatcher:(id<BrowserCommands>)dispatcher {
   if ((self = [super init])) {
     _tabArray = [[NSMutableArray alloc] initWithCapacity:10];
     _closingTabs = [[NSMutableSet alloc] initWithCapacity:5];
@@ -336,6 +339,7 @@
     _tabModel = tabModel;
     [_tabModel addObserver:self];
     _style = style;
+    _dispatcher = dispatcher;
 
     // |self.view| setup.
     CGRect tabStripFrame = [UIApplication sharedApplication].keyWindow.bounds;
@@ -583,9 +587,10 @@
 - (void)sendNewTabCommand {
   CGPoint center = [_buttonNewTab.superview convertPoint:_buttonNewTab.center
                                                   toView:_buttonNewTab.window];
-  NewTabCommand* command =
-      [[NewTabCommand alloc] initWithIncognito:_isIncognito originPoint:center];
-  [_view chromeExecuteCommand:command];
+  OpenNewTabCommand* command =
+      [[OpenNewTabCommand alloc] initWithIncognito:_isIncognito
+                                       originPoint:center];
+  [self.dispatcher openNewTab:command];
 }
 
 - (void)tabTapped:(id)sender {
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
index c76170f..914781e8 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller_unittest.mm
@@ -127,7 +127,8 @@
     tab2_ = tab2;
     controller_ =
         [[TabStripController alloc] initWithTabModel:(TabModel*)tabModel_
-                                               style:TabStrip::kStyleDark];
+                                               style:TabStrip::kStyleDark
+                                          dispatcher:nil];
 
     // Force the view to load.
     UIWindow* window = [[UIWindow alloc] initWithFrame:CGRectZero];
diff --git a/ios/chrome/browser/ui/toolbar/new_tab_button.h b/ios/chrome/browser/ui/toolbar/new_tab_button.h
index bbad6227..f94b2e3d 100644
--- a/ios/chrome/browser/ui/toolbar/new_tab_button.h
+++ b/ios/chrome/browser/ui/toolbar/new_tab_button.h
@@ -8,10 +8,7 @@
 #import <UIKit/UIKit.h>
 
 // UIButton subclass used for the New Tab button in the phone switcher toolbar
-// and the tablet no-tabs toolbar. A NewTabButton has a custom background rect
-// and by default will call send a NewTabCommand via its (derived)
-// -chromeExecuteCommand method on |TouchUpInside|. Instances can add further
-// targets.
+// and the tablet no-tabs toolbar. A NewTabButton has a custom background rect.
 @interface NewTabButton : UIButton
 // Whether the button opens incognito tabs or not; setting this property changes
 // the button's behavior, updating its tag to
diff --git a/ios/chrome/browser/ui/toolbar/new_tab_button.mm b/ios/chrome/browser/ui/toolbar/new_tab_button.mm
index e3178d9..4c06605 100644
--- a/ios/chrome/browser/ui/toolbar/new_tab_button.mm
+++ b/ios/chrome/browser/ui/toolbar/new_tab_button.mm
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/image_util.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -36,10 +36,6 @@
   if (self = [super initWithFrame:frame]) {
     self.incognito = NO;
 
-    [self addTarget:self
-                  action:@selector(sendNewTabCommand)
-        forControlEvents:UIControlEventTouchUpInside];
-
     [self
         setContentEdgeInsets:UIEdgeInsetsMakeDirected(0, kContentInset, 0, 0)];
     [self setContentHorizontalAlignment:
@@ -85,12 +81,4 @@
   }
 }
 
-- (void)sendNewTabCommand {
-  CGPoint center = [self.superview convertPoint:self.center toView:self.window];
-  NewTabCommand* command =
-      [[NewTabCommand alloc] initWithIncognito:self.isIncognito
-                                   originPoint:center];
-  [self chromeExecuteCommand:command];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/tools_menu/new_tab_menu_view_item.mm b/ios/chrome/browser/ui/tools_menu/new_tab_menu_view_item.mm
index f5d4157..6cb39ce 100644
--- a/ios/chrome/browser/ui/tools_menu/new_tab_menu_view_item.mm
+++ b/ios/chrome/browser/ui/tools_menu/new_tab_menu_view_item.mm
@@ -4,7 +4,8 @@
 
 #import "ios/chrome/browser/ui/tools_menu/new_tab_menu_view_item.h"
 
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -20,11 +21,14 @@
   return NO;
 }
 
-- (id)command {
+- (void)executeCommandWithDispatcher:
+    (id<ApplicationCommands, BrowserCommands>)dispatcher {
   UIView* view = self.tableViewCell;
   CGPoint center = [view.superview convertPoint:view.center toView:view.window];
-  return [[NewTabCommand alloc] initWithIncognito:self.isIncognito
-                                      originPoint:center];
+  OpenNewTabCommand* command =
+      [[OpenNewTabCommand alloc] initWithIncognito:self.isIncognito
+                                       originPoint:center];
+  [dispatcher openNewTab:command];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
index 1b0f4e3..82df04d 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
@@ -48,6 +48,8 @@
   TOOLS_SHARE_ITEM = -5,
   TOOLS_MENU_ITEM = -6,
   TOOLS_SETTINGS_ITEM = -7,
+  TOOLS_NEW_TAB_ITEM = -8,
+  TOOLS_NEW_INCOGNITO_TAB_ITEM = -9,
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLS_MENU_TOOLS_MENU_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
index f50ea51e..899c6d4 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
@@ -37,10 +37,10 @@
 const MenuItemInfo itemInfoList[kToolsMenuNumberOfItems] = {
     // clang-format off
   { IDS_IOS_TOOLS_MENU_NEW_TAB,           kToolsMenuNewTabId,
-    IDC_NEW_TAB, nullptr,                 ToolbarTypeAll,
+    TOOLS_NEW_TAB_ITEM, nullptr,          ToolbarTypeAll,
     0,                                    [NewTabMenuViewItem class] },
   { IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB, kToolsMenuNewIncognitoTabId,
-    IDC_NEW_INCOGNITO_TAB, nullptr,       ToolbarTypeAll,
+    TOOLS_NEW_INCOGNITO_TAB_ITEM, nullptr,ToolbarTypeAll,
     0,                                    [NewIncognitoTabMenuViewItem class] },
   { IDS_IOS_TOOLS_MENU_CLOSE_ALL_TABS,    kToolsMenuCloseAllTabsId,
     IDC_CLOSE_ALL_TABS, nullptr,          ToolbarTypeSwitcheriPhone,
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
index 29697681..2c56c09d 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -568,15 +568,9 @@
         DCHECK([menuItem tag]);
         [_delegate commandWasSelected:[menuItem tag]];
         if ([menuItem tag] > 0) {
-          [self chromeExecuteCommand:[menuItem command]];
+          [self chromeExecuteCommand:menuItem];
         } else {
-          DCHECK([menuItem selector]);
-          DCHECK([self.dispatcher respondsToSelector:[menuItem selector]]);
-// TODO(crbug.com/738881): Find a better way to call these methods.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-          [self.dispatcher performSelector:[menuItem selector]];
-#pragma clang diagnostic pop
+          [menuItem executeCommandWithDispatcher:self.dispatcher];
         }
       });
 }
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h
index d2bbe37..0219332 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol ApplicationCommands;
+@protocol BrowserCommands;
 @class ToolsMenuViewCell;
 
 @interface ToolsMenuViewItem : NSObject
@@ -25,9 +27,10 @@
                          selector:(SEL)selector
                           command:(int)commandID;
 
-// The object that should be sent via -chromeExecuteCommand: when this item is
-// tapped.
-- (id)command;
+// Execute the command associated with this item using |dispatcher|. |selector|
+// must be defined on the receiver.
+- (void)executeCommandWithDispatcher:
+    (id<ApplicationCommands, BrowserCommands>)dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
index 3bf9ef1..62ff62bb 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
@@ -6,6 +6,8 @@
 
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -50,8 +52,7 @@
                          selector:(SEL)selector
                           command:(int)commandID {
   // Only commandIDs < 0 should have associated selectors.
-  DCHECK((commandID >= 0 && selector == nullptr) ||
-         (commandID < 0 && selector != nullptr));
+  DCHECK(selector == nullptr || commandID < 0);
   ToolsMenuViewItem* menuItem = [[self alloc] init];
   [menuItem setAccessibilityLabel:title];
   [menuItem setAccessibilityIdentifier:accessibilityIdentifier];
@@ -62,9 +63,15 @@
   return menuItem;
 }
 
-- (id)command {
-  // Default is to return |self|.
-  return self;
+- (void)executeCommandWithDispatcher:
+    (id<ApplicationCommands, BrowserCommands>)dispatcher {
+  DCHECK(self.selector);
+  DCHECK([dispatcher respondsToSelector:self.selector]);
+// TODO(crbug.com/738881): Find a better way to call these methods.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+  [dispatcher performSelector:self.selector];
+#pragma clang diagnostic pop
 }
 
 @end
diff --git a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
index b77bb75..9df29c6 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
@@ -182,10 +182,10 @@
     case IDC_HELP_PAGE_VIA_MENU:
       base::RecordAction(UserMetricsAction("MobileMenuHelp"));
       break;
-    case IDC_NEW_INCOGNITO_TAB:
+    case TOOLS_NEW_INCOGNITO_TAB_ITEM:
       base::RecordAction(UserMetricsAction("MobileMenuNewIncognitoTab"));
       break;
-    case IDC_NEW_TAB:
+    case TOOLS_NEW_TAB_ITEM:
       base::RecordAction(UserMetricsAction("MobileMenuNewTab"));
       break;
     case TOOLS_SETTINGS_ITEM:
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn
index 1c13ffa1..5abfdb9 100644
--- a/ios/chrome/test/app/BUILD.gn
+++ b/ios/chrome/test/app/BUILD.gn
@@ -71,6 +71,7 @@
     "//ios/chrome/browser/ui/ntp:ntp_controller",
     "//ios/chrome/browser/ui/stack_view",
     "//ios/chrome/browser/ui/static_content",
+    "//ios/chrome/browser/ui/tab_switcher",
     "//ios/chrome/browser/ui/tabs",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/signin:test_support",
diff --git a/ios/chrome/test/app/chrome_test_util.h b/ios/chrome/test/app/chrome_test_util.h
index 2dda8a4..ebaeca4 100644
--- a/ios/chrome/test/app/chrome_test_util.h
+++ b/ios/chrome/test/app/chrome_test_util.h
@@ -43,8 +43,12 @@
 NSUInteger GetRegisteredKeyCommandsCount();
 
 // Returns the dispatcher for the main BVC.
+// TODO(crbug.com/738881): Use DispatcherForActiveViewController() instead.
 id<BrowserCommands> BrowserCommandDispatcherForMainBVC();
 
+// Returns the dispatcher for the active view controller.
+id<BrowserCommands> DispatcherForActiveViewController();
+
 // Runs |command| using the active view controller.
 void RunCommandWithActiveViewController(GenericChromeCommand* command);
 
diff --git a/ios/chrome/test/app/chrome_test_util.mm b/ios/chrome/test/app/chrome_test_util.mm
index 3a14989..ae040f0 100644
--- a/ios/chrome/test/app/chrome_test_util.mm
+++ b/ios/chrome/test/app/chrome_test_util.mm
@@ -25,6 +25,7 @@
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #import "ios/chrome/browser/ui/main/main_view_controller.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_controller.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_switcher.h"
 #import "ios/web/public/test/native_controller_test_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -139,6 +140,19 @@
   return mainBVC.dispatcher;
 }
 
+id<BrowserCommands> DispatcherForActiveViewController() {
+  UIViewController* vc = GetActiveViewController();
+  BrowserViewController* bvc = base::mac::ObjCCast<BrowserViewController>(vc);
+  if (bvc)
+    return bvc.dispatcher;
+  if ([vc conformsToProtocol:@protocol(TabSwitcher)]) {
+    UIViewController<TabSwitcher>* tabSwitcher =
+        static_cast<UIViewController<TabSwitcher>*>(vc);
+    return tabSwitcher.dispatcher;
+  }
+  return nil;
+}
+
 void RunCommandWithActiveViewController(GenericChromeCommand* command) {
   [GetActiveViewController() chromeExecuteCommand:command];
 }
diff --git a/ios/chrome/test/app/tab_test_util.mm b/ios/chrome/test/app/tab_test_util.mm
index 10f549bf..a754dec9 100644
--- a/ios/chrome/test/app/tab_test_util.mm
+++ b/ios/chrome/test/app/tab_test_util.mm
@@ -15,9 +15,8 @@
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_private.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
-#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/tabs/tab_strip_controller_private.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/testing/wait_util.h"
@@ -51,17 +50,15 @@
 
 void OpenNewTab() {
   @autoreleasepool {  // Make sure that all internals are deallocated.
-    GenericChromeCommand* command =
-        [[NewTabCommand alloc] initWithIncognito:NO];
-    chrome_test_util::RunCommandWithActiveViewController(command);
+    OpenNewTabCommand* command = [OpenNewTabCommand command];
+    [chrome_test_util::DispatcherForActiveViewController() openNewTab:command];
   }
 }
 
 void OpenNewIncognitoTab() {
   @autoreleasepool {  // Make sure that all internals are deallocated.
-    GenericChromeCommand* command =
-        [[NewTabCommand alloc] initWithIncognito:YES];
-    chrome_test_util::RunCommandWithActiveViewController(command);
+    OpenNewTabCommand* command = [OpenNewTabCommand incognitoTabCommand];
+    [chrome_test_util::DispatcherForActiveViewController() openNewTab:command];
   }
 }
 
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 92329d3b1..f447aa3 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -141,7 +141,8 @@
   // tabs section.
   TabSwitcherPanelOverlayView* overlayView =
       [[TabSwitcherPanelOverlayView alloc] initWithFrame:self.tabs.bounds
-                                            browserState:nil];
+                                            browserState:nil
+                                              dispatcher:nil];
   overlayView.overlayType =
       TabSwitcherPanelOverlayType::OVERLAY_PANEL_USER_NO_OPEN_TABS;
   overlayView.autoresizingMask =
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 38051f4e..5079a0ca 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -55,6 +55,7 @@
     "ENABLE_REPORTING=$enable_reporting",
     "ENABLE_WEBSOCKETS=$enable_websockets",
     "USE_BYTE_CERTS=$use_byte_certs",
+    "INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST=$include_transport_security_state_preload_list",
   ]
 }
 
@@ -285,6 +286,7 @@
     "http/http_vary_data.h",
     "http/transport_security_state.cc",
     "http/transport_security_state.h",
+    "http/transport_security_state_source.cc",
     "http/transport_security_state_source.h",
     "log/net_log.cc",
     "log/net_log.h",
@@ -359,11 +361,14 @@
     "//base",
     "//net/base/registry_controlled_domains",
     "//net/data/ssl/certificate_transparency:ct_log_list",
-    "//net/http:generate_transport_security_state",
     "//third_party/protobuf:protobuf_lite",
     "//url:url_features",
   ]
 
+  if (include_transport_security_state_preload_list) {
+    deps += [ "//net/http:generate_transport_security_state" ]
+  }
+
   public_deps = [
     ":net_quic_proto",
     ":traffic_annotation",
diff --git a/net/features.gni b/net/features.gni
index ab189559..c54da53 100644
--- a/net/features.gni
+++ b/net/features.gni
@@ -31,4 +31,12 @@
 
   # Reporting not used on iOS.
   enable_reporting = !is_ios
+
+  # Includes the transport security state preload list. This list includes
+  # mechanisms (e.g. HSTS, HPKP) to enforce trusted connections to a significant
+  # set of hardcoded domains. While this list has a several hundred KB of binary
+  # size footprint, this flag should not be disabled unless the embedder is
+  # willing to take the responsibility to make sure that all important
+  # connections use HTTPS.
+  include_transport_security_state_preload_list = true
 }
diff --git a/net/http/BUILD.gn b/net/http/BUILD.gn
index e5106193..8699aeff 100644
--- a/net/http/BUILD.gn
+++ b/net/http/BUILD.gn
@@ -23,6 +23,7 @@
 compiled_action_foreach("transport_security_state_unittest_data") {
   tool = "//net/tools/transport_security_state_generator"
   sources = [
+    "transport_security_state_static_unittest0.json",
     "transport_security_state_static_unittest1.json",
     "transport_security_state_static_unittest2.json",
     "transport_security_state_static_unittest3.json",
diff --git a/net/http/http_security_headers_unittest.cc b/net/http/http_security_headers_unittest.cc
index 7f1148a..2ea5d0a 100644
--- a/net/http/http_security_headers_unittest.cc
+++ b/net/http/http_security_headers_unittest.cc
@@ -652,7 +652,13 @@
   TestValidPKPHeaders(HASH_VALUE_SHA256);
 }
 
-TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+#define MAYBE_UpdateDynamicPKPOnly DISABLED_UpdateDynamicPKPOnly
+#else
+#define MAYBE_UpdateDynamicPKPOnly UpdateDynamicPKPOnly
+#endif
+
+TEST_F(HttpSecurityHeadersTest, MAYBE_UpdateDynamicPKPOnly) {
   TransportSecurityState state;
   TransportSecurityState::STSState static_sts_state;
   TransportSecurityState::PKPState static_pkp_state;
@@ -721,7 +727,13 @@
       base::ContainsValue(new_dynamic_pkp_state.spki_hashes, backup_hash));
 }
 
-TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPMaxAge0) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+#define MAYBE_UpdateDynamicPKPMaxAge0 DISABLED_UpdateDynamicPKPMaxAge0
+#else
+#define MAYBE_UpdateDynamicPKPMaxAge0 UpdateDynamicPKPMaxAge0
+#endif
+
+TEST_F(HttpSecurityHeadersTest, MAYBE_UpdateDynamicPKPMaxAge0) {
   TransportSecurityState state;
   TransportSecurityState::STSState static_sts_state;
   TransportSecurityState::PKPState static_pkp_state;
@@ -799,7 +811,13 @@
 // Tests that when a static HSTS and a static HPKP entry are present, adding a
 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
 // dynamic HPKP entry could not affect the HSTS entry for the site.
-TEST_F(HttpSecurityHeadersTest, NoClobberPins) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+#define MAYBE_NoClobberPins DISABLED_NoClobberPins
+#else
+#define MAYBE_NoClobberPins NoClobberPins
+#endif
+
+TEST_F(HttpSecurityHeadersTest, MAYBE_NoClobberPins) {
   TransportSecurityState state;
   TransportSecurityState::STSState sts_state;
   TransportSecurityState::PKPState pkp_state;
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index d4d6f49..4ffe9e8 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -40,16 +40,22 @@
 namespace {
 
 #include "net/http/transport_security_state_ct_policies.inc"
+
+#if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
 #include "net/http/transport_security_state_static.h"
+// Points to the active transport security state source.
+const TransportSecurityStateSource* const kDefaultHSTSSource = &kHSTSSource;
+#else
+const TransportSecurityStateSource* const kDefaultHSTSSource = nullptr;
+#endif
+
+const TransportSecurityStateSource* g_hsts_source = kDefaultHSTSSource;
 
 // Parameters for remembering sent HPKP and Expect-CT reports.
 const size_t kMaxReportCacheEntries = 50;
 const int kTimeToRememberReportsMins = 60;
 const size_t kReportCacheKeyLength = 16;
 
-// Points to the active transport security state source.
-const TransportSecurityStateSource* g_hsts_source = &kHSTSSource;
-
 // Override for CheckCTRequirements() for unit tests. Possible values:
 //  -1: Unless a delegate says otherwise, do not require CT.
 //   0: Use the default implementation (e.g. production)
@@ -637,6 +643,11 @@
 }
 
 bool DecodeHSTSPreload(const std::string& hostname, PreloadResult* out) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+  if (g_hsts_source == nullptr)
+    return false;
+#endif
+
   bool found;
   if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
     DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname "
@@ -734,7 +745,7 @@
 
 void SetTransportSecurityStateSourceForTesting(
     const TransportSecurityStateSource* source) {
-  g_hsts_source = source ? source : &kHSTSSource;
+  g_hsts_source = source ? source : kDefaultHSTSSource;
 }
 
 TransportSecurityState::TransportSecurityState()
diff --git a/net/http/transport_security_state_source.cc b/net/http/transport_security_state_source.cc
new file mode 100644
index 0000000..587c5dfd
--- /dev/null
+++ b/net/http/transport_security_state_source.cc
@@ -0,0 +1,11 @@
+// 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 "net/http/transport_security_state_source.h"
+
+namespace net {
+
+const char kNoReportURI[] = "";
+
+}  // namespace net
diff --git a/net/http/transport_security_state_source.h b/net/http/transport_security_state_source.h
index 206746d..2c065db 100644
--- a/net/http/transport_security_state_source.h
+++ b/net/http/transport_security_state_source.h
@@ -5,8 +5,16 @@
 #ifndef NET_HTTP_TRANSPORT_SECURITY_STATE_SOURCE_H_
 #define NET_HTTP_TRANSPORT_SECURITY_STATE_SOURCE_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/base/net_export.h"
+
 namespace net {
 
+// kNoReportURI is a placeholder for when a pinset does not have a report URI.
+NET_EXPORT_PRIVATE extern const char kNoReportURI[];
+
 struct TransportSecurityStateSource {
   struct Pinset {
     const char* const* const accepted_pins;
diff --git a/net/http/transport_security_state_static.template b/net/http/transport_security_state_static.template
index fd73c127..6ec865c5 100644
--- a/net/http/transport_security_state_static.template
+++ b/net/http/transport_security_state_static.template
@@ -24,9 +24,6 @@
     nullptr,
 };
 
-// kNoReportURI is a placeholder for when a pinset does not have a report URI.
-static const char kNoReportURI[] = "";
-
 [[ACCEPTABLE_CERTS]]
 
 static const net::TransportSecurityStateSource::Pinset kPinsets[] = [[PINSETS]];
diff --git a/net/http/transport_security_state_static_unittest.template b/net/http/transport_security_state_static_unittest.template
index 8f1a704c1..633ec78b 100644
--- a/net/http/transport_security_state_static_unittest.template
+++ b/net/http/transport_security_state_static_unittest.template
@@ -20,8 +20,6 @@
     NULL,
 };
 
-static const char kNoReportURI[] = "";
-
 [[ACCEPTABLE_CERTS]]
 
 static const struct net::TransportSecurityStateSource::Pinset kPinsets[] = [[PINSETS]];
diff --git a/net/http/transport_security_state_static_unittest0.json b/net/http/transport_security_state_static_unittest0.json
new file mode 100644
index 0000000..8c89c38
--- /dev/null
+++ b/net/http/transport_security_state_static_unittest0.json
@@ -0,0 +1,175 @@
+// 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.
+
+// This is a HSTS preloaded list used by the unittests to supply a custom
+// preload list when the default one isn't available. For more information on
+// the content and format see the comments in
+// transport_security_state_static.json.
+
+{
+  "pinsets": [
+    {
+      "name": "test",
+      "static_spki_hashes": [
+        "TestSPKI1"
+      ]
+    },
+    {
+      "name": "google",
+      "static_spki_hashes": [
+        "TestSPKI1"
+      ],
+      "report_uri": "http://clients3.google.com/cert_upload_json"
+    },
+    {
+      "name": "tor",
+      "static_spki_hashes": [
+        "TestSPKI1"
+      ]
+    },
+    {
+      "name": "twitterCom",
+      "static_spki_hashes": [
+        "TestSPKI1"
+      ],
+      "report_uri": "http://l.twimg.com/i/hpkp_report"
+    },
+    {
+      "name": "twitterCDN",
+      "static_spki_hashes": [
+        "TestSPKI1"
+      ],
+      "report_uri": "http://l.twimg.com/i/hpkp_report"
+    },
+    {
+      "name": "facebook",
+      "static_spki_hashes": [
+        "TestSPKI2"
+      ]
+    }
+  ],
+
+  "entries": [
+    { "name": "pinningtest.appspot.com", "include_subdomains": true, "pins": "test" },
+    { "name": "pinning-test.badssl.com", "include_subdomains": true, "pins": "test" },
+    { "name": "preloaded-expect-ct.badssl.com", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
+    { "name": "preloaded-expect-staple.badssl.com", "expect_staple": true, "expect_staple_report_uri": "https://report.badssl.com/expect-staple" },
+    { "name": "preloaded-expect-staple-include-subdomains.badssl.com", "expect_staple": true, "expect_staple_report_uri": "https://report.badssl.com/expect-staple", "include_subdomains_for_expect_staple": true },
+    { "name": "google", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "mail.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
+    { "name": "accounts.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "appengine.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "checkout.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "chrome.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "docs.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "encrypted.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "hostedtalkgadget.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "play.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "plus.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "profiles.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "sites.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "spreadsheets.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "talkgadget.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "talk.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "wallet.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "apis.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "drive.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "gmail.com", "mode": "force-https", "pins": "google" },
+    { "name": "googlecode.com", "include_subdomains": true, "pins": "google" },
+    { "name": "googlemail.com", "mode": "force-https", "pins": "google" },
+    { "name": "googleplex.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "groups.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "market.android.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "www.gmail.com", "mode": "force-https", "pins": "google" },
+    { "name": "www.googlemail.com", "mode": "force-https", "pins": "google" },
+    { "name": "google-analytics.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "chart.apis.google.com", "include_subdomains": true, "pins": "google" },
+    { "name": "appspot.com", "include_subdomains": true, "pins": "google" },
+    { "name": "doubleclick.net", "include_subdomains": true, "pins": "google" },
+    { "name": "googleadservices.com", "include_subdomains": true, "pins": "google" },
+    { "name": "googleapis.com", "include_subdomains": true, "pins": "google" },
+    { "name": "google.com", "include_subdomains": true, "pins": "google" },
+    { "name": "googlegroups.com", "include_subdomains": true, "pins": "google", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
+    { "name": "googlesyndication.com", "include_subdomains": true, "pins": "google" },
+    { "name": "googleusercontent.com", "include_subdomains": true, "pins": "google" },
+    { "name": "gstatic.com", "include_subdomains": true, "pins": "google" },
+    { "name": "youtube.com", "include_subdomains": true, "pins": "google" },
+    { "name": "ytimg.com", "include_subdomains": true, "pins": "google" },
+    { "name": "learn.doubleclick.net", "include_subdomains": true },
+    { "name": "www.paypal.com", "mode": "force-https" },
+    { "name": "paypal.com", "mode": "force-https" },
+    { "name": "www.elanex.biz", "mode": "force-https" },
+    { "name": "sunshinepress.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "www.noisebridge.net", "mode": "force-https" },
+    { "name": "neg9.org", "mode": "force-https" },
+    { "name": "riseup.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "factor.cc", "mode": "force-https" },
+    { "name": "members.mayfirst.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "support.mayfirst.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "id.mayfirst.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lists.mayfirst.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aladdinschools.appspot.com", "mode": "force-https" },
+    { "name": "ottospora.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "www.paycheckrecords.com", "mode": "force-https" },
+    { "name": "lastpass.com", "mode": "force-https" },
+    { "name": "www.lastpass.com", "mode": "force-https" },
+    { "name": "keyerror.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "entropia.de", "mode": "force-https" },
+    { "name": "www.entropia.de", "mode": "force-https" },
+    { "name": "romab.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "logentries.com", "mode": "force-https" },
+    { "name": "www.logentries.com", "mode": "force-https" },
+    { "name": "stripe.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cloudsecurityalliance.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "login.sapo.pt", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mattmccutchen.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "betnet.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uprotect.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "squareup.com", "mode": "force-https" },
+    { "name": "cert.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "simon.butcher.name", "include_subdomains": true, "mode": "force-https" },
+    { "name": "linx.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dropcam.com", "mode": "force-https" },
+    { "name": "www.dropcam.com", "mode": "force-https" },
+    { "name": "ebanking.indovinabank.com.vn", "include_subdomains": true, "mode": "force-https" },
+    { "name": "epoxate.com", "mode": "force-https" },
+    { "name": "torproject.org", "mode": "force-https", "pins": "tor" },
+    { "name": "blog.torproject.org", "include_subdomains": true, "mode": "force-https", "pins": "tor" },
+    { "name": "check.torproject.org", "include_subdomains": true, "mode": "force-https", "pins": "tor" },
+    { "name": "www.torproject.org", "include_subdomains": true, "mode": "force-https", "pins": "tor" },
+    { "name": "www.moneybookers.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ledgerscope.net", "mode": "force-https" },
+    { "name": "www.ledgerscope.net", "mode": "force-https" },
+    { "name": "app.recurly.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "api.recurly.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "greplin.com", "mode": "force-https" },
+    { "name": "www.greplin.com", "mode": "force-https" },
+    { "name": "luneta.nearbuysystems.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ubertt.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pixi.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "grepular.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mydigipass.com", "mode": "force-https" },
+    { "name": "www.mydigipass.com", "mode": "force-https" },
+    { "name": "developer.mydigipass.com", "mode": "force-https" },
+    { "name": "www.developer.mydigipass.com", "mode": "force-https" },
+    { "name": "sandbox.mydigipass.com", "mode": "force-https" },
+    { "name": "www.sandbox.mydigipass.com", "mode": "force-https" },
+    { "name": "bigshinylock.minazo.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crate.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "twitter.com", "mode": "force-https", "pins": "twitterCom" },
+    { "name": "www.twitter.com", "include_subdomains": true, "mode": "force-https", "pins": "twitterCom" },
+    { "name": "api.twitter.com", "include_subdomains": true, "pins": "twitterCDN" },
+    { "name": "oauth.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+    { "name": "mobile.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+    { "name": "dev.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+    { "name": "business.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+    { "name": "platform.twitter.com", "include_subdomains": true, "pins": "twitterCDN" },
+    { "name": "twimg.com", "include_subdomains": true, "pins": "twitterCDN" },
+    { "name": "facebook.com", "mode": "force-https", "include_subdomains_for_pinning": true, "pins": "facebook" },
+    { "name": "www.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
+    { "name": "recurly.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crypto.is", "include_subdomains": true, "mode": "force-https", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" }
+  ]
+}
+
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 7fe9642f..3fcb7dd3 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -33,6 +33,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
+#include "net/net_features.h"
 #include "net/ssl/ssl_info.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -43,6 +44,10 @@
 
 namespace {
 
+namespace test0 {
+#include "net/http/transport_security_state_static_unittest0.h"
+}
+
 namespace test1 {
 #include "net/http/transport_security_state_static_unittest1.h"
 }
@@ -398,6 +403,12 @@
 
 class TransportSecurityStateTest : public testing::Test {
  public:
+  TransportSecurityStateTest() {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+    SetTransportSecurityStateSourceForTesting(&test0::kHSTSSource);
+#endif
+  }
+
   ~TransportSecurityStateTest() override {
     SetTransportSecurityStateSourceForTesting(nullptr);
   }
@@ -1356,7 +1367,15 @@
   return true;
 }
 
-TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
+// This test depends on the pinset of tor.
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+#define MAYBE_PinValidationWithoutRejectedCerts \
+  DISABLED_PinValidationWithoutRejectedCerts
+#else
+#define MAYBE_PinValidationWithoutRejectedCerts \
+  PinValidationWithoutRejectedCerts
+#endif
+TEST_F(TransportSecurityStateTest, MAYBE_PinValidationWithoutRejectedCerts) {
   HashValueVector good_hashes, bad_hashes;
 
   for (size_t i = 0; kGoodPath[i]; i++) {
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 083cd24..04d8a45 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -155,6 +155,10 @@
 
 namespace {
 
+namespace test0 {
+#include "net/http/transport_security_state_static_unittest0.h"
+}
+
 const base::string16 kChrome(ASCIIToUTF16("chrome"));
 const base::string16 kSecret(ASCIIToUTF16("secret"));
 const base::string16 kUser(ASCIIToUTF16("user"));
@@ -6747,6 +6751,9 @@
 
 // Tests that Expect CT headers are processed correctly.
 TEST_F(URLRequestTestHTTP, ExpectCTHeader) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+  SetTransportSecurityStateSourceForTesting(&test0::kHSTSSource);
+#endif
   EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
   https_test_server.SetSSLConfig(
       net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
@@ -9215,6 +9222,9 @@
 // the |certificate_errors_are_fatal| flag correctly. This flag will cause
 // the interstitial to be fatal.
 TEST_F(HTTPSRequestTest, HTTPSPreloadedHSTSTest) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+  SetTransportSecurityStateSourceForTesting(&test0::kHSTSSource);
+#endif
   EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
   test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
   test_server.ServeFilesFromSourceDirectory("net/data/ssl");
@@ -9254,6 +9264,9 @@
 // This tests that cached HTTPS page loads do not cause any updates to the
 // TransportSecurityState.
 TEST_F(HTTPSRequestTest, HTTPSErrorsNoClobberTSSTest) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+  SetTransportSecurityStateSourceForTesting(&test0::kHSTSSource);
+#endif
   // The actual problem -- CERT_MISMATCHED_NAME in this case -- doesn't
   // matter. It just has to be any error.
   EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
@@ -10157,6 +10170,9 @@
 }
 
 TEST_F(HTTPSOCSPTest, ExpectStapleReportSentOnMissing) {
+#if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
+  SetTransportSecurityStateSourceForTesting(&test0::kHSTSSource);
+#endif
   EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
   https_test_server.SetSSLConfig(
       net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index 9fa5daa..1ec93f3 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -238,6 +238,7 @@
       // TODO(hjd): Change to NOTREACHED when crbug.com/739710 is fixed.
       VLOG(1) << "Couldn't find a PID for client \"" << client_identity.name()
               << "." << client_identity.instance() << "\"";
+      continue;
     }
     request->responses[client].process_id = pid;
     request->responses[client].process_type = kv.second->process_type;
@@ -265,6 +266,12 @@
   for (const auto& kv : clients_) {
     service_manager::Identity client_identity = kv.second->identity;
     const base::ProcessId pid = GetProcessIdForClientIdentity(client_identity);
+    if (pid == base::kNullProcessId) {
+      // TODO(hjd): Change to NOTREACHED when crbug.com/739710 is fixed.
+      VLOG(1) << "Couldn't find a PID for client \"" << client_identity.name()
+              << "." << client_identity.instance() << "\"";
+      continue;
+    }
     pids.push_back(pid);
     if (kv.second->process_type == mojom::ProcessType::BROWSER) {
       browser_client = kv.first;
@@ -416,7 +423,8 @@
   std::map<base::ProcessId, mojom::ProcessMemoryDumpPtr> finalized_pmds;
   for (auto& response : request->responses) {
     const base::ProcessId pid = response.second.process_id;
-    DCHECK(!finalized_pmds.count(pid));
+    DCHECK(!finalized_pmds.count(pid))
+        << "Received PID: " << pid << " more than once.";
 
     // The dump might be nullptr if the client crashed / disconnected before
     // replying.
diff --git a/testing/buildbot/filters/mojo.fyi.browser_tests.filter b/testing/buildbot/filters/mojo.fyi.browser_tests.filter
index ba0b591..e69843a 100644
--- a/testing/buildbot/filters/mojo.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.browser_tests.filter
@@ -1,15 +1,8 @@
+BrowserTest.*
+
 # Failing test
 -BrowserTest.FullscreenBookmarkBar
 
-# Flaky tests -crbug.com/707195
--BrowserTest.AboutVersion
--BrowserTest.CanDuplicateTab
--BrowserTest.ClearPendingOnFailUnlessNT
--BrowserTest.DefaultMediaDevices
--BrowserTest.GetSizeForNewRenderView
--BrowserTest.JavascriptAlertActivatesTab
--BrowserTest.Title
-
 # Trying to whitelist
 BrowserDialogTest.Invoke
 CastSessionBrowserTest.CreateAndDestroy
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index f27a391..f70c2ba 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -184,10 +184,6 @@
 
 crbug.com/258896 animations/direction-and-fill/animation-direction-reverse-fill-mode.html [ Slow ]
 
-# This test has to generate >250MB of data which takes ~6s in both release and debug.
-crbug.com/420240 http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html [ Slow ]
-crbug.com/420240 virtual/mojo-loading/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html [ Slow ]
-
 # These html5lib tests are generated tests that test a huge amount of permutations so they need a bit more time.
 crbug.com/453312 html5lib/generated/run-doctype01-data.html [ Slow ]
 crbug.com/453312 html5lib/generated/run-domjs-unsafe-data.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 297fb4e..e7fea2a3 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -750,8 +750,6 @@
 crbug.com/432129 html/marquee/marquee-scroll.html [ Failure Pass ]
 crbug.com/326139 crbug.com/390125 media/video-frame-accurate-seek.html [ Failure Pass ]
 crbug.com/248938 virtual/threaded/animations/stability/animation-iteration-event-destroy-renderer.html [ Pass Timeout ]
-crbug.com/446385 [ Win7 Debug ] http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html [ Crash Pass Timeout ]
-crbug.com/446385 [ Win7 Debug ] virtual/mojo-loading/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html [ Crash Pass Timeout ]
 crbug.com/248938 virtual/threaded/animations/dynamic-stylesheet-loading.html [ Pass Failure Timeout ]
 crbug.com/421283 html/marquee/marquee-scrollamount.html [ Pass Failure ]
 
@@ -1959,7 +1957,7 @@
 crbug.com/626703 external/wpt/wasm/wasm_indexeddb_test.html [ Timeout ]
 crbug.com/626703 external/wpt/wasm/wasm_local_iframe_test.html [ Failure ]
 crbug.com/626703 external/wpt/wasm/wasm_serialization_tests.html [ Failure ]
-crbug.com/626703 external/wpt/wasm/wasm_service_worker_test.html [ Failure ]
+crbug.com/626703 external/wpt/wasm/wasm_service_worker_test.https.html [ Failure ]
 crbug.com/626703 external/wpt/web-animations/animation-model/animation-types/accumulation-per-property.html [ Timeout ]
 crbug.com/626703 external/wpt/webaudio/the-audio-api/the-audioparam-interface/idl-test.html [ Timeout ]
 crbug.com/626703 external/wpt/webaudio/the-audio-api/the-audioparam-interface/retrospective-exponentialRampToValueAtTime.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.https.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.html
rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.https.html
index 9d4afb8..e350ed95 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.https.html
@@ -2,7 +2,8 @@
 <title>Service Worker: postMessage with wasm</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/serviceworker/resources/test-helpers.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
 <script>
   promise_test(async test => {
     var registration = await service_worker_unregister_and_register(
diff --git a/third_party/WebKit/LayoutTests/http/tests/payments/abort-payment-event.html b/third_party/WebKit/LayoutTests/http/tests/payments/abort-payment-event.html
new file mode 100644
index 0000000..10a48c55
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/payments/abort-payment-event.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Payment App: Tests for AbortPaymentEvent</title>
+<link rel="help" href="https://github.com/w3c/payment-handler/pull/170">
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../serviceworker/resources/test-helpers.js"></script>
+<script>
+'use strict';
+
+// Tests that the AbortPaymentEvent is in a ServiceWorkerGloablContext and
+// exposes its members (e.g. respondWith, waitUntil and data).
+service_worker_test(
+    'resources/abort-payment-event.js',
+    'Exposure of the AbortPaymentEvent object in a Service Worker.');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/payments/resources/abort-payment-event.js b/third_party/WebKit/LayoutTests/http/tests/payments/resources/abort-payment-event.js
new file mode 100644
index 0000000..0dc33b9a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/payments/resources/abort-payment-event.js
@@ -0,0 +1,19 @@
+importScripts('../../serviceworker/resources/worker-testharness.js');
+
+test(() => {
+  assert_true('AbortPaymentEvent' in self);
+  assert_inherits(AbortPaymentEvent.prototype, 'waitUntil');
+  assert_own_property(AbortPaymentEvent.prototype, 'respondWith');
+});
+
+promise_test(() => {
+  return new Promise(resolve => {
+    var abortEvent = new AbortPaymentEvent('abortpayment', {});
+
+    self.addEventListener('abortpayment', e => {
+      resolve();
+    });
+
+    self.dispatchEvent(abortEvent);
+  });
+});
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 14fde4d..37a16a0c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1,4 +1,8 @@
 [INTERFACES]
+interface AbortPaymentEvent : ExtendableEvent
+    attribute @@toStringTag
+    method constructor
+    method respondWith
 interface BackgroundFetchClickEvent : BackgroundFetchEvent
     attribute @@toStringTag
     getter state
@@ -2467,6 +2471,7 @@
     attribute console
     attribute internals
     getter clients
+    getter onabortpayment
     getter onactivate
     getter onbackgroundfetchabort
     getter onbackgroundfetchclick
@@ -2486,6 +2491,7 @@
     method fetch
     method gc
     method skipWaiting
+    setter onabortpayment
     setter onactivate
     setter onbackgroundfetchabort
     setter onbackgroundfetchclick
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/json-response-overflow.php b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/json-response-overflow.php
deleted file mode 100644
index 555da498..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/json-response-overflow.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-header("Content-Type: text/json");
-echo "{";
-for ($i = 0; $i < 13*1024*1024; $i++) {
-    echo "\"v_$i\":$i,";
-    if (!$i % 1000)
-        flush();
-}
-echo "\"end\" : true}";
-flush();
-?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow-expected.txt
deleted file mode 100644
index 6e36bbb8..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Verify that XMLHttpRequest handles string overflows.
-You should see PASSED once.
-PASSED
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html
deleted file mode 100644
index b854bdf..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<html>
-<body>
-Verify that XMLHttpRequest handles string overflows.<br/>
-You should see PASSED once.<br/>
-
-<script type="text/javascript">
-
-function log (msg)
-{
-    document.body.appendChild(document.createTextNode(msg));
-}
-
-var xhr = new XMLHttpRequest;
-xhr.responseType = 'json';
-xhr.onreadystatechange = function() {
-    if (xhr.readyState != 4)
-        return;
-    log((xhr.response === null && (xhr.status === 200)) ? "PASSED" : "FAILED");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-xhr.open("GET", "resources/json-response-overflow.php", true);
-xhr.send(null);
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/virtual/enable_wasm/external/wpt/wasm/wasm_service_worker_test-expected.txt b/third_party/WebKit/LayoutTests/virtual/enable_wasm/external/wpt/wasm/wasm_service_worker_test-expected.txt
deleted file mode 100644
index 157d422..0000000
--- a/third_party/WebKit/LayoutTests/virtual/enable_wasm/external/wpt/wasm/wasm_service_worker_test-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL postMessaging wasm from a service worker should fail promise_test: Unhandled rejection with value: object "ReferenceError: service_worker_unregister_and_register is not defined"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 3d3cb4c..b8a6918 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1,4 +1,8 @@
 [INTERFACES]
+interface AbortPaymentEvent : ExtendableEvent
+    attribute @@toStringTag
+    method constructor
+    method respondWith
 interface BackgroundFetchClickEvent : BackgroundFetchEvent
     attribute @@toStringTag
     getter state
@@ -2458,6 +2462,7 @@
     attribute console
     attribute internals
     getter clients
+    getter onabortpayment
     getter onactivate
     getter onbackgroundfetchabort
     getter onbackgroundfetchclick
@@ -2477,6 +2482,7 @@
     method fetch
     method gc
     method skipWaiting
+    setter onabortpayment
     setter onactivate
     setter onbackgroundfetchabort
     setter onbackgroundfetchclick
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 30f11f67..5e8e1dce 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1,3 +1,7 @@
+interface AbortPaymentEvent : ExtendableEvent
+    attribute @@toStringTag
+    method constructor
+    method respondWith
 interface BackgroundFetchClickEvent : BackgroundFetchEvent
     getter state
     method constructor
@@ -2293,6 +2297,7 @@
     attribute console
     attribute internals
     getter clients
+    getter onabortpayment
     getter onactivate
     getter onbackgroundfetchabort
     getter onbackgroundfetchclick
@@ -2312,6 +2317,7 @@
     method fetch
     method gc
     method skipWaiting
+    setter onabortpayment
     setter onactivate
     setter onbackgroundfetchabort
     setter onbackgroundfetchclick
diff --git a/third_party/WebKit/Source/bindings/modules/BUILD.gn b/third_party/WebKit/Source/bindings/modules/BUILD.gn
index fc720bd..34d43fa 100644
--- a/third_party/WebKit/Source/bindings/modules/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/modules/BUILD.gn
@@ -34,6 +34,7 @@
     "//third_party/WebKit/Source/modules/mediastream/MediaStreamEvent.idl",
     "//third_party/WebKit/Source/modules/mediastream/MediaStreamTrackEvent.idl",
     "//third_party/WebKit/Source/modules/notifications/NotificationEvent.idl",
+    "//third_party/WebKit/Source/modules/payments/AbortPaymentEvent.idl",
     "//third_party/WebKit/Source/modules/payments/CanMakePaymentEvent.idl",
     "//third_party/WebKit/Source/modules/payments/PaymentRequestEvent.idl",
     "//third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.idl",
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index 58efa09..b4e0a9b 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -200,9 +200,9 @@
   // TODO(dglazkov): TextIterator should not be created for documents that don't
   // have a frame, but it currently still happens in some cases. See
   // http://crbug.com/591877 for details.
-  DCHECK(!start.GetDocument()->View() ||
-         !start.GetDocument()->View()->NeedsLayout());
-  DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate());
+  CHECK(!start.GetDocument()->View() ||
+        !start.GetDocument()->View()->NeedsLayout());
+  CHECK(!start.GetDocument()->NeedsLayoutTreeUpdate());
   // To avoid renderer hang, we use |CHECK_LE()| to catch the bad callers
   // in release build.
   CHECK_LE(start, end);
diff --git a/third_party/WebKit/Source/core/events/EventTypeNames.json5 b/third_party/WebKit/Source/core/events/EventTypeNames.json5
index 87db01c..a79b8b75 100644
--- a/third_party/WebKit/Source/core/events/EventTypeNames.json5
+++ b/third_party/WebKit/Source/core/events/EventTypeNames.json5
@@ -16,6 +16,7 @@
     "DOMNodeRemovedFromDocument",
     "DOMSubtreeModified",
     "abort",
+    "abortpayment",
     "activate",
     "active",
     "addsourcebuffer",
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
index 7abd0a4e..84980175 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
@@ -53,7 +53,7 @@
 
 namespace {
 
-class MockChromeClient : public EmptyChromeClient {
+class MockChromeClientForImpl : public EmptyChromeClient {
  public:
   // EmptyChromeClient overrides:
   WebScreenInfo GetScreenInfo() const override {
@@ -63,7 +63,7 @@
   }
 };
 
-class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer {
+class MockWebMediaPlayerForImpl : public EmptyWebMediaPlayer {
  public:
   // WebMediaPlayer overrides:
   WebTimeRanges Seekable() const override { return seekable_; }
@@ -83,15 +83,17 @@
   }
 };
 
-class StubLocalFrameClient : public EmptyLocalFrameClient {
+class StubLocalFrameClientForImpl : public EmptyLocalFrameClient {
  public:
-  static StubLocalFrameClient* Create() { return new StubLocalFrameClient; }
+  static StubLocalFrameClientForImpl* Create() {
+    return new StubLocalFrameClientForImpl;
+  }
 
   std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
       HTMLMediaElement&,
       const WebMediaPlayerSource&,
       WebMediaPlayerClient*) override {
-    return WTF::WrapUnique(new MockVideoWebMediaPlayer);
+    return WTF::WrapUnique(new MockWebMediaPlayerForImpl);
   }
 
   WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
@@ -153,9 +155,9 @@
   void InitializePage() {
     Page::PageClients clients;
     FillWithEmptyClients(clients);
-    clients.chrome_client = new MockChromeClient();
-    page_holder_ = DummyPageHolder::Create(IntSize(800, 600), &clients,
-                                           StubLocalFrameClient::Create());
+    clients.chrome_client = new MockChromeClientForImpl();
+    page_holder_ = DummyPageHolder::Create(
+        IntSize(800, 600), &clients, StubLocalFrameClientForImpl::Create());
 
     GetDocument().write("<video>");
     HTMLVideoElement& video =
@@ -194,8 +196,8 @@
   MediaControlCurrentTimeDisplayElement* GetCurrentTimeDisplayElement() const {
     return media_controls_->current_time_display_;
   }
-  MockVideoWebMediaPlayer* WebMediaPlayer() {
-    return static_cast<MockVideoWebMediaPlayer*>(
+  MockWebMediaPlayerForImpl* WebMediaPlayer() {
+    return static_cast<MockWebMediaPlayerForImpl*>(
         MediaControls().MediaElement().GetWebMediaPlayer());
   }
   Document& GetDocument() { return page_holder_->GetDocument(); }
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp
index 9cc4397..0d1d59b 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp
@@ -44,7 +44,8 @@
   void OnError(WebLockOrientationError) override {}
 };
 
-class MockVideoWebMediaPlayer final : public EmptyWebMediaPlayer {
+class MockWebMediaPlayerForOrientationLockDelegate final
+    : public EmptyWebMediaPlayer {
  public:
   bool HasVideo() const override { return true; }
 
@@ -75,7 +76,8 @@
   document->ServiceScriptedAnimations(WTF::MonotonicallyIncreasingTime());
 }
 
-class MockChromeClient final : public EmptyChromeClient {
+class MockChromeClientForOrientationLockDelegate final
+    : public EmptyChromeClient {
  public:
   // ChromeClient overrides:
   void InstallSupplements(LocalFrame& frame) override {
@@ -106,15 +108,18 @@
   MockWebScreenOrientationClient web_screen_orientation_client_;
 };
 
-class StubLocalFrameClient final : public EmptyLocalFrameClient {
+class StubLocalFrameClientForOrientationLockDelegate final
+    : public EmptyLocalFrameClient {
  public:
-  static StubLocalFrameClient* Create() { return new StubLocalFrameClient; }
+  static StubLocalFrameClientForOrientationLockDelegate* Create() {
+    return new StubLocalFrameClientForOrientationLockDelegate;
+  }
 
   std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
       HTMLMediaElement&,
       const WebMediaPlayerSource&,
       WebMediaPlayerClient*) override {
-    return WTF::MakeUnique<MockVideoWebMediaPlayer>();
+    return WTF::MakeUnique<MockWebMediaPlayerForOrientationLockDelegate>();
   }
 };
 
@@ -130,14 +135,15 @@
   }
 
   void SetUp() override {
-    chrome_client_ = new MockChromeClient();
+    chrome_client_ = new MockChromeClientForOrientationLockDelegate();
 
     Page::PageClients clients;
     FillWithEmptyClients(clients);
     clients.chrome_client = chrome_client_.Get();
 
-    page_holder_ = DummyPageHolder::Create(IntSize(800, 600), &clients,
-                                           StubLocalFrameClient::Create());
+    page_holder_ = DummyPageHolder::Create(
+        IntSize(800, 600), &clients,
+        StubLocalFrameClientForOrientationLockDelegate::Create());
 
     previous_orientation_event_value_ =
         RuntimeEnabledFeatures::OrientationEventEnabled();
@@ -232,15 +238,18 @@
         ->orientation_lock_delegate_->ComputeOrientationLock();
   }
 
-  MockChromeClient& ChromeClient() const { return *chrome_client_; }
+  MockChromeClientForOrientationLockDelegate& ChromeClient() const {
+    return *chrome_client_;
+  }
 
   HTMLVideoElement& Video() const { return *video_; }
   Document& GetDocument() const { return page_holder_->GetDocument(); }
   MockWebScreenOrientationClient& ScreenOrientationClient() const {
     return ChromeClient().WebScreenOrientationClient();
   }
-  MockVideoWebMediaPlayer& MockWebMediaPlayer() const {
-    return *static_cast<MockVideoWebMediaPlayer*>(Video().GetWebMediaPlayer());
+  MockWebMediaPlayerForOrientationLockDelegate& MockWebMediaPlayer() const {
+    return *static_cast<MockWebMediaPlayerForOrientationLockDelegate*>(
+        Video().GetWebMediaPlayer());
   }
 
  private:
@@ -251,7 +260,7 @@
   bool previous_video_rotate_to_fullscreen_value_;
   std::unique_ptr<DummyPageHolder> page_holder_;
   Persistent<HTMLVideoElement> video_;
-  Persistent<MockChromeClient> chrome_client_;
+  Persistent<MockChromeClientForOrientationLockDelegate> chrome_client_;
 };
 
 class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 81516e5..f0ae8d0 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -178,6 +178,7 @@
                     "notifications/NotificationEvent.idl",
                     "notifications/NotificationPermissionCallback.idl",
                     "offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl",
+                    "payments/AbortPaymentEvent.idl",
                     "payments/CanMakePaymentEvent.idl",
                     "payments/PaymentAddress.idl",
                     "payments/PaymentInstruments.idl",
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationDataTest.cpp b/third_party/WebKit/Source/modules/notifications/NotificationDataTest.cpp
index 839c2dd..8af7a6b 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationDataTest.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationDataTest.cpp
@@ -17,7 +17,7 @@
 namespace blink {
 namespace {
 
-const char kBaseUrl[] = "https://example.com/directory/";
+const char kNotificationBaseUrl[] = "https://example.com/directory/";
 const char kNotificationTitle[] = "My Notification";
 
 const char kNotificationDir[] = "rtl";
@@ -67,7 +67,7 @@
 class NotificationDataTest : public ::testing::Test {
  public:
   void SetUp() override {
-    execution_context_ = new CompleteUrlExecutionContext(kBaseUrl);
+    execution_context_ = new CompleteUrlExecutionContext(kNotificationBaseUrl);
   }
 
   ExecutionContext* GetExecutionContext() { return execution_context_.Get(); }
@@ -126,7 +126,7 @@
   EXPECT_EQ(kNotificationBody, notification_data.body);
   EXPECT_EQ(kNotificationTag, notification_data.tag);
 
-  KURL base(kParsedURLString, kBaseUrl);
+  KURL base(kParsedURLString, kNotificationBaseUrl);
 
   // URLs should be resolved against the base URL of the execution context.
   EXPECT_EQ(WebURL(KURL(base, kNotificationImage)), notification_data.image);
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp b/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp
index fe2a3736..5108aae6 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp
@@ -24,9 +24,9 @@
 
 enum class LoadState { kNotLoaded, kLoadFailed, kLoadSuccessful };
 
-constexpr char kBaseUrl[] = "http://test.com/";
-constexpr char kBaseDir[] = "notifications/";
-constexpr char kIcon500x500[] = "500x500.png";
+constexpr char kImageLoaderBaseUrl[] = "http://test.com/";
+constexpr char kImageLoaderBaseDir[] = "notifications/";
+constexpr char kImageLoaderIcon500x500[] = "500x500.png";
 
 // This mirrors the definition in NotificationImageLoader.cpp.
 constexpr unsigned long kImageFetchTimeoutInMs = 90000;
@@ -54,7 +54,8 @@
   // directory.
   WebURL RegisterMockedURL(const String& file_name) {
     WebURL registered_url = URLTestHelpers::RegisterMockedURLLoadFromBase(
-        kBaseUrl, testing::CoreTestDataPath(kBaseDir), file_name, "image/png");
+        kImageLoaderBaseUrl, testing::CoreTestDataPath(kImageLoaderBaseDir),
+        file_name, "image/png");
     return registered_url;
   }
 
@@ -86,7 +87,7 @@
 };
 
 TEST_F(NotificationImageLoaderTest, SuccessTest) {
-  KURL url = RegisterMockedURL(kIcon500x500);
+  KURL url = RegisterMockedURL(kImageLoaderIcon500x500);
   LoadImage(url);
   histogram_tester_.ExpectTotalCount("Notifications.LoadFinishTime.Icon", 0);
   histogram_tester_.ExpectTotalCount("Notifications.LoadFileSize.Icon", 0);
@@ -105,7 +106,7 @@
 
   // To test for a timeout, this needs to override the clock in the platform.
   // Just creating the mock platform will do everything to set it up.
-  KURL url = RegisterMockedURL(kIcon500x500);
+  KURL url = RegisterMockedURL(kImageLoaderIcon500x500);
   LoadImage(url);
 
   // Run the platform for kImageFetchTimeoutInMs-1 seconds. This should not
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoaderTest.cpp b/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoaderTest.cpp
index 8b2935b8..aedbd44 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoaderTest.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoaderTest.cpp
@@ -25,15 +25,15 @@
 namespace blink {
 namespace {
 
-constexpr char kBaseUrl[] = "http://test.com/";
-constexpr char kBaseDir[] = "notifications/";
-constexpr char kIcon48x48[] = "48x48.png";
-constexpr char kIcon100x100[] = "100x100.png";
-constexpr char kIcon110x110[] = "110x110.png";
-constexpr char kIcon120x120[] = "120x120.png";
-constexpr char kIcon500x500[] = "500x500.png";
-constexpr char kIcon3000x1000[] = "3000x1000.png";
-constexpr char kIcon3000x2000[] = "3000x2000.png";
+constexpr char kResourcesLoaderBaseUrl[] = "http://test.com/";
+constexpr char kResourcesLoaderBaseDir[] = "notifications/";
+constexpr char kResourcesLoaderIcon48x48[] = "48x48.png";
+constexpr char kResourcesLoaderIcon100x100[] = "100x100.png";
+constexpr char kResourcesLoaderIcon110x110[] = "110x110.png";
+constexpr char kResourcesLoaderIcon120x120[] = "120x120.png";
+constexpr char kResourcesLoaderIcon500x500[] = "500x500.png";
+constexpr char kResourcesLoaderIcon3000x1000[] = "3000x1000.png";
+constexpr char kResourcesLoaderIcon3000x2000[] = "3000x2000.png";
 
 class NotificationResourcesLoaderTest : public ::testing::Test {
  public:
@@ -67,13 +67,15 @@
   // test data directory.
   WebURL RegisterMockedURL(const String& file_name) {
     WebURL registered_url = URLTestHelpers::RegisterMockedURLLoadFromBase(
-        kBaseUrl, testing::CoreTestDataPath(kBaseDir), file_name, "image/png");
+        kResourcesLoaderBaseUrl,
+        testing::CoreTestDataPath(kResourcesLoaderBaseDir), file_name,
+        "image/png");
     return registered_url;
   }
 
   // Registers a mocked url that will fail to be fetched, with a 404 error.
   WebURL RegisterMockedErrorURL(const String& file_name) {
-    WebURL url(KURL(kParsedURLString, kBaseUrl + file_name));
+    WebURL url(KURL(kParsedURLString, kResourcesLoaderBaseUrl + file_name));
     URLTestHelpers::RegisterMockedErrorURLLoad(url);
     return url;
   }
@@ -86,13 +88,15 @@
 
 TEST_F(NotificationResourcesLoaderTest, LoadMultipleResources) {
   WebNotificationData notification_data;
-  notification_data.image = RegisterMockedURL(kIcon500x500);
-  notification_data.icon = RegisterMockedURL(kIcon100x100);
-  notification_data.badge = RegisterMockedURL(kIcon48x48);
+  notification_data.image = RegisterMockedURL(kResourcesLoaderIcon500x500);
+  notification_data.icon = RegisterMockedURL(kResourcesLoaderIcon100x100);
+  notification_data.badge = RegisterMockedURL(kResourcesLoaderIcon48x48);
   notification_data.actions =
       WebVector<WebNotificationAction>(static_cast<size_t>(2));
-  notification_data.actions[0].icon = RegisterMockedURL(kIcon110x110);
-  notification_data.actions[1].icon = RegisterMockedURL(kIcon120x120);
+  notification_data.actions[0].icon =
+      RegisterMockedURL(kResourcesLoaderIcon110x110);
+  notification_data.actions[1].icon =
+      RegisterMockedURL(kResourcesLoaderIcon120x120);
 
   ASSERT_FALSE(Resources());
 
@@ -120,7 +124,7 @@
 
 TEST_F(NotificationResourcesLoaderTest, LargeIconsAreScaledDown) {
   WebNotificationData notification_data;
-  notification_data.icon = RegisterMockedURL(kIcon500x500);
+  notification_data.icon = RegisterMockedURL(kResourcesLoaderIcon500x500);
   notification_data.badge = notification_data.icon;
   notification_data.actions =
       WebVector<WebNotificationAction>(static_cast<size_t>(1));
@@ -151,7 +155,7 @@
 
 TEST_F(NotificationResourcesLoaderTest, DownscalingPreserves3_1AspectRatio) {
   WebNotificationData notification_data;
-  notification_data.image = RegisterMockedURL(kIcon3000x1000);
+  notification_data.image = RegisterMockedURL(kResourcesLoaderIcon3000x1000);
 
   ASSERT_FALSE(Resources());
 
@@ -167,7 +171,7 @@
 
 TEST_F(NotificationResourcesLoaderTest, DownscalingPreserves3_2AspectRatio) {
   WebNotificationData notification_data;
-  notification_data.image = RegisterMockedURL(kIcon3000x2000);
+  notification_data.image = RegisterMockedURL(kResourcesLoaderIcon3000x2000);
 
   ASSERT_FALSE(Resources());
 
@@ -201,7 +205,7 @@
 TEST_F(NotificationResourcesLoaderTest, EmptyResourcesIfAllImagesFailToLoad) {
   WebNotificationData notification_data;
   notification_data.image = notification_data.icon;
-  notification_data.icon = RegisterMockedErrorURL(kIcon100x100);
+  notification_data.icon = RegisterMockedErrorURL(kResourcesLoaderIcon100x100);
   notification_data.badge = notification_data.icon;
   notification_data.actions =
       WebVector<WebNotificationAction>(static_cast<size_t>(1));
@@ -225,8 +229,8 @@
 
 TEST_F(NotificationResourcesLoaderTest, OneImageFailsToLoad) {
   WebNotificationData notification_data;
-  notification_data.icon = RegisterMockedURL(kIcon100x100);
-  notification_data.badge = RegisterMockedErrorURL(kIcon48x48);
+  notification_data.icon = RegisterMockedURL(kResourcesLoaderIcon100x100);
+  notification_data.badge = RegisterMockedErrorURL(kResourcesLoaderIcon48x48);
 
   ASSERT_FALSE(Resources());
 
@@ -246,13 +250,15 @@
 
 TEST_F(NotificationResourcesLoaderTest, StopYieldsNoResources) {
   WebNotificationData notification_data;
-  notification_data.image = RegisterMockedURL(kIcon500x500);
-  notification_data.icon = RegisterMockedURL(kIcon100x100);
-  notification_data.badge = RegisterMockedURL(kIcon48x48);
+  notification_data.image = RegisterMockedURL(kResourcesLoaderIcon500x500);
+  notification_data.icon = RegisterMockedURL(kResourcesLoaderIcon100x100);
+  notification_data.badge = RegisterMockedURL(kResourcesLoaderIcon48x48);
   notification_data.actions =
       WebVector<WebNotificationAction>(static_cast<size_t>(2));
-  notification_data.actions[0].icon = RegisterMockedURL(kIcon110x110);
-  notification_data.actions[1].icon = RegisterMockedURL(kIcon120x120);
+  notification_data.actions[0].icon =
+      RegisterMockedURL(kResourcesLoaderIcon110x110);
+  notification_data.actions[1].icon =
+      RegisterMockedURL(kResourcesLoaderIcon120x120);
 
   ASSERT_FALSE(Resources());
 
diff --git a/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.cpp b/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.cpp
new file mode 100644
index 0000000..cbbe752
--- /dev/null
+++ b/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.cpp
@@ -0,0 +1,61 @@
+// 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 "modules/payments/AbortPaymentEvent.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/ScriptPromise.h"
+#include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "modules/EventModules.h"
+#include "modules/serviceworkers/ExtendableEventInit.h"
+#include "modules/serviceworkers/RespondWithObserver.h"
+#include "modules/serviceworkers/WaitUntilObserver.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/text/AtomicString.h"
+
+namespace blink {
+
+AbortPaymentEvent* AbortPaymentEvent::Create(
+    const AtomicString& type,
+    const ExtendableEventInit& initializer) {
+  return new AbortPaymentEvent(type, initializer, nullptr, nullptr);
+}
+
+AbortPaymentEvent* AbortPaymentEvent::Create(
+    const AtomicString& type,
+    const ExtendableEventInit& initializer,
+    RespondWithObserver* respond_with_observer,
+    WaitUntilObserver* wait_until_observer) {
+  return new AbortPaymentEvent(type, initializer, respond_with_observer,
+                               wait_until_observer);
+}
+
+AbortPaymentEvent::~AbortPaymentEvent() {}
+
+const AtomicString& AbortPaymentEvent::InterfaceName() const {
+  return EventNames::AbortPaymentEvent;
+}
+
+void AbortPaymentEvent::respondWith(ScriptState* script_state,
+                                    ScriptPromise script_promise,
+                                    ExceptionState& exception_state) {
+  stopImmediatePropagation();
+  if (observer_) {
+    observer_->RespondWith(script_state, script_promise, exception_state);
+  }
+}
+
+DEFINE_TRACE(AbortPaymentEvent) {
+  visitor->Trace(observer_);
+  ExtendableEvent::Trace(visitor);
+}
+
+AbortPaymentEvent::AbortPaymentEvent(const AtomicString& type,
+                                     const ExtendableEventInit& initializer,
+                                     RespondWithObserver* respond_with_observer,
+                                     WaitUntilObserver* wait_until_observer)
+    : ExtendableEvent(type, initializer, wait_until_observer),
+      observer_(respond_with_observer) {}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.h b/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.h
new file mode 100644
index 0000000..97e2448
--- /dev/null
+++ b/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.h
@@ -0,0 +1,54 @@
+// 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 AbortPaymentEvent_h
+#define AbortPaymentEvent_h
+
+#include "modules/EventModules.h"
+#include "modules/serviceworkers/ExtendableEvent.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/heap/Handle.h"
+#include "platform/wtf/Noncopyable.h"
+
+namespace WTF {
+class AtomicString;
+}
+
+namespace blink {
+
+class ExtendableEventInit;
+class RespondWithObserver;
+class ScriptState;
+
+class MODULES_EXPORT AbortPaymentEvent final : public ExtendableEvent {
+  DEFINE_WRAPPERTYPEINFO();
+  WTF_MAKE_NONCOPYABLE(AbortPaymentEvent);
+
+ public:
+  static AbortPaymentEvent* Create(const AtomicString& type,
+                                   const ExtendableEventInit&);
+  static AbortPaymentEvent* Create(const AtomicString& type,
+                                   const ExtendableEventInit&,
+                                   RespondWithObserver*,
+                                   WaitUntilObserver*);
+  ~AbortPaymentEvent() override;
+
+  const AtomicString& InterfaceName() const override;
+
+  void respondWith(ScriptState*, ScriptPromise, ExceptionState&);
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  AbortPaymentEvent(const AtomicString& type,
+                    const ExtendableEventInit&,
+                    RespondWithObserver*,
+                    WaitUntilObserver*);
+
+  Member<RespondWithObserver> observer_;
+};
+
+}  // namespace blink
+
+#endif  // AbortPaymentEvent_h
diff --git a/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.idl b/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.idl
new file mode 100644
index 0000000..e1cd327f9
--- /dev/null
+++ b/third_party/WebKit/Source/modules/payments/AbortPaymentEvent.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://github.com/w3c/payment-handler/pull/170
+
+[
+    RuntimeEnabled=PaymentApp,
+    Constructor(DOMString type, ExtendableEventInit eventInitDict),
+    Exposed=ServiceWorker
+] interface AbortPaymentEvent : ExtendableEvent {
+    [CallWith=ScriptState, RaisesException] void respondWith(Promise<boolean> paymentAbortedResponse);
+};
diff --git a/third_party/WebKit/Source/modules/payments/BUILD.gn b/third_party/WebKit/Source/modules/payments/BUILD.gn
index 1a5de53..1f08f59 100644
--- a/third_party/WebKit/Source/modules/payments/BUILD.gn
+++ b/third_party/WebKit/Source/modules/payments/BUILD.gn
@@ -6,6 +6,8 @@
 
 blink_modules_sources("payments") {
   sources = [
+    "AbortPaymentEvent.cpp",
+    "AbortPaymentEvent.h",
     "CanMakePaymentEvent.cpp",
     "CanMakePaymentEvent.h",
     "CanMakePaymentRespondWithObserver.cpp",
diff --git a/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.h b/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.h
index 5e198ac..9b982b5 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.h
@@ -14,6 +14,7 @@
   STATIC_ONLY(PaymentAppServiceWorkerGlobalScope);
 
  public:
+  DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(abortpayment);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(canmakepayment);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(paymentrequest);
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.idl b/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.idl
index 63057cd..02a3550 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentAppServiceWorkerGlobalScope.idl
@@ -7,6 +7,7 @@
 [
     RuntimeEnabled=PaymentApp
 ] partial interface ServiceWorkerGlobalScope {
+    attribute EventHandler onabortpayment;
     attribute EventHandler oncanmakepayment;
     attribute EventHandler onpaymentrequest;
 };
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp b/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
index 3abfda6e..8a1de1f 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
+++ b/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
@@ -23,9 +23,10 @@
 
 namespace blink {
 
-class MockEventListener : public EventListener {
+class MockEventListenerForPresentationReceiver : public EventListener {
  public:
-  MockEventListener() : EventListener(kCPPEventListenerType) {}
+  MockEventListenerForPresentationReceiver()
+      : EventListener(kCPPEventListenerType) {}
 
   bool operator==(const EventListener& other) const final {
     return this == &other;
@@ -69,7 +70,8 @@
   V8TestingScope scope;
   auto receiver = new PresentationReceiver(&scope.GetFrame(), nullptr);
 
-  auto event_handler = new StrictMock<MockEventListener>();
+  auto event_handler =
+      new StrictMock<MockEventListenerForPresentationReceiver>();
   AddConnectionavailableEventListener(event_handler, receiver);
   EXPECT_CALL(*event_handler, handleEvent(::testing::_, ::testing::_)).Times(0);
 
@@ -84,7 +86,8 @@
   V8TestingScope scope;
   auto receiver = new PresentationReceiver(&scope.GetFrame(), nullptr);
 
-  auto event_handler = new StrictMock<MockEventListener>();
+  auto event_handler =
+      new StrictMock<MockEventListenerForPresentationReceiver>();
   AddConnectionavailableEventListener(event_handler, receiver);
   EXPECT_CALL(*event_handler, handleEvent(::testing::_, ::testing::_)).Times(0);
 
@@ -103,8 +106,8 @@
   V8TestingScope scope;
   auto receiver = new PresentationReceiver(&scope.GetFrame(), nullptr);
 
-  StrictMock<MockEventListener>* event_handler =
-      new StrictMock<MockEventListener>();
+  StrictMock<MockEventListenerForPresentationReceiver>* event_handler =
+      new StrictMock<MockEventListenerForPresentationReceiver>();
   AddConnectionavailableEventListener(event_handler, receiver);
   EXPECT_CALL(*event_handler, handleEvent(::testing::_, ::testing::_)).Times(1);
 
@@ -124,8 +127,8 @@
   V8TestingScope scope;
   auto receiver = new PresentationReceiver(&scope.GetFrame(), nullptr);
 
-  StrictMock<MockEventListener>* event_handler =
-      new StrictMock<MockEventListener>();
+  StrictMock<MockEventListenerForPresentationReceiver>* event_handler =
+      new StrictMock<MockEventListenerForPresentationReceiver>();
   AddConnectionavailableEventListener(event_handler, receiver);
   EXPECT_CALL(*event_handler, handleEvent(::testing::_, ::testing::_)).Times(0);
 
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
index 837461e..8411ea7 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
@@ -39,9 +39,9 @@
       : ScriptFunction(script_state) {}
 };
 
-class MockEventListener : public EventListener {
+class MockEventListenerForRemotePlayback : public EventListener {
  public:
-  MockEventListener() : EventListener(kCPPEventListenerType) {}
+  MockEventListenerForRemotePlayback() : EventListener(kCPPEventListenerType) {}
 
   bool operator==(const EventListener& other) const final {
     return this == &other;
@@ -199,9 +199,12 @@
   RemotePlayback* remote_playback =
       HTMLMediaElementRemotePlayback::remote(*element);
 
-  auto connecting_handler = new ::testing::StrictMock<MockEventListener>();
-  auto connect_handler = new ::testing::StrictMock<MockEventListener>();
-  auto disconnect_handler = new ::testing::StrictMock<MockEventListener>();
+  auto connecting_handler =
+      new ::testing::StrictMock<MockEventListenerForRemotePlayback>();
+  auto connect_handler =
+      new ::testing::StrictMock<MockEventListenerForRemotePlayback>();
+  auto disconnect_handler =
+      new ::testing::StrictMock<MockEventListenerForRemotePlayback>();
 
   remote_playback->addEventListener(EventTypeNames::connecting,
                                     connecting_handler);
diff --git a/third_party/WebKit/Source/modules/sensor/Sensor.cpp b/third_party/WebKit/Source/modules/sensor/Sensor.cpp
index 174e78a9..a0075fd2 100644
--- a/third_party/WebKit/Source/modules/sensor/Sensor.cpp
+++ b/third_party/WebKit/Source/modules/sensor/Sensor.cpp
@@ -63,11 +63,17 @@
 Sensor::~Sensor() = default;
 
 void Sensor::start() {
-  StartListening();
+  if (state_ != SensorState::kIdle)
+    return;
+  state_ = SensorState::kActivating;
+  Activate();
 }
 
 void Sensor::stop() {
-  StopListening();
+  if (state_ == SensorState::kIdle)
+    return;
+  Deactivate();
+  state_ = SensorState::kIdle;
 }
 
 // Getters
@@ -105,7 +111,7 @@
 }
 
 bool Sensor::HasPendingActivity() const {
-  if (state_ == Sensor::SensorState::kIdle)
+  if (state_ == SensorState::kIdle)
     return false;
   return GetExecutionContext() && HasEventListeners();
 }
@@ -157,23 +163,24 @@
 }
 
 void Sensor::ContextDestroyed(ExecutionContext*) {
-  StopListening();
+  if (!IsIdleOrErrored())
+    Deactivate();
 }
 
 void Sensor::OnSensorInitialized() {
-  if (state_ != Sensor::SensorState::kActivating)
+  if (state_ != SensorState::kActivating)
     return;
 
   RequestAddConfiguration();
 }
 
 void Sensor::OnSensorReadingChanged() {
-  if (state_ != Sensor::SensorState::kActivated)
+  if (state_ != SensorState::kActivated)
     return;
 
   // Return if reading update is already scheduled or the cached
   // reading is up-to-date.
-  if (pending_reading_update_.IsActive())
+  if (pending_reading_notification_.IsActive())
     return;
 
   double elapsedTime =
@@ -192,12 +199,12 @@
     // Invoke JS callbacks in a different callchain to obviate
     // possible modifications of SensorProxy::observers_ container
     // while it is being iterated through.
-    pending_reading_update_ =
+    pending_reading_notification_ =
         TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
             ->PostCancellableTask(BLINK_FROM_HERE,
                                   std::move(sensor_reading_changed));
   } else {
-    pending_reading_update_ =
+    pending_reading_notification_ =
         TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
             ->PostDelayedCancellableTask(
                 BLINK_FROM_HERE, std::move(sensor_reading_changed),
@@ -220,18 +227,18 @@
     return;
   }
 
-  UpdateState(Sensor::SensorState::kActivated);
+  if (!GetExecutionContext())
+    return;
 
-  if (GetExecutionContext()) {
-    TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
-        ->PostTask(BLINK_FROM_HERE, WTF::Bind(&Sensor::NotifyActivate,
-                                              WrapWeakPersistent(this)));
-  }
+  pending_activated_notification_ =
+      TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
+          ->PostCancellableTask(
+              BLINK_FROM_HERE,
+              WTF::Bind(&Sensor::NotifyActivated, WrapWeakPersistent(this)));
 }
 
-void Sensor::StartListening() {
-  if (state_ != SensorState::kIdle)
-    return;
+void Sensor::Activate() {
+  DCHECK_EQ(state_, SensorState::kActivating);
 
   InitSensorProxyIfNeeded();
   if (!sensor_proxy_) {
@@ -246,23 +253,27 @@
     sensor_proxy_->Initialize();
 
   sensor_proxy_->AddObserver(this);
-  UpdateState(SensorState::kActivating);
 }
 
-void Sensor::StopListening() {
-  if (state_ == SensorState::kIdle)
+void Sensor::Deactivate() {
+  DCHECK_NE(state_, SensorState::kIdle);
+  // state_ is not set to kIdle here as on error it should
+  // transition to the kIdle state in the same call chain
+  // the error event is dispatched, i.e. inside NotifyError().
+  pending_reading_notification_.Cancel();
+  pending_activated_notification_.Cancel();
+  pending_error_notification_.Cancel();
+
+  if (!sensor_proxy_)
     return;
 
-  pending_reading_update_.Cancel();
-
-  DCHECK(sensor_proxy_);
   if (sensor_proxy_->IsInitialized()) {
     DCHECK(configuration_);
     sensor_proxy_->RemoveConfiguration(configuration_->Clone());
+    last_reported_timestamp_ = 0.0;
   }
 
   sensor_proxy_->RemoveObserver(this);
-  UpdateState(Sensor::SensorState::kIdle);
 }
 
 void Sensor::RequestAddConfiguration() {
@@ -281,35 +292,56 @@
                 WrapWeakPersistent(this)));
 }
 
-void Sensor::UpdateState(Sensor::SensorState new_state) {
-  state_ = new_state;
-}
-
 void Sensor::HandleError(ExceptionCode code,
                          const String& sanitized_message,
                          const String& unsanitized_message) {
-  StopListening();
-
-  if (GetExecutionContext()) {
-    auto error =
-        DOMException::Create(code, sanitized_message, unsanitized_message);
-    TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
-        ->PostTask(BLINK_FROM_HERE,
-                   WTF::Bind(&Sensor::NotifyError, WrapWeakPersistent(this),
-                             WrapPersistent(error)));
+  if (!GetExecutionContext()) {
+    // Deactivate() is already called from Sensor::ContextDestroyed().
+    return;
   }
+
+  if (IsIdleOrErrored())
+    return;
+
+  Deactivate();
+
+  auto error =
+      DOMException::Create(code, sanitized_message, unsanitized_message);
+  pending_error_notification_ =
+      TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
+          ->PostCancellableTask(
+              BLINK_FROM_HERE,
+              WTF::Bind(&Sensor::NotifyError, WrapWeakPersistent(this),
+                        WrapPersistent(error)));
 }
 
 void Sensor::NotifyReading() {
+  DCHECK_EQ(state_, SensorState::kActivated);
   last_reported_timestamp_ = sensor_proxy_->reading().timestamp;
   DispatchEvent(Event::Create(EventTypeNames::reading));
 }
 
-void Sensor::NotifyActivate() {
+void Sensor::NotifyActivated() {
+  DCHECK_EQ(state_, SensorState::kActivating);
+  state_ = SensorState::kActivated;
+
+  if (CanReturnReadings()) {
+    // If reading has already arrived, send initial 'reading' notification
+    // right away.
+    DCHECK(!pending_reading_notification_.IsActive());
+    pending_reading_notification_ =
+        TaskRunnerHelper::Get(TaskType::kSensor, GetExecutionContext())
+            ->PostCancellableTask(
+                BLINK_FROM_HERE,
+                WTF::Bind(&Sensor::NotifyReading, WrapWeakPersistent(this)));
+  }
+
   DispatchEvent(Event::Create(EventTypeNames::activate));
 }
 
 void Sensor::NotifyError(DOMException* error) {
+  DCHECK_NE(state_, SensorState::kIdle);
+  state_ = SensorState::kIdle;
   DispatchEvent(SensorErrorEvent::Create(EventTypeNames::error, error));
 }
 
@@ -320,4 +352,9 @@
   return sensor_proxy_->reading().timestamp != 0.0;
 }
 
+bool Sensor::IsIdleOrErrored() const {
+  return (state_ == SensorState::kIdle) ||
+         pending_error_notification_.IsActive();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/sensor/Sensor.h b/third_party/WebKit/Source/modules/sensor/Sensor.h
index ff9d2ac..84a11e8 100644
--- a/third_party/WebKit/Source/modules/sensor/Sensor.h
+++ b/third_party/WebKit/Source/modules/sensor/Sensor.h
@@ -78,6 +78,7 @@
   double ReadingValueUnchecked(int index) const;
   bool CanReturnReadings() const;
   bool IsActivated() const { return state_ == SensorState::kActivated; }
+  bool IsIdleOrErrored() const;
 
   // SensorProxy::Observer overrides.
   void OnSensorInitialized() override;
@@ -94,18 +95,17 @@
 
   void OnAddConfigurationRequestCompleted(bool);
 
-  void StartListening();
-  void StopListening();
+  void Activate();
+  void Deactivate();
 
   void RequestAddConfiguration();
 
-  void UpdateState(SensorState new_state);
   void HandleError(ExceptionCode = kUnknownError,
                    const String& sanitized_message = String(),
                    const String& unsanitized_message = String());
 
   void NotifyReading();
-  void NotifyActivate();
+  void NotifyActivated();
   void NotifyError(DOMException* error);
 
  private:
@@ -115,7 +115,9 @@
   Member<SensorProxy> sensor_proxy_;
   double last_reported_timestamp_;
   SensorConfigurationPtr configuration_;
-  TaskHandle pending_reading_update_;
+  TaskHandle pending_reading_notification_;
+  TaskHandle pending_activated_notification_;
+  TaskHandle pending_error_notification_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
index cf0a3c82..7547fba 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
@@ -16,11 +16,12 @@
 
 namespace {
 
-class MockWebAudioDevice : public WebAudioDevice {
+class MockWebAudioDeviceForAudioContext : public WebAudioDevice {
  public:
-  explicit MockWebAudioDevice(double sample_rate, int frames_per_buffer)
+  explicit MockWebAudioDeviceForAudioContext(double sample_rate,
+                                             int frames_per_buffer)
       : sample_rate_(sample_rate), frames_per_buffer_(frames_per_buffer) {}
-  ~MockWebAudioDevice() override = default;
+  ~MockWebAudioDeviceForAudioContext() override = default;
 
   void Start() override {}
   void Stop() override {}
@@ -66,8 +67,8 @@
         break;
     }
 
-    return WTF::MakeUnique<MockWebAudioDevice>(AudioHardwareSampleRate(),
-                                               buffer_size);
+    return WTF::MakeUnique<MockWebAudioDeviceForAudioContext>(
+        AudioHardwareSampleRate(), buffer_size);
   }
 
   double AudioHardwareSampleRate() override { return 44100; }
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
index f0c6c9f..aedc6c9 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
@@ -50,11 +50,12 @@
   Member<Frame> parent_;
 };
 
-class MockWebAudioDevice : public WebAudioDevice {
+class MockWebAudioDeviceForBaseAudioContext : public WebAudioDevice {
  public:
-  explicit MockWebAudioDevice(double sample_rate, int frames_per_buffer)
+  explicit MockWebAudioDeviceForBaseAudioContext(double sample_rate,
+                                                 int frames_per_buffer)
       : sample_rate_(sample_rate), frames_per_buffer_(frames_per_buffer) {}
-  ~MockWebAudioDevice() override = default;
+  ~MockWebAudioDeviceForBaseAudioContext() override = default;
 
   void Start() override {}
   void Stop() override {}
@@ -75,8 +76,8 @@
       WebAudioDevice::RenderCallback*,
       const WebString& device_id,
       const WebSecurityOrigin&) override {
-    return WTF::MakeUnique<MockWebAudioDevice>(AudioHardwareSampleRate(),
-                                               AudioHardwareBufferSize());
+    return WTF::MakeUnique<MockWebAudioDeviceForBaseAudioContext>(
+        AudioHardwareSampleRate(), AudioHardwareBufferSize());
   }
 
   double AudioHardwareSampleRate() override { return 44100; }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py
index efdda32f..2648ab2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py
@@ -75,32 +75,33 @@
 
 class PathFinder(object):
 
-    def __init__(self, filesystem):
+    def __init__(self, filesystem, sys_path=None, env_path=None):
         self._filesystem = filesystem
         self._dirsep = filesystem.sep
-        self._sys_path = sys.path
-        self._env_path = os.environ['PATH'].split(os.pathsep)
-
-    @memoized
-    def _webkit_base(self):
-        """Returns the absolute path to the top of the WebKit tree.
-
-        Raises an AssertionError if the top dir can't be determined.
-        """
-        # TODO(qyearsley): This code somewhat duplicates the code in
-        # git.find_checkout_root().
-        module_path = self._filesystem.abspath(self._filesystem.path_to_module(self.__module__))
-        tools_index = module_path.rfind('Tools')
-        assert tools_index != -1, 'could not find location of this checkout from %s' % module_path
-        return self._filesystem.normpath(module_path[0:tools_index - 1])
+        self._sys_path = sys_path or sys.path
+        self._env_path = env_path or os.environ['PATH'].split(os.pathsep)
 
     @memoized
     def chromium_base(self):
         return self._filesystem.dirname(self._filesystem.dirname(self._webkit_base()))
 
-    # Do not expose this function in order to make the code robust against
-    # directory structure changes.
+    def layout_tests_dir(self):
+        return self._path_from_webkit_base('LayoutTests')
+
+    def perf_tests_dir(self):
+        return self._path_from_webkit_base('PerformanceTests')
+
+    @memoized
+    def _webkit_base(self):
+        """Returns the absolute path to the top of the Blink directory."""
+        module_path = self._filesystem.path_to_module(self.__module__)
+        tools_index = module_path.rfind('Tools')
+        assert tools_index != -1, 'could not find location of this checkout from %s' % module_path
+        return self._filesystem.normpath(module_path[0:tools_index - 1])
+
     def _path_from_webkit_base(self, *comps):
+        # This function is marked as protected in order to make the code
+        # more robust against directory structure changes.
         return self._filesystem.join(self._webkit_base(), *comps)
 
     def path_from_chromium_base(self, *comps):
@@ -112,21 +113,16 @@
     def path_from_tools_scripts(self, *comps):
         return self._filesystem.join(self._filesystem.join(self._webkit_base(), 'Tools', 'Scripts'), *comps)
 
-    def layout_tests_dir(self):
-        return self._path_from_webkit_base('LayoutTests')
-
     def path_from_layout_tests(self, *comps):
         return self._filesystem.join(self.layout_tests_dir(), *comps)
 
-    def perf_tests_dir(self):
-        return self._path_from_webkit_base('PerformanceTests')
-
     def layout_test_name(self, file_path):
         """Returns a layout test name, given the path from the repo root.
 
         Note: this appears to not work on Windows; see crbug.com/658795.
         Also, this function duplicates functionality that's in
         Port.relative_test_filename.
+
         TODO(qyearsley): De-duplicate this and Port.relative_test_filename,
         and ensure that it works properly with Windows paths.
 
@@ -145,8 +141,11 @@
 
     @memoized
     def depot_tools_base(self):
-        # This basically duplicates src/build/find_depot_tools.py without the side effects
-        # (adding the directory to sys.path and importing breakpad).
+        """Returns the path to depot_tools, or None if not found.
+
+        This basically duplicates src/build/find_depot_tools.py without the
+        side effects of adding the directory to sys.path or importing breakpad.
+        """
         return (self._check_paths_for_depot_tools(self._sys_path) or
                 self._check_paths_for_depot_tools(self._env_path) or
                 self._check_upward_for_depot_tools())
@@ -158,6 +157,8 @@
         return None
 
     def _check_upward_for_depot_tools(self):
+        # TODO(qyearsley): Remove this, since on Chromium developer machines
+        # we generally assume that depot_tools is in PATH.
         fs = self._filesystem
         prev_dir = ''
         current_dir = fs.dirname(self._webkit_base())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder_unittest.py
index 84e804f..c5a30d7 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder_unittest.py
@@ -10,24 +10,6 @@
 
 class TestPathFinder(unittest.TestCase):
 
-    # TODO(qyearsley): Add tests for other methods in PathFinder.
-    # Including tests for cases when the separator character is backslash.
-
-    def test_layout_test_name(self):
-        finder = PathFinder(MockFileSystem())
-        self.assertEqual(
-            finder.layout_test_name('third_party/WebKit/LayoutTests/test/name.html'),
-            'test/name.html')
-
-    def test_layout_test_name_not_in_layout_tests_dir(self):
-        finder = PathFinder(MockFileSystem())
-        self.assertIsNone(finder.layout_test_name('some/other/path/file.html'))
-
-    # pylint: disable=protected-access
-    def test_webkit_base(self):
-        finder = PathFinder(MockFileSystem())
-        self.assertEqual(finder._webkit_base(), '/mock-checkout/third_party/WebKit')
-
     def test_chromium_base(self):
         finder = PathFinder(MockFileSystem())
         self.assertEqual(finder.chromium_base(), '/mock-checkout')
@@ -37,3 +19,54 @@
         self.assertEqual(
             finder.path_from_chromium_base('foo', 'bar.baz'),
             '/mock-checkout/foo/bar.baz')
+
+    def test_layout_tests_dir(self):
+        finder = PathFinder(MockFileSystem())
+        self.assertEqual(
+            finder.layout_tests_dir(),
+            '/mock-checkout/third_party/WebKit/LayoutTests')
+
+    def test_layout_tests_dir_with_backslash_sep(self):
+        filesystem = MockFileSystem()
+        filesystem.sep = '\\'
+        filesystem.path_to_module = lambda _: (
+            'C:\\mock-checkout\\third_party\\WebKit\\Tools\\Scripts\\webkitpy\\foo.py')
+        finder = PathFinder(filesystem)
+        self.assertEqual(
+            finder.layout_tests_dir(),
+            'C:\\mock-checkout\\third_party\\WebKit\\LayoutTests')
+
+    def test_perf_tests_dir(self):
+        finder = PathFinder(MockFileSystem())
+        self.assertEqual(
+            finder.perf_tests_dir(),
+            '/mock-checkout/third_party/WebKit/PerformanceTests')
+
+    def test_path_from_layout_tests(self):
+        finder = PathFinder(MockFileSystem())
+        self.assertEqual(
+            finder.path_from_layout_tests('external', 'wpt'),
+            '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt')
+
+    def test_layout_test_name(self):
+        finder = PathFinder(MockFileSystem())
+        self.assertEqual(
+            finder.layout_test_name('third_party/WebKit/LayoutTests/test/name.html'),
+            'test/name.html')
+
+    def test_layout_test_name_not_in_layout_tests_dir(self):
+        finder = PathFinder(MockFileSystem())
+        self.assertIsNone(
+            finder.layout_test_name('some/other/path/file.html'))
+
+    def test_depot_tools_base_not_found(self):
+        finder = PathFinder(MockFileSystem(), sys_path=['/foo'], env_path=['/bar'])
+        self.assertIsNone(finder.depot_tools_base())
+
+    def test_depot_tools_base_in_sys_path(self):
+        finder = PathFinder(MockFileSystem(), sys_path=['/foo/bar/depot_tools'], env_path=['/bar'])
+        self.assertEqual(finder.depot_tools_base(), '/foo/bar/depot_tools')
+
+    def test_depot_tools_base_in_env_path(self):
+        finder = PathFinder(MockFileSystem(), sys_path=['/foo'], env_path=['/baz/bin/depot_tools'])
+        self.assertEqual(finder.depot_tools_base(), '/baz/bin/depot_tools')
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 6f25e30..9a0f5ed 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -81,7 +81,7 @@
   # START chrome/browser section.
   "chrome/browser/browser_resources.grd": {
     "includes": [11000],
-    "structures": [11510],
+    "structures": [11520],
   },
   "chrome/browser/resources/component_extension_resources.grd": {
     "includes": [11610],