diff --git a/AUTHORS b/AUTHORS
index 6703fd7c..5dac9b0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -316,6 +316,7 @@
 Jake Hendy <me@jakehendy.com>
 Jakob Weigert <jakob.j.w@googlemail.com>
 Jakub Machacek <xtreit@gmail.com>
+James Burton <jb@0.me.uk>
 James Choi <jchoi42@pha.jhu.edu>
 James Stanley <james@apphaus.co.uk>
 James Vega <vega.james@gmail.com>
diff --git a/DEPS b/DEPS
index 6bb9bff..2ebfe06 100644
--- a/DEPS
+++ b/DEPS
@@ -347,10 +347,6 @@
     'src/third_party/mingw-w64/mingw/bin':
       Var('chromium_git') + '/native_client/deps/third_party/mingw-w64/mingw/bin.git' + '@' + '3cc8b140b883a9fe4986d12cfd46c16a093d3527',
 
-    # Dependencies used by libjpeg-turbo
-    'src/third_party/yasm/binaries':
-      Var('chromium_git') + '/chromium/deps/yasm/binaries.git' + '@' + '52f9b3f4b0aa06da24ef8b123058bb61ee468881',
-
     # Binaries for nacl sdk.
     'src/third_party/nacl_sdk_binaries':
       Var('chromium_git') + '/chromium/deps/nacl_sdk_binaries.git' + '@' + '759dfca03bdc774da7ecbf974f6e2b84f43699a5',
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc
index e3bd36e5..d091e72 100644
--- a/ash/frame/caption_buttons/frame_caption_button.cc
+++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -124,6 +124,10 @@
   CustomButton::OnGestureEvent(event);
 }
 
+views::PaintInfo::ScaleType FrameCaptionButton::GetPaintScaleType() const {
+  return views::PaintInfo::ScaleType::kScaleToScaleFactor;
+}
+
 void FrameCaptionButton::PaintButtonContents(gfx::Canvas* canvas) {
   SkAlpha bg_alpha = SK_AlphaTRANSPARENT;
   if (hover_animation().is_animating())
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h
index 2d05f6ed..4d369a225 100644
--- a/ash/frame/caption_buttons/frame_caption_button.h
+++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -49,6 +49,7 @@
   // views::View overrides:
   const char* GetClassName() const override;
   void OnGestureEvent(ui::GestureEvent* event) override;
+  views::PaintInfo::ScaleType GetPaintScaleType() const override;
 
   void set_paint_as_active(bool paint_as_active) {
     paint_as_active_ = paint_as_active;
diff --git a/ash/shelf/voice_interaction_overlay.cc b/ash/shelf/voice_interaction_overlay.cc
index ef03f42..1a4d07e 100644
--- a/ash/shelf/voice_interaction_overlay.cc
+++ b/ash/shelf/voice_interaction_overlay.cc
@@ -19,6 +19,7 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/user_metrics.h"
@@ -655,10 +656,14 @@
   transform.Scale(scale_factor, scale_factor);
   icon_layer_->SetTransform(transform);
 
+  const bool is_tablet_mode = Shell::Get()
+                                  ->tablet_mode_controller()
+                                  ->IsTabletModeWindowManagerEnabled();
+  const int icon_x_offset = is_tablet_mode ? 0 : kIconOffsetDip;
   // Setup icon animation.
   scale_factor = kIconSizeDip / kIconInitSizeDip;
   transform.MakeIdentity();
-  transform.Translate(center.x() - kIconSizeDip / 2 + kIconOffsetDip,
+  transform.Translate(center.x() - kIconSizeDip / 2 + icon_x_offset,
                       center.y() - kIconSizeDip / 2 - kIconOffsetDip);
   transform.Scale(scale_factor, scale_factor);
 
@@ -686,7 +691,7 @@
   // Setup background animation.
   scale_factor = kBackgroundSizeDip / kBackgroundInitSizeDip;
   transform.MakeIdentity();
-  transform.Translate(center.x() - kBackgroundSizeDip / 2 + kIconOffsetDip,
+  transform.Translate(center.x() - kBackgroundSizeDip / 2 + icon_x_offset,
                       center.y() - kBackgroundSizeDip / 2 - kIconOffsetDip);
   transform.Scale(scale_factor, scale_factor);
 
@@ -769,7 +774,11 @@
   // We want to animate from the background's current position into a larger
   // size. The animation moves the background's center point while morphing from
   // circle to a rectangle.
-  float x_offset = center.x() - kBackgroundSizeDip / 2 + kIconOffsetDip;
+  const bool is_tablet_mode = Shell::Get()
+                                  ->tablet_mode_controller()
+                                  ->IsTabletModeWindowManagerEnabled();
+  const int icon_x_offset = is_tablet_mode ? 0 : kIconOffsetDip;
+  float x_offset = center.x() - kBackgroundSizeDip / 2 + icon_x_offset;
   float y_offset = center.y() - kBackgroundSizeDip / 2 - kIconOffsetDip;
 
   background_layer_->AnimateToLarge(
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 4e83767..7c76c75 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -11,6 +11,8 @@
 #include "ash/keyboard/test_keyboard_ui.h"
 #include "ash/palette_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/shell/context_menu.h"
 #include "ash/shell/example_factory.h"
@@ -102,7 +104,11 @@
 
 void ShellDelegateImpl::OpenUrlFromArc(const GURL& url) {}
 
-void ShellDelegateImpl::ShelfInit() {}
+void ShellDelegateImpl::ShelfInit() {
+  Shelf* shelf = Shell::GetPrimaryRootWindowController()->shelf();
+  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
+}
 
 void ShellDelegateImpl::ShelfShutdown() {}
 
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc
index 70f38a6..a4ed5b0c 100644
--- a/ash/shell/window_watcher.cc
+++ b/ash/shell/window_watcher.cc
@@ -16,11 +16,19 @@
 #include "ash/wm/window_util.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/aura/window.h"
 
 namespace ash {
 namespace shell {
 
+namespace {
+
+constexpr int kContainerIds[] = {kShellWindowId_DefaultContainer,
+                                 kShellWindowId_PanelContainer};
+
+}  // namespace
+
 class WindowWatcher::WorkspaceWindowWatcher : public aura::WindowObserver {
  public:
   explicit WorkspaceWindowWatcher(WindowWatcher* watcher) : watcher_(watcher) {}
@@ -37,27 +45,21 @@
   }
 
   void RootWindowAdded(aura::Window* root) {
-    aura::Window* panel_container =
-        Shell::GetContainer(root, kShellWindowId_PanelContainer);
-    panel_container->AddObserver(watcher_);
-
-    aura::Window* container =
-        Shell::GetContainer(root, kShellWindowId_ShelfContainer);
-    container->AddObserver(this);
-    for (size_t i = 0; i < container->children().size(); ++i)
-      container->children()[i]->AddObserver(watcher_);
+    for (const int container_id : kContainerIds) {
+      aura::Window* container = root->GetChildById(container_id);
+      container->AddObserver(watcher_);
+      for (aura::Window* window : container->children())
+        watcher_->OnWindowAdded(window);
+    }
   }
 
   void RootWindowRemoved(aura::Window* root) {
-    aura::Window* panel_container =
-        Shell::GetContainer(root, kShellWindowId_PanelContainer);
-    panel_container->RemoveObserver(watcher_);
-
-    aura::Window* container =
-        Shell::GetContainer(root, kShellWindowId_ShelfContainer);
-    container->RemoveObserver(this);
-    for (size_t i = 0; i < container->children().size(); ++i)
-      container->children()[i]->RemoveObserver(watcher_);
+    for (const int container_id : kContainerIds) {
+      aura::Window* container = root->GetChildById(container_id);
+      container->RemoveObserver(watcher_);
+      for (aura::Window* window : container->children())
+        watcher_->OnWillRemoveWindow(window);
+    }
   }
 
  private:
@@ -69,19 +71,13 @@
 WindowWatcher::WindowWatcher() {
   Shell::Get()->AddShellObserver(this);
   workspace_window_watcher_ = base::MakeUnique<WorkspaceWindowWatcher>(this);
-  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
-  for (aura::Window::Windows::iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    workspace_window_watcher_->RootWindowAdded(*iter);
-  }
+  for (aura::Window* root : Shell::GetAllRootWindows())
+    workspace_window_watcher_->RootWindowAdded(root);
 }
 
 WindowWatcher::~WindowWatcher() {
-  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
-  for (aura::Window::Windows::iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    workspace_window_watcher_->RootWindowRemoved(*iter);
-  }
+  for (aura::Window* root : Shell::GetAllRootWindows())
+    workspace_window_watcher_->RootWindowRemoved(root);
   Shell::Get()->RemoveShellObserver(this);
 }
 
@@ -95,7 +91,6 @@
   if (!wm::IsWindowUserPositionable(new_window))
     return;
 
-  static int image_count = 0;
   ShelfModel* model = Shell::Get()->shelf_model();
   ShelfItem item;
   item.type = new_window->type() == aura::client::WINDOW_TYPE_PANEL
@@ -107,12 +102,10 @@
 
   SkBitmap icon_bitmap;
   icon_bitmap.allocN32Pixels(16, 16);
-  icon_bitmap.eraseARGB(255, image_count == 0 ? 255 : 0,
-                        image_count == 1 ? 255 : 0, image_count == 2 ? 255 : 0);
-  image_count = (image_count + 1) % 3;
+  constexpr SkColor colors[] = {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE};
+  icon_bitmap.eraseColor(colors[shelf_id % 3]);
   item.image = gfx::ImageSkia(gfx::ImageSkiaRep(icon_bitmap, 1.0f));
-  item.title = new_window->GetTitle();
-
+  item.title = base::IntToString16(shelf_id);
   model->Add(item);
 
   model->SetShelfItemDelegate(
diff --git a/ash/shell/window_watcher.h b/ash/shell/window_watcher.h
index 541d6d7..2b7147b1 100644
--- a/ash/shell/window_watcher.h
+++ b/ash/shell/window_watcher.h
@@ -16,10 +16,6 @@
 #include "base/macros.h"
 #include "ui/aura/window_observer.h"
 
-namespace aura {
-class Window;
-}
-
 namespace ash {
 namespace shell {
 
diff --git a/base/process/process_fuchsia.cc b/base/process/process_fuchsia.cc
index ec16e28..e48d7af 100644
--- a/base/process/process_fuchsia.cc
+++ b/base/process/process_fuchsia.cc
@@ -126,7 +126,7 @@
 }
 
 bool Process::Terminate(int exit_code, bool wait) const {
-  // exit_code isn't supportable.
+  // exit_code isn't supportable. https://crbug.com/753490.
   mx_status_t status = mx_task_kill(process_.get());
   // TODO(scottmg): Put these LOG/CHECK back to DLOG/DCHECK after
   // https://crbug.com/750756 is diagnosed.
diff --git a/cc/ipc/BUILD.gn b/cc/ipc/BUILD.gn
index 3a267f92..e9d087d 100644
--- a/cc/ipc/BUILD.gn
+++ b/cc/ipc/BUILD.gn
@@ -53,7 +53,6 @@
     "shared_bitmap_allocation_notifier.mojom",
     "shared_quad_state.mojom",
     "surface_id.mojom",
-    "surface_sequence.mojom",
     "texture_mailbox.mojom",
     "texture_mailbox_releaser.mojom",
     "transferable_resource.mojom",
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 0586f98..9b57eb0 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -97,11 +97,6 @@
     std::move(callback).Run(s);
   }
 
-  void EchoSurfaceSequence(const viz::SurfaceSequence& s,
-                           EchoSurfaceSequenceCallback callback) override {
-    std::move(callback).Run(s);
-  }
-
   void EchoTextureMailbox(const viz::TextureMailbox& t,
                           EchoTextureMailboxCallback callback) override {
     std::move(callback).Run(t);
@@ -874,17 +869,6 @@
   EXPECT_EQ(local_surface_id, output.local_surface_id());
 }
 
-TEST_F(StructTraitsTest, SurfaceSequence) {
-  const viz::FrameSinkId frame_sink_id(2016, 1234);
-  const uint32_t sequence = 0xfbadbeef;
-  viz::SurfaceSequence input(frame_sink_id, sequence);
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  viz::SurfaceSequence output;
-  proxy->EchoSurfaceSequence(input, &output);
-  EXPECT_EQ(frame_sink_id, output.frame_sink_id);
-  EXPECT_EQ(sequence, output.sequence);
-}
-
 TEST_F(StructTraitsTest, SharedQuadState) {
   const gfx::Transform quad_to_target_transform(1.f, 2.f, 3.f, 4.f, 5.f, 6.f,
                                                 7.f, 8.f, 9.f, 10.f, 11.f, 12.f,
diff --git a/cc/ipc/surface_sequence.typemap b/cc/ipc/surface_sequence.typemap
deleted file mode 100644
index e05d72e..0000000
--- a/cc/ipc/surface_sequence.typemap
+++ /dev/null
@@ -1,11 +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.
-
-mojom = "//cc/ipc/surface_sequence.mojom"
-public_headers = [ "//components/viz/common/surfaces/surface_sequence.h" ]
-traits_headers = [ "//cc/ipc/surface_sequence_struct_traits.h" ]
-deps = [
-  "//components/viz/common",
-]
-type_mappings = [ "cc.mojom.SurfaceSequence=viz::SurfaceSequence" ]
diff --git a/cc/ipc/traits_test_service.mojom b/cc/ipc/traits_test_service.mojom
index d38c0d752..0f5f3cca 100644
--- a/cc/ipc/traits_test_service.mojom
+++ b/cc/ipc/traits_test_service.mojom
@@ -15,7 +15,6 @@
 import "cc/ipc/selection.mojom";
 import "cc/ipc/shared_quad_state.mojom";
 import "cc/ipc/surface_id.mojom";
-import "cc/ipc/surface_sequence.mojom";
 import "cc/ipc/texture_mailbox.mojom";
 import "cc/ipc/transferable_resource.mojom";
 
@@ -57,9 +56,6 @@
   EchoSurfaceId(SurfaceId s) => (SurfaceId pass);
 
   [Sync]
-  EchoSurfaceSequence(SurfaceSequence s) => (SurfaceSequence pass);
-
-  [Sync]
   EchoTextureMailbox(TextureMailbox t) =>
       (TextureMailbox pass);
 
diff --git a/cc/ipc/typemaps.gni b/cc/ipc/typemaps.gni
index f6963c4e..bbbcdc7 100644
--- a/cc/ipc/typemaps.gni
+++ b/cc/ipc/typemaps.gni
@@ -15,7 +15,6 @@
   "//cc/ipc/selection.typemap",
   "//cc/ipc/shared_quad_state.typemap",
   "//cc/ipc/surface_id.typemap",
-  "//cc/ipc/surface_sequence.typemap",
   "//cc/ipc/texture_mailbox.typemap",
   "//cc/ipc/transferable_resource.typemap",
 ]
diff --git a/cc/quads/draw_polygon.cc b/cc/quads/draw_polygon.cc
index 43642fa..98da20ec 100644
--- a/cc/quads/draw_polygon.cc
+++ b/cc/quads/draw_polygon.cc
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/memory/ptr_util.h"
-#include "cc/output/bsp_compare_result.h"
 #include "cc/quads/draw_quad.h"
 
 namespace {
diff --git a/cc/quads/draw_polygon.h b/cc/quads/draw_polygon.h
index 351d3cb..34625dc 100644
--- a/cc/quads/draw_polygon.h
+++ b/cc/quads/draw_polygon.h
@@ -9,7 +9,6 @@
 
 #include "cc/base/math_util.h"
 #include "cc/cc_export.h"
-#include "cc/output/bsp_compare_result.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/quad_f.h"
 #include "ui/gfx/geometry/rect_f.h"
diff --git a/cc/quads/draw_quad.cc b/cc/quads/draw_quad.cc
index d5edffeb..76141d0 100644
--- a/cc/quads/draw_quad.cc
+++ b/cc/quads/draw_quad.cc
@@ -11,15 +11,6 @@
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "cc/debug/traced_value.h"
-#include "cc/quads/debug_border_draw_quad.h"
-#include "cc/quads/picture_draw_quad.h"
-#include "cc/quads/render_pass_draw_quad.h"
-#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/quads/stream_video_draw_quad.h"
-#include "cc/quads/surface_draw_quad.h"
-#include "cc/quads/texture_draw_quad.h"
-#include "cc/quads/tile_draw_quad.h"
-#include "cc/quads/yuv_video_draw_quad.h"
 #include "ui/gfx/geometry/quad_f.h"
 
 namespace cc {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 0db0159..a460ba0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -148,6 +148,7 @@
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
 import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
+import org.chromium.chrome.browser.widget.textbubble.TextBubble;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.content.browser.ContentVideoView;
 import org.chromium.content.browser.ContentViewCore;
@@ -1839,6 +1840,8 @@
     @Override
     public final void onBackPressed() {
         if (mNativeInitialized) RecordUserAction.record("SystemBack");
+
+        TextBubble.onBackPressed();
         if (VrShellDelegate.onBackPressed()) return;
         if (mCompositorViewHolder != null) {
             LayoutManager layoutManager = mCompositorViewHolder.getLayoutManager();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 2ac057a..257a7a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -215,6 +215,13 @@
     /** The task id of the activity that tabs were merged into. */
     private static int sMergedInstanceTaskId;
 
+    /**
+     * Time in ms from when we last backgrounded Chrome until we show the bottom sheet at half.
+     * Time is 3 hours.
+     * crbug.com/706258
+     */
+    private static final long TIME_SINCE_BACKGROUNDED_TO_SHOW_BOTTOM_SHEET_HALF_MS = 10800000L;
+
     private final ActivityStopMetrics mActivityStopMetrics;
     private final MainIntentBehaviorMetrics mMainIntentMetrics;
 
@@ -656,7 +663,7 @@
             super.onNewIntentWithNative(intent);
             if (isMainIntentFromLauncher(intent)) {
                 if (IntentHandler.getUrlFromIntent(intent) == null) {
-                    maybeLaunchNtpFromMainIntent(intent);
+                    maybeLaunchNtpOrResetBottomSheetFromMainIntent(intent);
                 }
                 logMainIntentBehavior(intent);
             }
@@ -837,9 +844,7 @@
     private void logMainIntentBehavior(Intent intent) {
         assert isMainIntentFromLauncher(intent);
         long currentTime = System.currentTimeMillis();
-        long lastBackgroundedTimeMs = ContextUtils.getAppSharedPreferences().getLong(
-                LAST_BACKGROUNDED_TIME_MS_PREF, currentTime);
-        mMainIntentMetrics.onMainIntentWithNative(currentTime - lastBackgroundedTimeMs);
+        mMainIntentMetrics.onMainIntentWithNative(currentTime - getTimeSinceLastBackgroundedMs());
     }
 
     /** Access the main intent metrics for test validation. */
@@ -849,16 +854,23 @@
     }
 
     /**
-     * Determines if the intent should trigger an NTP and launches it if applicable.
+     * Determines if the intent should trigger an NTP and launches it if applicable. If Chrome Home
+     * is enabled, we reset the bottom sheet state to half after some time being backgrounded.
      *
      * @param intent The intent to check whether an NTP should be triggered.
      * @return Whether an NTP was triggered as a result of this intent.
      */
-    private boolean maybeLaunchNtpFromMainIntent(Intent intent) {
+    private boolean maybeLaunchNtpOrResetBottomSheetFromMainIntent(Intent intent) {
         assert isMainIntentFromLauncher(intent);
 
         if (!mIntentHandler.isIntentUserVisible()) return false;
-        if (FeatureUtilities.isChromeHomeEnabled()) return false;
+
+        if (FeatureUtilities.isChromeHomeEnabled()) {
+            BottomSheet bottomSheet = getBottomSheet();
+            assert bottomSheet != null;
+            maybeSetBottomSheetStateToHalfOnStartup(bottomSheet);
+            return false;
+        }
 
         if (!ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_LAUNCH_AFTER_INACTIVITY)) {
             return false;
@@ -915,6 +927,26 @@
         return true;
     }
 
+    private boolean maybeSetBottomSheetStateToHalfOnStartup(BottomSheet bottomSheet) {
+        if (getTimeSinceLastBackgroundedMs()
+                >= TIME_SINCE_BACKGROUNDED_TO_SHOW_BOTTOM_SHEET_HALF_MS) {
+            bottomSheet.getBottomSheetMetrics().recordSheetOpenReason(
+                    BottomSheetMetrics.OPENED_BY_STARTUP);
+            bottomSheet.setSheetState(BottomSheet.SHEET_STATE_HALF, true);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the number of milliseconds since Chrome was last backgrounded.
+     */
+    private long getTimeSinceLastBackgroundedMs() {
+        long lastBackgroundedTimeMs =
+                ContextUtils.getAppSharedPreferences().getLong(LAST_BACKGROUNDED_TIME_MS_PREF, -1);
+        return System.currentTimeMillis() - lastBackgroundedTimeMs;
+    }
+
     @Override
     public void initializeState() {
         // This method goes through 3 steps:
@@ -969,7 +1001,7 @@
                     if (IntentHandler.getUrlFromIntent(intent) == null) {
                         assert !mIntentWithEffect
                                 : "ACTION_MAIN should not have triggered any prior action";
-                        mIntentWithEffect = maybeLaunchNtpFromMainIntent(intent);
+                        mIntentWithEffect = maybeLaunchNtpOrResetBottomSheetFromMainIntent(intent);
                     }
                     logMainIntentBehavior(intent);
                 }
@@ -2212,10 +2244,11 @@
 
         Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile());
         tracker.notifyEvent(EventConstants.SCREENSHOT_TAKEN_CHROME_IN_FOREGROUND);
-        maybeShowFeatureEngagementTextBubbleForDownloadPage(tracker);
+        maybeShowFeatureEngagementTextBubbleForDownloadPageScreenshot(tracker);
     }
 
-    private void maybeShowFeatureEngagementTextBubbleForDownloadPage(final Tracker tracker) {
+    private void maybeShowFeatureEngagementTextBubbleForDownloadPageScreenshot(
+            final Tracker tracker) {
         if (!tracker.shouldTriggerHelpUI(FeatureConstants.DOWNLOAD_PAGE_SCREENSHOT_FEATURE)) return;
 
         ViewAnchoredTextBubble textBubble =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
index d0bf423..c5f0e75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
@@ -27,11 +27,13 @@
 
     private boolean mImpressionTracked;
     private int mPerSectionRank = -1;
+    private boolean mEnabled;
 
     public ActionItem(SuggestionsSection section, SuggestionsRanker ranker) {
         mCategoryInfo = section.getCategoryInfo();
         mParentSection = section;
         mSuggestionsRanker = ranker;
+        mEnabled = true;
         setVisibilityInternal(
                 mCategoryInfo.getAdditionalAction() != ContentSuggestionsAdditionalAction.NONE);
     }
@@ -68,6 +70,8 @@
 
     @VisibleForTesting
     void performAction(SuggestionsUiDelegate uiDelegate) {
+        if (!mEnabled) return;
+
         uiDelegate.getEventReporter().onMoreButtonClicked(this);
 
         switch (mCategoryInfo.getAdditionalAction()) {
@@ -90,6 +94,11 @@
         }
     }
 
+    /** Used to enable/disable the action of this item. */
+    public void setEnabled(boolean enabled) {
+        mEnabled = enabled;
+    }
+
     /** ViewHolder associated to {@link ItemViewType#ACTION}. */
     public static class ViewHolder extends CardViewHolder implements ContextMenuManager.Delegate {
         private ActionItem mActionListItem;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index f7194d2..0e7250bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -471,6 +471,9 @@
 
     /** Fetches additional suggestions only for this section. */
     public void fetchSuggestions() {
+        // We want to disable the action item while we are fetching suggestions in order to
+        // avoid fetching the same suggestions twice. See crbug.com/739648.
+        mMoreButton.setEnabled(false);
         mSuggestionsSource.fetchSuggestions(mCategoryInfo.getCategory(),
                 getDisplayedSuggestionIds(), new Callback<List<SnippetArticle>>() {
                     @Override
@@ -479,6 +482,7 @@
 
                         mProgressIndicator.setVisible(false);
                         appendSuggestions(additionalSuggestions, /*keepSectionSize=*/false);
+                        mMoreButton.setEnabled(true);
                     }
                 });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
index 9fb1154..714b938 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
@@ -23,14 +23,15 @@
      * histogram and should therefore be treated as append-only.
      */
     @IntDef({OPENED_BY_SWIPE, OPENED_BY_OMNIBOX_FOCUS, OPENED_BY_NEW_TAB_CREATION,
-            OPENED_BY_EXPAND_BUTTON})
+            OPENED_BY_EXPAND_BUTTON, OPENED_BY_STARTUP})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SheetOpenReason {}
     public static final int OPENED_BY_SWIPE = 0;
     public static final int OPENED_BY_OMNIBOX_FOCUS = 1;
     public static final int OPENED_BY_NEW_TAB_CREATION = 2;
     public static final int OPENED_BY_EXPAND_BUTTON = 3;
-    private static final int OPENED_BY_BOUNDARY = 4;
+    public static final int OPENED_BY_STARTUP = 4;
+    private static final int OPENED_BY_BOUNDARY = 5;
 
     /** The different ways that the bottom sheet can be closed. */
     @IntDef({CLOSED_BY_NONE, CLOSED_BY_SWIPE, CLOSED_BY_BACK_PRESS, CLOSED_BY_TAP_SCRIM,
@@ -160,6 +161,9 @@
             case OPENED_BY_EXPAND_BUTTON:
                 RecordUserAction.record("Android.ChromeHome.OpenedByExpandButton");
                 break;
+            case OPENED_BY_STARTUP:
+                RecordUserAction.record("Android.ChromeHome.OpenedByStartup");
+                break;
             default:
                 assert false;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java
index 7473465..cc81dbc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java
@@ -28,6 +28,9 @@
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.MathUtils;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * UI component that handles showing a text callout bubble.  Positioning this bubble happens through
  * calls to {@link #setAnchorRect(Rect)}.  This should be called at least once before the
@@ -40,6 +43,12 @@
      */
     public static final long NO_TIMEOUT = 0;
 
+    /**
+     * A set of bubbles which are active at this moment. This set can be used to dismiss the
+     * bubbles on a back press event.
+     */
+    private static final Set<TextBubble> sBubbles = new HashSet<>();
+
     // Cache Rect objects for querying View and Screen coordinate APIs.
     private final Rect mCachedPaddingRect = new Rect();
     private final Rect mCachedWindowRect = new Rect();
@@ -74,6 +83,8 @@
 
             mHandler.removeCallbacks(mDismissRunnable);
             for (OnDismissListener listener : mDismissListeners) listener.onDismiss();
+
+            sBubbles.remove(TextBubble.this);
         }
     };
 
@@ -154,6 +165,8 @@
         createContentView();
         updateBubbleLayout();
         mPopupWindow.showAtLocation(mRootView, Gravity.TOP | Gravity.START, mX, mY);
+
+        sBubbles.add(this);
     }
 
     /**
@@ -165,6 +178,16 @@
     }
 
     /**
+     * Dismisses the active bubbles if user has pressed the back button.
+     */
+    public static void onBackPressed() {
+        Set<TextBubble> bubbles = new HashSet<>(sBubbles);
+        for (TextBubble bubble : bubbles) {
+            bubble.dismiss();
+        }
+    }
+
+    /**
      * @param onTouchListener A callback for all touch events being dispatched to the bubble.
      * @see PopupWindow#setTouchInterceptor(OnTouchListener)
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
index 0eadac17..b055386 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
@@ -224,7 +224,7 @@
 
             // Cannot use EmbeddedTestServer#createAndStartServer(), as we need to add the
             // connection listener.
-            server.initializeNative(mContext);
+            server.initializeNative(mContext, EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
             server.addDefaultHandlers("");
             server.setConnectionListener(new EmbeddedTestServer.ConnectionListener() {
                 @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 43621f92..e768942 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -18,7 +18,6 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.ImageButton;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.junit.Assert;
@@ -31,7 +30,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.EnormousTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.ScalableTimeout;
@@ -56,6 +54,7 @@
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.content.browser.test.util.UiUtils;
 import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.net.test.ServerCertificate;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.HashMap;
@@ -594,20 +593,16 @@
     }
 
     /**
-     * Test to verify security-icon "lock or globe" on visiting http and secured Urls.
-     * @EnormousTest
+     * Test to verify that the security icon is present when visiting http:// URLs.
      */
     @Test
-    @FlakyTest(message = "crbug.com/414353")
-    public void testSecurityIcon() throws InterruptedException {
+    @MediumTest
+    public void testSecurityIconOnHTTP() throws InterruptedException {
         EmbeddedTestServer testServer = EmbeddedTestServer.createAndStartServer(
                 InstrumentationRegistry.getInstrumentation().getContext());
         try {
             final String testUrl = testServer.getURL("/chrome/test/data/android/omnibox/one.html");
-            final String securedExternalUrl = "https://www.google.com";
 
-            ImageView navigationButton = (ImageView) mActivityTestRule.getActivity().findViewById(
-                    R.id.navigation_button);
             ImageButton securityButton = (ImageButton) mActivityTestRule.getActivity().findViewById(
                     R.id.security_button);
 
@@ -617,20 +612,39 @@
                             R.id.location_bar);
             boolean securityIcon = locationBar.isSecurityButtonShown();
             Assert.assertFalse("Omnibox should not have a Security icon", securityIcon);
-            Assert.assertEquals("navigation_button with wrong resource-id", R.id.navigation_button,
-                    navigationButton.getId());
-            Assert.assertTrue(navigationButton.isShown());
             Assert.assertFalse(securityButton.isShown());
+        } finally {
+            testServer.stopAndDestroyServer();
+        }
+    }
 
-            mActivityTestRule.loadUrl(securedExternalUrl);
-            securityIcon = locationBar.isSecurityButtonShown();
+    /**
+     * Test to verify that the security icon is present when visiting https:// URLs.
+     */
+    @Test
+    @MediumTest
+    public void testSecurityIconOnHTTPS() throws InterruptedException {
+        EmbeddedTestServer httpsTestServer = EmbeddedTestServer.createAndStartHTTPSServer(
+                InstrumentationRegistry.getInstrumentation().getContext(),
+                ServerCertificate.CERT_OK);
+        try {
+            final String testHttpsUrl =
+                    httpsTestServer.getURL("/chrome/test/data/android/omnibox/one.html");
+
+            ImageButton securityButton = (ImageButton) mActivityTestRule.getActivity().findViewById(
+                    R.id.security_button);
+
+            mActivityTestRule.loadUrl(testHttpsUrl);
+            final LocationBarLayout locationBar =
+                    (LocationBarLayout) mActivityTestRule.getActivity().findViewById(
+                            R.id.location_bar);
+            boolean securityIcon = locationBar.isSecurityButtonShown();
             Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
             Assert.assertEquals("security_button with wrong resource-id", R.id.security_button,
                     securityButton.getId());
             Assert.assertTrue(securityButton.isShown());
-            Assert.assertFalse(navigationButton.isShown());
         } finally {
-            testServer.stopAndDestroyServer();
+            httpsTestServer.stopAndDestroyServer();
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
index 9af1320..d79613c8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
@@ -77,25 +77,6 @@
         mPaymentRequestTestRule.getDismissed().waitForCallback(callCount);
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // CanMakePayment was queried.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Usage",
-                        CanMakePaymentUsage.CAN_MAKE_PAYMENT_USED));
-
-        // The CanMakePayment effect on show should be recorded as being false and shown.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-                        CanMakePaymentEffectOnShow.DID_SHOW));
-
-        // There should be a record for an abort when CanMakePayment is false but the PR is shown to
-        // the user.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
         // Make sure the canMakePayment events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.CAN_MAKE_PAYMENT_FALSE;
         Assert.assertEquals(1,
@@ -135,25 +116,6 @@
         mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                 DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed());
 
-        // CanMakePayment was queried.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Usage",
-                        CanMakePaymentUsage.CAN_MAKE_PAYMENT_USED));
-
-        // The CanMakePayment effect on show should be recorded as being false and shown.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-                        CanMakePaymentEffectOnShow.DID_SHOW));
-
-        // There should be a record for a completion when CanMakePayment is false but the PR is
-        // shown to the user.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-                        CompletionStatus.COMPLETED));
-
         // Make sure the canMakePayment events were logged correctly.
         int expectedSample = Event.SHOWN | Event.PAY_CLICKED | Event.RECEIVED_INSTRUMENT_DETAILS
                 | Event.COMPLETED | Event.CAN_MAKE_PAYMENT_FALSE;
@@ -183,26 +145,6 @@
         mPaymentRequestTestRule.clickNodeAndWait("abort", mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Abort"});
 
-        // CanMakePayment was queried.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Usage",
-                        CanMakePaymentUsage.CAN_MAKE_PAYMENT_USED));
-
-        // The CanMakePayment effect on show should be recorded as being false and shown.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-                        CanMakePaymentEffectOnShow.DID_SHOW
-                                | CanMakePaymentEffectOnShow.COULD_MAKE_PAYMENT));
-
-        // There should be a record for an abort when CanMakePayment is false but the PR is shown to
-        // the user.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-                        CompletionStatus.OTHER_ABORTED));
-
         // Make sure the canMakePayment events were logged correctly.
         int expectedSample = Event.SHOWN | Event.OTHER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.CAN_MAKE_PAYMENT_TRUE;
@@ -230,26 +172,6 @@
         mPaymentRequestTestRule.clickAndWait(
                 R.id.button_primary, mPaymentRequestTestRule.getDismissed());
 
-        // CanMakePayment was queried.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Usage",
-                        CanMakePaymentUsage.CAN_MAKE_PAYMENT_USED));
-
-        // The CanMakePayment effect on show should be recorded as being false and shown.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-                        CanMakePaymentEffectOnShow.DID_SHOW
-                                | CanMakePaymentEffectOnShow.COULD_MAKE_PAYMENT));
-
-        // There should be a record for an abort when CanMakePayment is false but the PR is shown to
-        // the user.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-                        CompletionStatus.COMPLETED));
-
         // Make sure the canMakePayment events were logged correctly.
         int expectedSample = Event.SHOWN | Event.PAY_CLICKED | Event.RECEIVED_INSTRUMENT_DETAILS
                 | Event.COMPLETED | Event.HAD_INITIAL_FORM_OF_PAYMENT
@@ -283,19 +205,6 @@
         mPaymentRequestTestRule.getDismissed().waitForCallback(callCount);
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // CanMakePayment was not queried.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Usage",
-                        CanMakePaymentUsage.CAN_MAKE_PAYMENT_NOT_USED));
-
-        // There should be a record for an abort when CanMakePayment is not called but the PR is
-        // shown to the user.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
         // Make sure no canMakePayment events were logged.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED;
         Assert.assertEquals(1,
@@ -321,19 +230,6 @@
         mPaymentRequestTestRule.clickAndWait(
                 R.id.button_primary, mPaymentRequestTestRule.getDismissed());
 
-        // CanMakePayment was not queried.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.Usage",
-                        CanMakePaymentUsage.CAN_MAKE_PAYMENT_NOT_USED));
-
-        // There should be a record for a completion when CanMakePayment is not called but the PR is
-        // shown to the user.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-                        CompletionStatus.COMPLETED));
-
         // Make sure no canMakePayment events were logged.
         int expectedSample = Event.SHOWN | Event.PAY_CLICKED | Event.RECEIVED_INSTRUMENT_DETAILS
                 | Event.COMPLETED | Event.HAD_INITIAL_FORM_OF_PAYMENT
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
index 2c7c1e28..774b983 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
@@ -576,18 +576,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything.EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING;
@@ -621,19 +609,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.REQUEST_SHIPPING;
@@ -667,19 +642,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.REQUEST_SHIPPING;
@@ -713,19 +675,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING;
         Assert.assertEquals(1,
@@ -756,19 +705,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING;
         Assert.assertEquals(1,
@@ -799,19 +735,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING;
         Assert.assertEquals(1,
@@ -842,18 +765,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything.EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING;
@@ -887,19 +798,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.REQUEST_SHIPPING;
@@ -934,18 +832,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything.EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING;
@@ -978,18 +864,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything.EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING;
@@ -1025,18 +899,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestionsForEverything.EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                        + "EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                 | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING;
@@ -1067,18 +929,6 @@
                 R.id.close_button, mPaymentRequestTestRule.getDismissed());
         mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"});
 
-        // Make sure the metric was logged correctly.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-                                + "EffectOnCompletion",
-                        CompletionStatus.USER_ABORTED));
-
-        // Make sure the opposite metric has no logs.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        "PaymentRequest.UserHadCompleteSuggestions.EffectOnCompletion"));
-
         // Make sure the events were logged correctly.
         int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING;
         Assert.assertEquals(1,
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
index 26656bc1..599ca8d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -1168,18 +1168,25 @@
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.bounds = wallpaper_bounds();
-  params.show_state = ui::SHOW_STATE_FULLSCREEN;
+  // Disable fullscreen state for voice interaction OOBE since the shelf should
+  // be visible.
+  if (!is_voice_interaction_oobe_)
+    params.show_state = ui::SHOW_STATE_FULLSCREEN;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+
+  // Put the voice interaction oobe inside AlwaysOnTop container instead of
+  // LockScreenContainer.
+  ash::ShellWindowId container = is_voice_interaction_oobe_
+                                     ? ash::kShellWindowId_AlwaysOnTopContainer
+                                     : ash::kShellWindowId_LockScreenContainer;
   // The ash::Shell containers are not available in Mash
   if (!ash_util::IsRunningInMash()) {
     params.parent =
-        ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
-                                 ash::kShellWindowId_LockScreenContainer);
+        ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), container);
   } else {
     using ui::mojom::WindowManager;
     params.mus_properties[WindowManager::kContainerId_InitProperty] =
-        mojo::ConvertTo<std::vector<uint8_t>>(
-            static_cast<int32_t>(ash::kShellWindowId_LockScreenContainer));
+        mojo::ConvertTo<std::vector<uint8_t>>(static_cast<int32_t>(container));
   }
   login_window_ = new views::Widget;
   params.delegate = login_window_delegate_ =
@@ -1191,8 +1198,9 @@
   if (login_view_->webui_visible())
     OnLoginPromptVisible();
 
-  // Animations are not available in Mash
-  if (!ash_util::IsRunningInMash()) {
+  // Animations are not available in Mash.
+  // For voice interaction OOBE, we do not want the animation here.
+  if (!ash_util::IsRunningInMash() && !is_voice_interaction_oobe_) {
     login_window_->SetVisibilityAnimationDuration(
         base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
     login_window_->SetVisibilityAnimationTransition(
@@ -1295,13 +1303,6 @@
 
 void LoginDisplayHostImpl::StartVoiceInteractionOobe() {
   is_voice_interaction_oobe_ = true;
-
-  // Lock container can be transparent after lock screen animation.
-  aura::Window* lock_container = ash::Shell::GetContainer(
-      ash::Shell::GetPrimaryRootWindow(),
-      ash::kShellWindowId_LockScreenContainersContainer);
-  lock_container->layer()->SetOpacity(1.0);
-
   finalize_animation_type_ = ANIMATION_NONE;
   StartWizard(chromeos::OobeScreen::SCREEN_VOICE_INTERACTION_VALUE_PROP);
 }
diff --git a/chrome/browser/chromeos/tether/tether_service.cc b/chrome/browser/chromeos/tether/tether_service.cc
index 5a95cfd..2135e18a 100644
--- a/chrome/browser/chromeos/tether/tether_service.cc
+++ b/chrome/browser/chromeos/tether/tether_service.cc
@@ -26,6 +26,15 @@
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "ui/message_center/message_center.h"
 
+namespace {
+
+// TODO (hansberry): Experiment with intervals to determine ideal advertising
+//                   interval parameters. See crbug.com/753215.
+constexpr int64_t kMinAdvertisingIntervalMilliseconds = 100;
+constexpr int64_t kMaxAdvertisingIntervalMilliseconds = 100;
+
+}  // namespace
+
 // static
 TetherService* TetherService::Get(Profile* profile) {
   if (IsFeatureFlagEnabled())
@@ -38,6 +47,22 @@
 void TetherService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(prefs::kInstantTetheringAllowed, true);
   registry->RegisterBooleanPref(prefs::kInstantTetheringEnabled, true);
+
+  // If we initially assume that BLE advertising is not supported, it will
+  // result in Tether's Settings and Quick Settings sections not being visible
+  // when the user logs in with Bluetooth disabled (because the TechnologyState
+  // will be UNAVAILABLE, instead of the desired UNINITIALIZED).
+  //
+  // Initially assuming that BLE advertising *is* supported works well for most
+  // devices, but if a user first logs into a device without BLE advertising
+  // support and with Bluetooth disabled, Tether will be visible in Settings and
+  // Quick Settings, but disappear upon enabling Bluetooth. This is an
+  // acceptable edge case, and likely rare because Bluetooth is enabled by
+  // default on new logins. Additionally, through this pref, we will record if
+  // BLE advertising is not supported and remember that for future logins.
+  registry->RegisterBooleanPref(prefs::kInstantTetheringBleAdvertisingSupported,
+                                true);
+
   chromeos::tether::Initializer::RegisterProfilePrefs(registry);
 }
 
@@ -55,12 +80,13 @@
     chromeos::ManagedNetworkConfigurationHandler*
         managed_network_configuration_handler,
     chromeos::NetworkConnect* network_connect,
-    chromeos::NetworkConnectionHandler* network_connection_handler) {
+    chromeos::NetworkConnectionHandler* network_connection_handler,
+    scoped_refptr<device::BluetoothAdapter> adapter) {
   chromeos::tether::Initializer::Init(
       cryptauth_service, std::move(notification_presenter), pref_service,
       token_service, network_state_handler,
       managed_network_configuration_handler, network_connect,
-      network_connection_handler);
+      network_connection_handler, adapter);
 }
 
 void TetherService::InitializerDelegate::ShutdownTether() {
@@ -121,7 +147,7 @@
       network_state_handler_,
       chromeos::NetworkHandler::Get()->managed_network_configuration_handler(),
       chromeos::NetworkConnect::Get(),
-      chromeos::NetworkHandler::Get()->network_connection_handler());
+      chromeos::NetworkHandler::Get()->network_connection_handler(), adapter_);
 }
 
 void TetherService::StopTetherIfNecessary() {
@@ -184,7 +210,18 @@
 
 void TetherService::AdapterPoweredChanged(device::BluetoothAdapter* adapter,
                                           bool powered) {
-  UpdateTetherTechnologyState();
+  // Once the BLE advertising interval has been set (regardless of if BLE
+  // advertising is supported), simply update the TechnologyState.
+  if (has_attempted_to_set_ble_advertising_interval_) {
+    UpdateTetherTechnologyState();
+    return;
+  }
+
+  // If the BluetoothAdapter was not powered when first fetched (see
+  // OnBluetoothAdapterFetched()), now attempt to set the BLE advertising
+  // interval.
+  if (powered)
+    SetBleAdvertisingInterval();
 }
 
 void TetherService::DefaultNetworkChanged(
@@ -239,6 +276,9 @@
 }
 
 void TetherService::UpdateTetherTechnologyState() {
+  if (!adapter_)
+    return;
+
   chromeos::NetworkStateHandler::TechnologyState new_tether_technology_state =
       GetTetherTechnologyState();
 
@@ -266,8 +306,9 @@
 
 chromeos::NetworkStateHandler::TechnologyState
 TetherService::GetTetherTechnologyState() {
-  if (shut_down_ || suspended_ || session_manager_client_->IsScreenLocked() ||
-      !HasSyncedTetherHosts() || IsCellularAvailableButNotEnabled()) {
+  if (shut_down_ || suspended_ || !GetIsBleAdvertisingSupportedPref() ||
+      session_manager_client_->IsScreenLocked() || !HasSyncedTetherHosts() ||
+      IsCellularAvailableButNotEnabled()) {
     // If Cellular technology is available, then Tether technology is treated
     // as a subset of Cellular, and it should only be enabled when Cellular
     // technology is enabled.
@@ -279,8 +320,7 @@
   } else if (!IsBluetoothAvailable()) {
     // TODO (hansberry): When !IsBluetoothAvailable(), this results in a weird
     // UI state for Settings where the toggle is clickable but immediately
-    // becomes disabled after enabling it.  Possible solution: grey out the
-    // toggle and tell the user to turn Bluetooth on?
+    // becomes disabled after enabling it. See crbug.com/753195.
     return chromeos::NetworkStateHandler::TechnologyState::
         TECHNOLOGY_UNINITIALIZED;
   } else if (!IsEnabledbyPreference()) {
@@ -298,14 +338,59 @@
   adapter_ = adapter;
   adapter_->AddObserver(this);
 
+  // Update TechnologyState in case Tether is otherwise available but Bluetooth
+  // is off.
   UpdateTetherTechnologyState();
 
+  // If |adapter_| is not powered, wait until it is to call
+  // SetBleAdvertisingInterval(). See AdapterPoweredChanged().
+  if (IsBluetoothAvailable())
+    SetBleAdvertisingInterval();
+
   // The user has just logged in; display the "enable Bluetooth" notification if
   // applicable.
   if (CanEnableBluetoothNotificationBeShown())
     notification_presenter_->NotifyEnableBluetooth();
 }
 
+void TetherService::OnBluetoothAdapterAdvertisingIntervalSet() {
+  has_attempted_to_set_ble_advertising_interval_ = true;
+  SetIsBleAdvertisingSupportedPref(true);
+
+  UpdateTetherTechnologyState();
+}
+
+void TetherService::OnBluetoothAdapterAdvertisingIntervalError(
+    device::BluetoothAdvertisement::ErrorCode status) {
+  has_attempted_to_set_ble_advertising_interval_ = true;
+  SetIsBleAdvertisingSupportedPref(false);
+
+  UpdateTetherTechnologyState();
+}
+
+void TetherService::SetBleAdvertisingInterval() {
+  DCHECK(IsBluetoothAvailable());
+  adapter_->SetAdvertisingInterval(
+      base::TimeDelta::FromMilliseconds(kMinAdvertisingIntervalMilliseconds),
+      base::TimeDelta::FromMilliseconds(kMaxAdvertisingIntervalMilliseconds),
+      base::Bind(&TetherService::OnBluetoothAdapterAdvertisingIntervalSet,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&TetherService::OnBluetoothAdapterAdvertisingIntervalError,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+bool TetherService::GetIsBleAdvertisingSupportedPref() {
+  return profile_->GetPrefs()->GetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported);
+}
+
+void TetherService::SetIsBleAdvertisingSupportedPref(
+    bool is_ble_advertising_supported) {
+  profile_->GetPrefs()->SetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported,
+      is_ble_advertising_supported);
+}
+
 bool TetherService::IsBluetoothAvailable() const {
   return adapter_.get() && adapter_->IsPresent() && adapter_->IsPowered();
 }
diff --git a/chrome/browser/chromeos/tether/tether_service.h b/chrome/browser/chromeos/tether/tether_service.h
index 22e40336..4c7d62e 100644
--- a/chrome/browser/chromeos/tether/tether_service.h
+++ b/chrome/browser/chromeos/tether/tether_service.h
@@ -78,7 +78,8 @@
         chromeos::ManagedNetworkConfigurationHandler*
             managed_network_configuration_handler,
         chromeos::NetworkConnect* network_connect,
-        chromeos::NetworkConnectionHandler* network_connection_handler);
+        chromeos::NetworkConnectionHandler* network_connection_handler,
+        scoped_refptr<device::BluetoothAdapter> adapter);
     virtual void ShutdownTether();
   };
 
@@ -131,6 +132,18 @@
 
   void OnBluetoothAdapterFetched(
       scoped_refptr<device::BluetoothAdapter> adapter);
+  void OnBluetoothAdapterAdvertisingIntervalSet();
+  void OnBluetoothAdapterAdvertisingIntervalError(
+      device::BluetoothAdvertisement::ErrorCode status);
+
+  void SetBleAdvertisingInterval();
+
+  // Whether BLE advertising is supported on this device. This should only
+  // return true if a call to BluetoothAdapter::SetAdvertisingInterval() during
+  // TetherService construction succeeds. That method will fail in cases like
+  // those captured in crbug.com/738222.
+  bool GetIsBleAdvertisingSupportedPref();
+  void SetIsBleAdvertisingSupportedPref(bool is_ble_advertising_supported);
 
   bool IsBluetoothAvailable() const;
 
@@ -161,6 +174,8 @@
   // was closed).
   bool suspended_ = false;
 
+  bool has_attempted_to_set_ble_advertising_interval_ = false;
+
   Profile* profile_;
   chromeos::PowerManagerClient* power_manager_client_;
   chromeos::SessionManagerClient* session_manager_client_;
diff --git a/chrome/browser/chromeos/tether/tether_service_unittest.cc b/chrome/browser/chromeos/tether/tether_service_unittest.cc
index 4907316..e63f8bef 100644
--- a/chrome/browser/chromeos/tether/tether_service_unittest.cc
+++ b/chrome/browser/chromeos/tether/tether_service_unittest.cc
@@ -67,6 +67,32 @@
                      std::vector<cryptauth::ExternalDeviceInfo>());
 };
 
+class MockExtendedBluetoothAdapter : public device::MockBluetoothAdapter {
+ public:
+  void SetAdvertisingInterval(
+      const base::TimeDelta& min,
+      const base::TimeDelta& max,
+      const base::Closure& callback,
+      const AdvertisementErrorCallback& error_callback) override {
+    if (is_ble_advertising_supported_) {
+      callback.Run();
+    } else {
+      error_callback.Run(device::BluetoothAdvertisement::ErrorCode::
+                             ERROR_INVALID_ADVERTISEMENT_INTERVAL);
+    }
+  }
+
+  void set_is_ble_advertising_supported(bool is_ble_advertising_supported) {
+    is_ble_advertising_supported_ = is_ble_advertising_supported;
+  }
+
+ protected:
+  ~MockExtendedBluetoothAdapter() override {}
+
+ private:
+  bool is_ble_advertising_supported_ = true;
+};
+
 class TestTetherService : public TetherService {
  public:
   TestTetherService(Profile* profile,
@@ -109,7 +135,8 @@
       chromeos::ManagedNetworkConfigurationHandler*
           managed_network_configuration_handler,
       chromeos::NetworkConnect* network_connect,
-      chromeos::NetworkConnectionHandler* network_connection_handler) override {
+      chromeos::NetworkConnectionHandler* network_connection_handler,
+      scoped_refptr<device::BluetoothAdapter> adapter) override {
     is_tether_running_ = true;
   }
 
@@ -155,8 +182,8 @@
         mock_cryptauth_device_manager_.get());
 
     mock_adapter_ =
-        make_scoped_refptr(new NiceMock<device::MockBluetoothAdapter>());
-    is_adapter_powered_ = true;
+        make_scoped_refptr(new NiceMock<MockExtendedBluetoothAdapter>());
+    SetIsBluetoothPowered(true);
     ON_CALL(*mock_adapter_, IsPresent()).WillByDefault(Return(true));
     ON_CALL(*mock_adapter_, IsPowered())
         .WillByDefault(Invoke(this, &TetherServiceTest::IsBluetoothPowered));
@@ -190,6 +217,14 @@
     tether_service_->SetNotificationPresenterForTest(
         base::WrapUnique(fake_notification_presenter_));
 
+    // Ensure that TetherService does not prematurely update its TechnologyState
+    // before it fetches the BluetoothAdapter.
+    EXPECT_EQ(
+        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
+        network_state_handler()->GetTechnologyState(
+            chromeos::NetworkTypePattern::Tether()));
+    EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+
     base::RunLoop().RunUntilIdle();
   }
 
@@ -221,6 +256,12 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  void SetIsBluetoothPowered(bool powered) {
+    is_adapter_powered_ = powered;
+    for (auto& observer : mock_adapter_->GetObservers())
+      observer.AdapterPoweredChanged(mock_adapter_.get(), powered);
+  }
+
   bool IsBluetoothPowered() { return is_adapter_powered_; }
 
   void DisconnectDefaultShillNetworks() {
@@ -244,7 +285,7 @@
   chromeos::tether::FakeNotificationPresenter* fake_notification_presenter_;
   std::unique_ptr<cryptauth::FakeCryptAuthService> fake_cryptauth_service_;
 
-  scoped_refptr<device::MockBluetoothAdapter> mock_adapter_;
+  scoped_refptr<MockExtendedBluetoothAdapter> mock_adapter_;
   bool is_adapter_powered_;
 
   std::unique_ptr<TestTetherService> tether_service_;
@@ -288,6 +329,93 @@
   EXPECT_TRUE(test_initializer_delegate_->is_tether_running());
 }
 
+TEST_F(TetherServiceTest, TestBleAdvertisingNotSupported) {
+  mock_adapter_->set_is_ble_advertising_supported(false);
+
+  CreateTetherService();
+
+  EXPECT_EQ(
+      chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
+      network_state_handler()->GetTechnologyState(
+          chromeos::NetworkTypePattern::Tether()));
+  EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+}
+
+TEST_F(TetherServiceTest,
+       TestBleAdvertisingNotSupported_BluetoothIsInitiallyNotPowered) {
+  SetIsBluetoothPowered(false);
+
+  mock_adapter_->set_is_ble_advertising_supported(false);
+
+  CreateTetherService();
+
+  // TetherService has not yet been able to find out that BLE advertising is not
+  // supported.
+  EXPECT_EQ(
+      chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
+      network_state_handler()->GetTechnologyState(
+          chromeos::NetworkTypePattern::Tether()));
+  EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+  EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported));
+
+  SetIsBluetoothPowered(true);
+
+  EXPECT_EQ(
+      chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
+      network_state_handler()->GetTechnologyState(
+          chromeos::NetworkTypePattern::Tether()));
+  EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+  EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported));
+}
+
+TEST_F(
+    TetherServiceTest,
+    TestBleAdvertisingNotSupportedAndRecorded_BluetoothIsInitiallyNotPowered) {
+  SetIsBluetoothPowered(false);
+
+  mock_adapter_->set_is_ble_advertising_supported(false);
+
+  // Simulate a login after we determined that BLE advertising is not supported.
+  profile_->GetPrefs()->SetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported, false);
+
+  CreateTetherService();
+
+  EXPECT_EQ(
+      chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
+      network_state_handler()->GetTechnologyState(
+          chromeos::NetworkTypePattern::Tether()));
+  EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+
+  SetIsBluetoothPowered(true);
+
+  EXPECT_EQ(
+      chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
+      network_state_handler()->GetTechnologyState(
+          chromeos::NetworkTypePattern::Tether()));
+  EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+}
+
+TEST_F(TetherServiceTest, TestBleAdvertisingSupportedButIncorrectlyRecorded) {
+  // Simulate a login after we incorrectly determined that BLE advertising is
+  // not supported (this is not an expected case, but may have happened if
+  // BluetoothAdapter::SetAdvertisingInterval() failed for a weird, one-off
+  // reason).
+  profile_->GetPrefs()->SetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported, false);
+
+  CreateTetherService();
+
+  EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
+            network_state_handler()->GetTechnologyState(
+                chromeos::NetworkTypePattern::Tether()));
+  EXPECT_TRUE(test_initializer_delegate_->is_tether_running());
+  EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
+      prefs::kInstantTetheringBleAdvertisingSupported));
+}
+
 TEST_F(TetherServiceTest, TestScreenLock) {
   CreateTetherService();
   EXPECT_TRUE(test_initializer_delegate_->is_tether_running());
@@ -348,8 +476,8 @@
   EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
 }
 
-TEST_F(TetherServiceTest, TestBluetoothIsNotPowered) {
-  is_adapter_powered_ = false;
+TEST_F(TetherServiceTest, TestIsBluetoothPowered) {
+  SetIsBluetoothPowered(false);
 
   CreateTetherService();
 
@@ -358,6 +486,21 @@
       network_state_handler()->GetTechnologyState(
           chromeos::NetworkTypePattern::Tether()));
   EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
+
+  SetIsBluetoothPowered(true);
+
+  EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
+            network_state_handler()->GetTechnologyState(
+                chromeos::NetworkTypePattern::Tether()));
+  EXPECT_TRUE(test_initializer_delegate_->is_tether_running());
+
+  SetIsBluetoothPowered(false);
+
+  EXPECT_EQ(
+      chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
+      network_state_handler()->GetTechnologyState(
+          chromeos::NetworkTypePattern::Tether()));
+  EXPECT_FALSE(test_initializer_delegate_->is_tether_running());
 }
 
 TEST_F(TetherServiceTest, TestCellularIsUnavailable) {
@@ -466,7 +609,7 @@
 // state than the user preference.
 TEST_F(TetherServiceTest, TestEnabledMultipleChanges) {
   CreateTetherService();
-  // CreateTetherService calls RunUntilIdle() so  UpdateTetherTechnologyState()
+  // CreateTetherService calls RunUntilIdle() so UpdateTetherTechnologyState()
   // may be called multiple times in the initialization process.
   int updated_technology_state_count =
       tether_service_->updated_technology_state_count();
@@ -489,7 +632,7 @@
 }
 
 TEST_F(TetherServiceTest, TestBluetoothNotification) {
-  is_adapter_powered_ = false;
+  SetIsBluetoothPowered(false);
 
   CreateTetherService();
   DisconnectDefaultShillNetworks();
@@ -499,20 +642,16 @@
   EXPECT_TRUE(
       fake_notification_presenter_->is_enable_bluetooth_notification_shown());
 
-  // Now, simulate the adapter being turned off. The notification should no
+  // Now, simulate the adapter being turned on. The notification should no
   // longer be visible.
-  is_adapter_powered_ = true;
-  tether_service_->AdapterPoweredChanged(mock_adapter_.get(),
-                                         true /* powered */);
+  SetIsBluetoothPowered(true);
   EXPECT_FALSE(
       fake_notification_presenter_->is_enable_bluetooth_notification_shown());
 
-  // Now, simulate the adapter being turned back on. The notification should
+  // Now, simulate the adapter being turned off again. The notification should
   // still *not* be available. It should only be shown when the service starts
   // up or when the network has been disconnected.
-  is_adapter_powered_ = false;
-  tether_service_->AdapterPoweredChanged(mock_adapter_.get(),
-                                         false /* powered */);
+  SetIsBluetoothPowered(false);
   EXPECT_FALSE(
       fake_notification_presenter_->is_enable_bluetooth_notification_shown());
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
index 9088ad5..d718b42b 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -16,7 +16,9 @@
 DialMediaSinkServiceImpl::DialMediaSinkServiceImpl(
     const OnSinksDiscoveredCallback& callback,
     net::URLRequestContextGetter* request_context)
-    : MediaSinkServiceBase(callback), request_context_(request_context) {
+    : MediaSinkServiceBase(callback),
+      observer_(nullptr),
+      request_context_(request_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(request_context_);
 }
@@ -61,6 +63,18 @@
   return description_service_.get();
 }
 
+void DialMediaSinkServiceImpl::SetObserver(
+    DialMediaSinkServiceObserver* observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  observer_ = observer;
+}
+
+void DialMediaSinkServiceImpl::ClearObserver(
+    DialMediaSinkServiceObserver* observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  observer_ = nullptr;
+}
+
 void DialMediaSinkServiceImpl::SetDialRegistryForTest(
     DialRegistry* dial_registry) {
   DCHECK(!test_dial_registry_);
@@ -115,7 +129,10 @@
     return;
   }
 
-  current_sinks_.insert(MediaSinkInternal(sink, extra_data));
+  MediaSinkInternal dial_sink(sink, extra_data);
+  current_sinks_.insert(dial_sink);
+  if (observer_)
+    observer_->OnDialSinkAdded(dial_sink);
 
   // Start fetch timer again if device description comes back after
   // |finish_timer_| fires.
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
index 2e74c93..ccc764f8b 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
@@ -18,6 +18,17 @@
 class DeviceDescriptionService;
 class DialRegistry;
 
+// An observer class registered with DialMediaSinkService to receive
+// notifications when DIAL sinks are added or removed from DialMediaSinkService
+class DialMediaSinkServiceObserver {
+ public:
+  virtual ~DialMediaSinkServiceObserver() {}
+
+  // Invoked when |sink| is added to DialMediaSinkServiceImpl instance.
+  // |sink|: must be a DIAL sink.
+  virtual void OnDialSinkAdded(const MediaSinkInternal& sink) = 0;
+};
+
 // A service which can be used to start background discovery and resolution of
 // DIAL devices (Smart TVs, Game Consoles, etc.).
 // This class is not thread safe. All methods must be called from the IO thread.
@@ -28,6 +39,13 @@
                            net::URLRequestContextGetter* request_context);
   ~DialMediaSinkServiceImpl() override;
 
+  // Does not take ownership of |observer|. Caller should make sure |observer|
+  // object outlives |this|.
+  void SetObserver(DialMediaSinkServiceObserver* observer);
+
+  // Sets |observer_| to nullptr.
+  void ClearObserver(DialMediaSinkServiceObserver* observer);
+
   // MediaSinkService implementation
   void Start() override;
   void Stop() override;
@@ -78,6 +96,8 @@
   // Device data list from current round of discovery.
   DialRegistry::DeviceList current_devices_;
 
+  DialMediaSinkServiceObserver* observer_;
+
   scoped_refptr<net::URLRequestContextGetter> request_context_;
 
   DialDeviceCountMetrics metrics_;
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
index c99e490..50dc9598 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
@@ -109,7 +109,7 @@
   media_sink_service_->OnDeviceDescriptionAvailable(device_data,
                                                     device_description);
 
-  EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size());
+  EXPECT_EQ(1u, media_sink_service_->current_sinks_.size());
 }
 
 TEST_F(DialMediaSinkServiceImplTest, TestTimer) {
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.cc
index a3362d0..bfc0efe5 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.cc
@@ -14,7 +14,7 @@
 DialMediaSinkServiceProxy::DialMediaSinkServiceProxy(
     const MediaSinkService::OnSinksDiscoveredCallback& callback,
     content::BrowserContext* context)
-    : MediaSinkService(callback) {
+    : MediaSinkService(callback), observer_(nullptr) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto* profile = Profile::FromBrowserContext(context);
   request_context_ = profile->GetRequestContext();
@@ -39,6 +39,18 @@
       base::BindOnce(&DialMediaSinkServiceProxy::StopOnIOThread, this));
 }
 
+void DialMediaSinkServiceProxy::SetObserver(
+    DialMediaSinkServiceObserver* observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  observer_ = observer;
+}
+
+void DialMediaSinkServiceProxy::ClearObserver(
+    DialMediaSinkServiceObserver* observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  observer_ = nullptr;
+}
+
 void DialMediaSinkServiceProxy::SetDialMediaSinkServiceForTest(
     std::unique_ptr<DialMediaSinkServiceImpl> dial_media_sink_service) {
   DCHECK(dial_media_sink_service);
@@ -54,6 +66,7 @@
         base::Bind(&DialMediaSinkServiceProxy::OnSinksDiscoveredOnIOThread,
                    this),
         request_context_.get());
+    dial_media_sink_service_->SetObserver(observer_);
   }
 
   dial_media_sink_service_->Start();
@@ -64,6 +77,7 @@
     return;
 
   dial_media_sink_service_->Stop();
+  dial_media_sink_service_->ClearObserver(observer_);
   dial_media_sink_service_.reset();
 }
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.h
index b11bad1..8efeca8 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.h
@@ -25,6 +25,7 @@
 namespace media_router {
 
 class DialMediaSinkServiceImpl;
+class DialMediaSinkServiceObserver;
 
 // A wrapper class of DialMediaSinkService handling thread hopping between UI
 // and IO threads. This class is thread safe. Public APIs should be invoked on
@@ -50,6 +51,13 @@
   // Start() is cleared.
   void Stop() override;
 
+  // Does not take ownership of |observer|. Caller should make sure |observer|
+  // object outlives |this|.
+  void SetObserver(DialMediaSinkServiceObserver* observer);
+
+  // Sets |observer_| to nullptr.
+  void ClearObserver(DialMediaSinkServiceObserver* observer);
+
   void SetDialMediaSinkServiceForTest(
       std::unique_ptr<DialMediaSinkServiceImpl> dial_media_sink_service);
 
@@ -75,6 +83,8 @@
  private:
   std::unique_ptr<DialMediaSinkServiceImpl> dial_media_sink_service_;
 
+  DialMediaSinkServiceObserver* observer_;
+
   scoped_refptr<net::URLRequestContextGetter> request_context_;
 
   DISALLOW_COPY_AND_ASSIGN(DialMediaSinkServiceProxy);
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
index 147a1f8..f350c63 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h"
 #include "chrome/browser/media/router/discovery/mdns/dns_sd_delegate.h"
 #include "chrome/browser/media/router/discovery/mdns/dns_sd_registry.h"
@@ -66,6 +67,11 @@
   extra_data.ip_address = ip_address;
   extra_data.port = service.service_host_port.port();
   extra_data.model_name = service_data["md"];
+  extra_data.capabilities = cast_channel::CastDeviceCapability::NONE;
+
+  unsigned capacities;
+  if (base::StringToUint(service_data["ca"], &capacities))
+    extra_data.capabilities = capacities;
 
   cast_sink->set_sink(sink);
   cast_sink->set_cast_data(extra_data);
@@ -175,6 +181,11 @@
                      std::move(cast_sinks)));
 }
 
+void CastMediaSinkService::OnDialSinkAdded(const MediaSinkInternal& sink) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  cast_media_sink_service_impl_->OnDialSinkAdded(sink);
+}
+
 void CastMediaSinkService::OnSinksDiscoveredOnIOThread(
     std::vector<MediaSinkInternal> sinks) {
   // TODO(crbug.com/749305): Migrate the discovery code to use sequences.
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
index 1559dbe..3505b64a 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
@@ -10,6 +10,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h"
 #include "chrome/browser/media/router/discovery/mdns/dns_sd_delegate.h"
 #include "chrome/browser/media/router/discovery/mdns/dns_sd_registry.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
@@ -29,6 +30,7 @@
 // Public APIs should be invoked on the UI thread.
 class CastMediaSinkService
     : public MediaSinkService,
+      public DialMediaSinkServiceObserver,
       public DnsSdRegistry::DnsSdObserver,
       public base::RefCountedThreadSafe<CastMediaSinkService> {
  public:
@@ -54,7 +56,6 @@
   ~CastMediaSinkService() override;
 
  private:
-
   friend class base::RefCountedThreadSafe<CastMediaSinkService>;
   friend class CastMediaSinkServiceTest;
 
@@ -71,6 +72,9 @@
   void OnDnsSdEvent(const std::string& service_type,
                     const DnsSdRegistry::DnsSdServiceList& services) override;
 
+  // DialMediaSinkServiceObserver implementation
+  void OnDialSinkAdded(const MediaSinkInternal& sink) override;
+
   // Raw pointer to DnsSdRegistry instance, which is a global leaky singleton
   // and lives as long as the browser process.
   DnsSdRegistry* dns_sd_registry_ = nullptr;
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index 37402d6f..26cf335 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -6,10 +6,34 @@
 
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/media/router/discovery/media_sink_service_base.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
+#include "chrome/common/media_router/discovery/media_sink_service.h"
+#include "chrome/common/media_router/media_sink.h"
 #include "components/cast_channel/cast_socket_service.h"
 #include "components/net_log/chrome_net_log.h"
 
+namespace {
+
+media_router::MediaSinkInternal CreateCastSinkFromDialSink(
+    const media_router::MediaSinkInternal& dial_sink) {
+  const std::string& unique_id = dial_sink.sink().id();
+  const std::string& friendly_name = dial_sink.sink().name();
+  media_router::MediaSink sink(unique_id, friendly_name,
+                               media_router::SinkIconType::CAST);
+
+  media_router::CastSinkExtraData extra_data;
+  extra_data.ip_address = dial_sink.dial_data().ip_address;
+  extra_data.port = media_router::CastMediaSinkServiceImpl::kCastControlPort;
+  extra_data.model_name = dial_sink.dial_data().model_name;
+  extra_data.discovered_by_dial = true;
+  extra_data.capabilities = cast_channel::CastDeviceCapability::NONE;
+
+  return media_router::MediaSinkInternal(sink, extra_data);
+}
+
+}  // namespace
+
 namespace media_router {
 
 // static
@@ -40,6 +64,30 @@
   MediaSinkServiceBase::StopTimer();
 }
 
+void CastMediaSinkServiceImpl::OnFetchCompleted() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  current_sinks_.clear();
+
+  // Copy cast sink from mDNS service to |current_sinks_|.
+  for (const auto& sink_it : current_sinks_by_mdns_) {
+    DVLOG(2) << "Discovered by mdns [name]: " << sink_it.second.sink().name()
+             << " [ip_address]: "
+             << sink_it.second.cast_data().ip_address.ToString();
+    current_sinks_.insert(sink_it.second);
+  }
+
+  // Copy cast sink from DIAL discovery to |current_sinks_|.
+  for (const auto& sink_it : current_sinks_by_dial_) {
+    DVLOG(2) << "Discovered by dial [name]: " << sink_it.second.sink().name()
+             << " [ip_address]: "
+             << sink_it.second.cast_data().ip_address.ToString();
+    if (!base::ContainsKey(current_sinks_by_mdns_, sink_it.first))
+      current_sinks_.insert(sink_it.second);
+  }
+
+  MediaSinkServiceBase::OnFetchCompleted();
+}
+
 void CastMediaSinkServiceImpl::RecordDeviceCounts() {
   metrics_.RecordDeviceCountsIfNeeded(current_sinks_.size(),
                                       current_service_ip_endpoints_.size());
@@ -67,17 +115,8 @@
            << " [error_state]: "
            << cast_channel::ChannelErrorToString(error_state);
   net::IPEndPoint ip_endpoint = socket.ip_endpoint();
-  auto sink_it = std::find_if(
-      current_sinks_.begin(), current_sinks_.end(),
-      [&](const MediaSinkInternal& sink) {
-        return sink.cast_data().ip_address == ip_endpoint.address() &&
-               sink.cast_data().port == ip_endpoint.port();
-      });
-
-  if (sink_it == current_sinks_.end())
-    return;
-
-  current_sinks_.erase(sink_it);
+  current_sinks_by_dial_.erase(ip_endpoint);
+  current_sinks_by_mdns_.erase(ip_endpoint);
   MediaSinkServiceBase::RestartTimer();
 }
 
@@ -119,8 +158,31 @@
   DVLOG(2) << "Ading sink to current_sinks_ [name]: "
            << updated_sink.sink().name();
 
-  current_sinks_.insert(updated_sink);
+  net::IPEndPoint ip_endpoint(cast_sink.cast_data().ip_address,
+                              cast_sink.cast_data().port);
+  // Add or update existing cast sink.
+  if (updated_sink.cast_data().discovered_by_dial) {
+    current_sinks_by_dial_[ip_endpoint] = updated_sink;
+  } else {
+    current_sinks_by_mdns_[ip_endpoint] = updated_sink;
+  }
   MediaSinkServiceBase::RestartTimer();
 }
 
+void CastMediaSinkServiceImpl::OnDialSinkAdded(const MediaSinkInternal& sink) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto ip_address = sink.dial_data().ip_address;
+  net::IPEndPoint ip_endpoint(ip_address, kCastControlPort);
+
+  if (base::ContainsKey(current_service_ip_endpoints_, ip_endpoint)) {
+    DVLOG(2) << "Sink discovered by mDNS, skip adding [name]: "
+             << sink.sink().name();
+    return;
+  }
+
+  // TODO(crbug.com/753175): Dual discovery should not try to open cast channel
+  // for non-Cast device.
+  OpenChannel(ip_endpoint, CreateCastSinkFromDialSink(sink));
+}
+
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
index 7b905e337..f82ffa94 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
@@ -42,11 +42,15 @@
   void Stop() override;
 
   // MediaSinkServiceBase implementation
+  // Called when the discovery loop timer expires.
+  void OnFetchCompleted() override;
   void RecordDeviceCounts() override;
 
   // Opens cast channels on the IO thread.
   virtual void OpenChannels(std::vector<MediaSinkInternal> cast_sinks);
 
+  void OnDialSinkAdded(const MediaSinkInternal& sink);
+
  private:
   friend class CastMediaSinkServiceImplTest;
   FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest, TestOnChannelOpened);
@@ -56,6 +60,8 @@
   FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
                            TestMultipleOpenChannels);
   FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest, TestOnChannelError);
+  FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest, TestOnDialSinkAdded);
+  FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest, TestOnFetchCompleted);
 
   // CastSocket::Observer implementation.
   void OnError(const cast_channel::CastSocket& socket,
@@ -79,6 +85,14 @@
   // Set of mDNS service IP endpoints from current round of discovery.
   std::set<net::IPEndPoint> current_service_ip_endpoints_;
 
+  using MediaSinkInternalMap = std::map<net::IPEndPoint, MediaSinkInternal>;
+
+  // Map of sinks from current round of mDNS discovery keyed by IP address.
+  MediaSinkInternalMap current_sinks_by_mdns_;
+
+  // Map of sinks from current round of DIAL discovery keyed by IP address.
+  MediaSinkInternalMap current_sinks_by_dial_;
+
   // Raw pointer of leaky singleton CastSocketService, which manages adding and
   // removing Cast channels.
   cast_channel::CastSocketService* const cast_socket_service_;
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
index 078cedf..bb28759 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
@@ -16,8 +16,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::testing::_;
+using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::SaveArg;
+using ::testing::WithArgs;
+using cast_channel::ChannelError;
 
 namespace {
 
@@ -45,6 +48,19 @@
   return media_router::MediaSinkInternal(sink, extra_data);
 }
 
+media_router::MediaSinkInternal CreateDialSink(int num) {
+  std::string friendly_name = base::StringPrintf("friendly name %d", num);
+  std::string unique_id = base::StringPrintf("id %d", num);
+  net::IPEndPoint ip_endpoint = CreateIPEndPoint(num);
+
+  media_router::MediaSink sink(unique_id, friendly_name,
+                               media_router::SinkIconType::GENERIC);
+  media_router::DialSinkExtraData extra_data;
+  extra_data.ip_address = ip_endpoint.address();
+  extra_data.model_name = base::StringPrintf("model name %d", num);
+  return media_router::MediaSinkInternal(sink, extra_data);
+}
+
 }  // namespace
 
 namespace media_router {
@@ -86,8 +102,9 @@
   media_sink_service_impl_.OnChannelOpened(cast_sink, &socket);
 
   // Verify sink content
-  EXPECT_EQ(media_sink_service_impl_.current_sinks_,
-            std::set<MediaSinkInternal>({cast_sink}));
+  EXPECT_CALL(mock_sink_discovered_cb_,
+              Run(std::vector<MediaSinkInternal>({cast_sink})));
+  media_sink_service_impl_.OnFetchCompleted();
 }
 
 TEST_F(CastMediaSinkServiceImplTest, TestMultipleOnChannelOpened) {
@@ -110,8 +127,10 @@
   media_sink_service_impl_.OnChannelOpened(cast_sink2, &socket2);
   media_sink_service_impl_.OnChannelOpened(cast_sink3, &socket3);
 
-  EXPECT_EQ(media_sink_service_impl_.current_sinks_,
-            std::set<MediaSinkInternal>({cast_sink2, cast_sink3}));
+  // Verify sink content
+  EXPECT_CALL(mock_sink_discovered_cb_,
+              Run(std::vector<MediaSinkInternal>({cast_sink2, cast_sink3})));
+  media_sink_service_impl_.OnFetchCompleted();
 }
 
 TEST_F(CastMediaSinkServiceImplTest, TestTimer) {
@@ -187,8 +206,10 @@
   media_sink_service_impl_.OnChannelOpened(cast_sink1, &socket1);
   media_sink_service_impl_.OnChannelOpened(cast_sink3, &socket3);
 
-  EXPECT_EQ(media_sink_service_impl_.current_sinks_,
-            std::set<MediaSinkInternal>({cast_sink1, cast_sink2, cast_sink3}));
+  EXPECT_CALL(mock_sink_discovered_cb_,
+              Run(std::vector<MediaSinkInternal>(
+                  {cast_sink1, cast_sink2, cast_sink3})));
+  media_sink_service_impl_.OnFetchCompleted();
 }
 
 TEST_F(CastMediaSinkServiceImplTest, TestOnChannelError) {
@@ -200,12 +221,83 @@
   media_sink_service_impl_.current_service_ip_endpoints_.insert(ip_endpoint1);
   media_sink_service_impl_.OnChannelOpened(cast_sink, &socket);
 
-  EXPECT_EQ(1u, media_sink_service_impl_.current_sinks_.size());
+  EXPECT_EQ(1u, media_sink_service_impl_.current_sinks_by_mdns_.size());
 
   socket.SetIPEndpoint(ip_endpoint1);
   media_sink_service_impl_.OnError(
       socket, cast_channel::ChannelError::CHANNEL_NOT_OPEN);
-  EXPECT_TRUE(media_sink_service_impl_.current_sinks_.empty());
+  EXPECT_TRUE(media_sink_service_impl_.current_sinks_by_mdns_.empty());
+}
+
+TEST_F(CastMediaSinkServiceImplTest, TestOnDialSinkAdded) {
+  MediaSinkInternal dial_sink1 = CreateDialSink(1);
+  MediaSinkInternal dial_sink2 = CreateDialSink(2);
+  net::IPEndPoint ip_endpoint1(dial_sink1.dial_data().ip_address,
+                               CastMediaSinkServiceImpl::kCastControlPort);
+  net::IPEndPoint ip_endpoint2(dial_sink2.dial_data().ip_address,
+                               CastMediaSinkServiceImpl::kCastControlPort);
+
+  cast_channel::MockCastSocket socket1;
+  cast_channel::MockCastSocket socket2;
+  socket1.set_id(1);
+  socket2.set_id(2);
+
+  // Channel 1, 2 opened.
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint1, _, _, _))
+      .WillOnce(DoAll(
+          WithArgs<2>(Invoke(
+              [&](const base::Callback<void(cast_channel::CastSocket * socket)>&
+                      callback) { std::move(callback).Run(&socket1); })),
+          Return(1)));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint2, _, _, _))
+      .WillOnce(DoAll(
+          WithArgs<2>(Invoke(
+              [&](const base::Callback<void(cast_channel::CastSocket * socket)>&
+                      callback) { std::move(callback).Run(&socket2); })),
+          Return(2)));
+
+  // Invoke CastSocketService::OpenSocket on the IO thread.
+  media_sink_service_impl_.OnDialSinkAdded(dial_sink1);
+  base::RunLoop().RunUntilIdle();
+
+  // Invoke CastSocketService::OpenSocket on the IO thread.
+  media_sink_service_impl_.OnDialSinkAdded(dial_sink2);
+  base::RunLoop().RunUntilIdle();
+  // Verify sink content.
+  EXPECT_EQ(2u, media_sink_service_impl_.current_sinks_by_dial_.size());
+}
+
+TEST_F(CastMediaSinkServiceImplTest, TestOnFetchCompleted) {
+  std::vector<MediaSinkInternal> sinks;
+  EXPECT_CALL(mock_sink_discovered_cb_, Run(_)).WillOnce(SaveArg<0>(&sinks));
+
+  auto cast_sink1 = CreateCastSink(1);
+  auto cast_sink2 = CreateCastSink(2);
+  auto cast_sink3 = CreateCastSink(3);
+  net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1);
+  net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2);
+  net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
+
+  // Cast sink 1, 2 from mDNS discovery
+  media_sink_service_impl_.current_sinks_by_mdns_[ip_endpoint1] = cast_sink1;
+  media_sink_service_impl_.current_sinks_by_mdns_[ip_endpoint2] = cast_sink2;
+  // Cast sink 2, 3 from dial discovery
+  auto extra_data = cast_sink2.cast_data();
+  extra_data.discovered_by_dial = true;
+  extra_data.model_name += " dial";
+
+  media_sink_service_impl_.current_sinks_by_dial_[ip_endpoint2] = cast_sink2;
+  media_sink_service_impl_.current_sinks_by_dial_[ip_endpoint3] = cast_sink3;
+
+  // Callback returns Cast sink 1, 2, 3
+  media_sink_service_impl_.OnFetchCompleted();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(base::ContainsValue(sinks, cast_sink1));
+  EXPECT_TRUE(base::ContainsValue(sinks, cast_sink2));
+  EXPECT_TRUE(base::ContainsValue(sinks, cast_sink3));
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/media_sink_service_base.h b/chrome/browser/media/router/discovery/media_sink_service_base.h
index 4821895..a2cc4717 100644
--- a/chrome/browser/media/router/discovery/media_sink_service_base.h
+++ b/chrome/browser/media/router/discovery/media_sink_service_base.h
@@ -24,7 +24,7 @@
   void SetTimerForTest(std::unique_ptr<base::Timer> timer);
 
   // Called when |finish_timer_| expires.
-  void OnFetchCompleted();
+  virtual void OnFetchCompleted();
 
   // Helper function to start |finish_timer_|. Create a new timer if none
   // exists.
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index 6cc4568..ad801f3 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -72,8 +72,11 @@
 
 MediaRouterMojoImpl::~MediaRouterMojoImpl() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (dial_media_sink_service_proxy_)
+  if (dial_media_sink_service_proxy_) {
     dial_media_sink_service_proxy_->Stop();
+    dial_media_sink_service_proxy_->ClearObserver(
+        cast_media_sink_service_.get());
+  }
   if (cast_media_sink_service_)
     cast_media_sink_service_->Stop();
 }
@@ -808,16 +811,6 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DVLOG_WITH_INSTANCE(1) << "StartDiscovery";
 
-  if (media_router::DialLocalDiscoveryEnabled()) {
-    if (!dial_media_sink_service_proxy_) {
-      dial_media_sink_service_proxy_ = new DialMediaSinkServiceProxy(
-          base::Bind(&MediaRouterMojoImpl::ProvideSinks,
-                     weak_factory_.GetWeakPtr(), "dial"),
-          context_);
-    }
-    dial_media_sink_service_proxy_->Start();
-  }
-
   if (media_router::CastDiscoveryEnabled()) {
     if (!cast_media_sink_service_) {
       cast_media_sink_service_ = new CastMediaSinkService(
@@ -827,6 +820,18 @@
     }
     cast_media_sink_service_->Start();
   }
+
+  if (media_router::DialLocalDiscoveryEnabled()) {
+    if (!dial_media_sink_service_proxy_) {
+      dial_media_sink_service_proxy_ = new DialMediaSinkServiceProxy(
+          base::Bind(&MediaRouterMojoImpl::ProvideSinks,
+                     weak_factory_.GetWeakPtr(), "dial"),
+          context_);
+      dial_media_sink_service_proxy_->SetObserver(
+          cast_media_sink_service_.get());
+    }
+    dial_media_sink_service_proxy_->Start();
+  }
 }
 
 void MediaRouterMojoImpl::UpdateMediaSinks(
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
index 8ca6bbc..204ad21 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -76,6 +76,8 @@
          prefs::kEnableTouchpadThreeFingerClick, true},
         {switches::kEnableUnifiedDesktop,
          prefs::kUnifiedDesktopEnabledByDefault, true},
+        {chromeos::switches::kEnableCastReceiver, prefs::kCastReceiverEnabled,
+         true},
 #endif
         {switches::kUnsafePacUrl, prefs::kPacHttpsUrlStrippingEnabled, false},
         {switches::kEnableLocalSyncBackend,
diff --git a/chrome/browser/resources/pdf/browser_api.js b/chrome/browser/resources/pdf/browser_api.js
index 37622de..34da975c 100644
--- a/chrome/browser/resources/pdf/browser_api.js
+++ b/chrome/browser/resources/pdf/browser_api.js
@@ -103,9 +103,9 @@
   setZoom(zoom) {
     if (this.zoomBehavior_ != BrowserApi.ZoomBehavior.MANAGE)
       return Promise.reject(new Error('Viewer does not manage browser zoom.'));
-    return new Promise(function(resolve, reject) {
+    return new Promise((resolve, reject) => {
       chrome.tabs.setZoom(this.streamInfo_.tabId, zoom, resolve);
-    }.bind(this));
+    });
   }
 
   /**
@@ -142,13 +142,13 @@
           this.zoomBehavior_ == BrowserApi.ZoomBehavior.PROPAGATE_PARENT))
       return;
 
-    chrome.tabs.onZoomChange.addListener(function(info) {
+    chrome.tabs.onZoomChange.addListener(info => {
       var zoomChangeInfo =
           /** @type {{tabId: number, newZoomFactor: number}} */ (info);
       if (zoomChangeInfo.tabId != this.streamInfo_.tabId)
         return;
       listener(zoomChangeInfo.newZoomFactor);
-    }.bind(this));
+    });
   }
 }
 
diff --git a/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js b/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js
index 96f7f3d..48631d8 100644
--- a/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js
+++ b/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js
@@ -47,10 +47,10 @@
     this.style.opacity = 1;
     clearTimeout(this.timerId);
 
-    this.timerId = setTimeout(function() {
+    this.timerId = setTimeout(() => {
       this.style.opacity = 0;
       this.timerId = undefined;
-    }.bind(this), displayTime);
+    }, displayTime);
   },
 
   pageLabelsChanged: function() {
diff --git a/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js b/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js
index 53e9acc5..f1751dd 100644
--- a/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js
+++ b/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js
@@ -93,11 +93,11 @@
    */
   playAnimation_: function(isEntry) {
     this.animation_ = isEntry ? this.animateEntry_() : this.animateExit_();
-    this.animation_.onfinish = function() {
+    this.animation_.onfinish = () => {
       this.animation_ = null;
       if (!this.dropdownOpen)
         this.$.dropdown.style.display = 'none';
-    }.bind(this);
+    };
   },
 
   animateEntry_: function() {
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js
index 632ee2b..ffc2a490 100644
--- a/chrome/browser/resources/pdf/pdf.js
+++ b/chrome/browser/resources/pdf/pdf.js
@@ -123,9 +123,9 @@
   this.errorScreen_ = $('error-screen');
   // Can only reload if we are in a normal tab.
   if (chrome.tabs && this.browserApi_.getStreamInfo().tabId != -1) {
-    this.errorScreen_.reloadFn = function() {
+    this.errorScreen_.reloadFn = () => {
       chrome.tabs.reload(this.browserApi_.getStreamInfo().tabId);
-    }.bind(this);
+    };
   }
 
   // Create the viewport.
@@ -216,16 +216,16 @@
     this.toolbar_.docTitle = getFilenameFromURL(this.originalUrl_);
   }
 
-  document.body.addEventListener('change-page', function(e) {
+  document.body.addEventListener('change-page', e => {
     this.viewport_.goToPage(e.detail.page);
-  }.bind(this));
+  });
 
-  document.body.addEventListener('navigate', function(e) {
+  document.body.addEventListener('navigate', e => {
     var disposition = e.detail.newtab ?
         Navigator.WindowOpenDisposition.NEW_BACKGROUND_TAB :
         Navigator.WindowOpenDisposition.CURRENT_TAB;
     this.navigator_.navigate(e.detail.uri, disposition);
-  }.bind(this));
+  });
 
   this.toolbarManager_ =
       new ToolbarManager(window, this.toolbar_, this.zoomToolbar_);
@@ -274,7 +274,7 @@
 
     this.toolbarManager_.hideToolbarsAfterTimeout(e);
 
-    var pageUpHandler = function() {
+    var pageUpHandler = () => {
       // Go to the previous page if we are fit-to-page.
       if (this.viewport_.fittingType == Viewport.FittingType.FIT_TO_PAGE) {
         this.viewport_.goToPage(this.viewport_.getMostVisiblePage() - 1);
@@ -284,8 +284,8 @@
         position.y -= this.viewport.size.height;
         this.viewport.position = position;
       }
-    }.bind(this);
-    var pageDownHandler = function() {
+    };
+    var pageDownHandler = () => {
       // Go to the next page if we are fit-to-page.
       if (this.viewport_.fittingType == Viewport.FittingType.FIT_TO_PAGE) {
         this.viewport_.goToPage(this.viewport_.getMostVisiblePage() + 1);
@@ -295,7 +295,7 @@
         position.y += this.viewport.size.height;
         this.viewport.position = position;
       }
-    }.bind(this);
+    };
 
     switch (e.keyCode) {
       case 9:  // Tab key.
@@ -718,10 +718,10 @@
     // Throttle number of pinch events to one per frame.
     if (!this.sentPinchEvent_) {
       this.sentPinchEvent_ = true;
-      window.requestAnimationFrame(function() {
+      window.requestAnimationFrame(() => {
         this.sentPinchEvent_ = false;
         this.viewport_.pinchZoom(e);
-      }.bind(this));
+      });
     }
   },
 
@@ -733,9 +733,9 @@
   onPinchEnd_: function(e) {
     // Using rAF for pinch end prevents pinch updates scheduled by rAF getting
     // sent after the pinch end.
-    window.requestAnimationFrame(function() {
+    window.requestAnimationFrame(() => {
       this.viewport_.pinchZoomEnd(e);
-    }.bind(this));
+    });
   },
 
   /**
diff --git a/chrome/browser/resources/pdf/pdf_scripting_api.js b/chrome/browser/resources/pdf/pdf_scripting_api.js
index fd5e2e15..a133b52 100644
--- a/chrome/browser/resources/pdf/pdf_scripting_api.js
+++ b/chrome/browser/resources/pdf/pdf_scripting_api.js
@@ -53,7 +53,7 @@
   this.pendingScriptingMessages_ = [];
   this.setPlugin(plugin);
 
-  window.addEventListener('message', function(event) {
+  window.addEventListener('message', event => {
     if (event.origin != 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai' &&
         event.origin != 'chrome://print') {
       console.error(
@@ -95,7 +95,7 @@
           this.keyEventCallback_(DeserializeKeyEvent(event.data.keyEvent));
         break;
     }
-  }.bind(this), false);
+  }, false);
 }
 
 PDFScriptingAPI.prototype = {
diff --git a/chrome/browser/resources/pdf/toolbar_manager.js b/chrome/browser/resources/pdf/toolbar_manager.js
index 958b9ee..6fa82bf9 100644
--- a/chrome/browser/resources/pdf/toolbar_manager.js
+++ b/chrome/browser/resources/pdf/toolbar_manager.js
@@ -233,9 +233,9 @@
       return;
     this.toolbar_.hide();
     this.sideToolbarAllowedOnly_ = true;
-    this.sideToolbarAllowedOnlyTimer_ = this.window_.setTimeout(function() {
+    this.sideToolbarAllowedOnlyTimer_ = this.window_.setTimeout(() => {
       this.sideToolbarAllowedOnlyTimer_ = null;
-    }.bind(this), FORCE_HIDE_TIMEOUT);
+    }, FORCE_HIDE_TIMEOUT);
   },
 
   /**
diff --git a/chrome/browser/resources/pdf/viewport.js b/chrome/browser/resources/pdf/viewport.js
index 54f166b..358922c 100644
--- a/chrome/browser/resources/pdf/viewport.js
+++ b/chrome/browser/resources/pdf/viewport.js
@@ -397,10 +397,10 @@
     newZoom = Math.max(
         Viewport.ZOOM_FACTOR_RANGE.min,
         Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max));
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.setZoomInternal_(newZoom);
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
@@ -409,7 +409,7 @@
    * @param {number} oldBrowserZoom the previous value of the browser zoom.
    */
   updateZoomFromBrowserChange: function(oldBrowserZoom) {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       // Record the scroll position (relative to the top-left of the window).
       var oldZoom = oldBrowserZoom * this.internalZoom_;
       var currentScrollPos = {
@@ -423,7 +423,7 @@
         y: currentScrollPos.y * this.zoom
       };
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
@@ -565,7 +565,7 @@
    * Zoom the viewport so that the page-width consumes the entire viewport.
    */
   fitToWidth: function() {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.fittingType_ = Viewport.FittingType.FIT_TO_WIDTH;
       if (!this.documentDimensions_)
         return;
@@ -575,7 +575,7 @@
           this.computeFittingZoom_(this.documentDimensions_, true));
       var page = this.getMostVisiblePage();
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
@@ -586,7 +586,7 @@
    *     should remain at the current scroll position.
    */
   fitToPageInternal_: function(scrollToTopOfPage) {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.fittingType_ = Viewport.FittingType.FIT_TO_PAGE;
       if (!this.documentDimensions_)
         return;
@@ -601,7 +601,7 @@
         this.position = {x: 0, y: this.pageDimensions_[page].y * this.zoom};
       }
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
@@ -616,7 +616,7 @@
    * Zoom out to the next predefined zoom level.
    */
   zoomOut: function() {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.fittingType_ = Viewport.FittingType.NONE;
       var nextZoom = Viewport.ZOOM_FACTORS[0];
       for (var i = 0; i < Viewport.ZOOM_FACTORS.length; i++) {
@@ -625,14 +625,14 @@
       }
       this.setZoomInternal_(nextZoom);
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
    * Zoom in to the next predefined zoom level.
    */
   zoomIn: function() {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.fittingType_ = Viewport.FittingType.NONE;
       var nextZoom = Viewport.ZOOM_FACTORS[Viewport.ZOOM_FACTORS.length - 1];
       for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) {
@@ -641,7 +641,7 @@
       }
       this.setZoomInternal_(nextZoom);
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
@@ -649,7 +649,7 @@
    * @param {!Object} e The pinch event.
    */
   pinchZoom: function(e) {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.pinchPhase_ = e.direction == 'out' ?
           Viewport.PinchPhase.PINCH_UPDATE_ZOOM_OUT :
           Viewport.PinchPhase.PINCH_UPDATE_ZOOM_IN;
@@ -684,7 +684,7 @@
       this.setPinchZoomInternal_(scaleDelta, frameToPluginCoordinate(e.center));
       this.updateViewport_();
       this.prevScale_ = e.startScaleRatio;
-    }.bind(this));
+    });
   },
 
   pinchZoomStart: function(e) {
@@ -701,14 +701,14 @@
   },
 
   pinchZoomEnd: function(e) {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       this.pinchPhase_ = Viewport.PinchPhase.PINCH_END;
       var scaleDelta = e.startScaleRatio / this.prevScale_;
       this.pinchCenter_ = e.center;
 
       this.setPinchZoomInternal_(scaleDelta, frameToPluginCoordinate(e.center));
       this.updateViewport_();
-    }.bind(this));
+    });
 
     this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE;
     this.pinchPanVector_ = null;
@@ -721,7 +721,7 @@
    * @param {number} page the index of the page to go to. zero-based.
    */
   goToPage: function(page) {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       if (this.pageDimensions_.length === 0)
         return;
       if (page < 0)
@@ -740,7 +740,7 @@
         y: dimensions.y * this.zoom - toolbarOffset
       };
       this.updateViewport_();
-    }.bind(this));
+    });
   },
 
   /**
@@ -748,7 +748,7 @@
    * @param {Object} documentDimensions the dimensions of the document
    */
   setDocumentDimensions: function(documentDimensions) {
-    this.mightZoom_(function() {
+    this.mightZoom_(() => {
       var initialDimensions = !this.documentDimensions_;
       this.documentDimensions_ = documentDimensions;
       this.pageDimensions_ = this.documentDimensions_.pageDimensions;
@@ -760,7 +760,7 @@
       }
       this.contentSizeChanged_();
       this.resize_();
-    }.bind(this));
+    });
   },
 
   /**
diff --git a/chrome/browser/resources/pdf/zoom_manager.js b/chrome/browser/resources/pdf/zoom_manager.js
index eec9115..3ca81814 100644
--- a/chrome/browser/resources/pdf/zoom_manager.js
+++ b/chrome/browser/resources/pdf/zoom_manager.js
@@ -145,16 +145,15 @@
     if (this.floatingPointEquals(this.browserZoom_, zoom))
       return;
 
-    this.changingBrowserZoom_ =
-        this.setBrowserZoomFunction_(zoom).then(function() {
-          this.browserZoom_ = zoom;
-          this.changingBrowserZoom_ = null;
+    this.changingBrowserZoom_ = this.setBrowserZoomFunction_(zoom).then(() => {
+      this.browserZoom_ = zoom;
+      this.changingBrowserZoom_ = null;
 
-          // The extension's zoom level may have changed while the browser zoom
-          // change was in progress. We call back into onPdfZoomChange to ensure
-          // the browser zoom is up to date.
-          this.onPdfZoomChange();
-        }.bind(this));
+      // The extension's zoom level may have changed while the browser zoom
+      // change was in progress. We call back into onPdfZoomChange to ensure
+      // the browser zoom is up to date.
+      this.onPdfZoomChange();
+    });
   }
 
   /**
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc
index 66e682b5..93c73e9 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc
@@ -23,6 +23,7 @@
 namespace {
 
 using ::testing::_;
+using ::testing::InvokeWithoutArgs;
 using ::testing::StrictMock;
 using ::testing::Return;
 
@@ -80,14 +81,18 @@
 
 // Disabled due to flaky failures: https://crbug.com/753632
 IN_PROC_BROWSER_TEST_F(ChromeCleanerPromptUserTest,
-                       DISABLED_OnInfectedBrowserNotAvailable) {
+                       OnInfectedBrowserNotAvailable) {
   browser()->window()->Minimize();
   base::RunLoop().RunUntilIdle();
   dialog_controller_->OnInfected(std::set<base::FilePath>());
 
+  base::RunLoop run_loop;
   // We only set the expectation here because we want to make sure that the
   // prompt is shown only when the window is restored.
-  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).Times(1);
+  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).WillOnce(
+          InvokeWithoutArgs([&run_loop]() {
+                  run_loop.QuitClosure().Run();
+               }));
 
   browser()->window()->Restore();
   base::RunLoop().RunUntilIdle();
@@ -102,12 +107,17 @@
   base::RunLoop().RunUntilIdle();
   dialog_controller_->OnInfected(std::set<base::FilePath>());
 
+  base::RunLoop run_loop;
+
   // We only set the expectation here because we want to make sure that the
   // prompt is shown only when the window is restored.
-  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).Times(1);
+  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).WillOnce(
+          InvokeWithoutArgs([&run_loop]() {
+                  run_loop.QuitClosure().Run();
+               }));
 
   CreateBrowser(ProfileManager::GetActiveUserProfile());
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
index 6b3e7ff..2eaaee6 100644
--- a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/session_util.h"
+#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_switches.h"
 #include "ui/app_list/presenter/app_list_presenter_delegate_factory.h"
 #include "ui/app_list/presenter/app_list_presenter_impl.h"
@@ -161,6 +162,8 @@
 void AppListServiceAsh::ShowForAppInstall(Profile* profile,
                                           const std::string& extension_id,
                                           bool start_discovery_tracking) {
+  if (app_list::features::IsFullscreenAppListEnabled())
+    return;
   ShowAndSwitchToState(app_list::AppListModel::STATE_APPS);
   AppListServiceImpl::ShowForAppInstall(profile, extension_id,
                                         start_discovery_tracking);
diff --git a/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
index 6996ab9..8870cd8 100644
--- a/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
@@ -58,22 +58,26 @@
   // Complete the Payment Request.
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
-          JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
-      1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -102,22 +106,26 @@
       content::ExecuteScript(GetActiveWebContents(), click_buy_button_js));
   WaitForObservedEvent();
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
-          JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
-      1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -140,22 +148,26 @@
   // Simulate that the user cancels the Payment Request.
   ClickOnCancel();
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
-          JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
-      1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -192,20 +204,26 @@
   // Complete the Payment Request.
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -231,20 +249,26 @@
       content::ExecuteScript(GetActiveWebContents(), click_buy_button_js));
   WaitForObservedEvent();
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -264,20 +288,26 @@
   // Simulate that the user cancels the Payment Request.
   ClickOnCancel();
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -298,17 +328,26 @@
   // Navigate away to trigger the log.
   NavigateTo("/payment_request_email_test.html");
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -326,18 +365,26 @@
   // Navigate away to trigger the log.
   NavigateTo("/payment_request_email_test.html");
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW,
-      1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -359,18 +406,26 @@
   // Complete the Payment Request.
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
   // Make sure that no canMakePayment events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -398,18 +453,26 @@
       content::ExecuteScript(GetActiveWebContents(), click_buy_button_js));
   WaitForObservedEvent();
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
   // Make sure that no canMakePayment events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -431,18 +494,26 @@
   // Simulate that the user cancels the Payment Request.
   ClickOnCancel();
 
-  // Make sure the metrics are logged correctly.
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure that no canMakePayment events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_TRUE(buckets[0].min &
+              JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -464,15 +535,26 @@
   NavigateTo("/payment_request_email_test.html");
   WaitForObservedEvent();
 
-  // Make sure that a navigation is logged as a user abort.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -496,15 +578,26 @@
   ui_test_utils::NavigateToURL(browser(), other_origin_url);
   WaitForObservedEvent();
 
-  // Make sure that a navigation is logged as a user abort.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -525,15 +618,26 @@
   chrome::CloseTab(browser());
   WaitForObservedEvent();
 
-  // Make sure that a tab closing is logged as a user abort.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
@@ -554,15 +658,26 @@
   chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
   WaitForObservedEvent();
 
-  // Make sure that a reload is logged as a user abort.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
   ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
   EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
diff --git a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
index 7b94664..309af6cb 100644
--- a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
@@ -70,6 +70,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -112,6 +114,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -156,6 +160,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -201,6 +207,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -240,6 +248,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -279,6 +289,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -320,6 +332,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest,
@@ -361,6 +375,8 @@
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
   EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
 }
 
 class PaymentRequestInitiatedCompletionStatusMetricsTest
@@ -384,6 +400,13 @@
 
   // No abort reason should be logged.
   histogram_tester.ExpectTotalCount("PaymentRequest.CheckoutFunnel.Aborted", 0);
+
+  // There is one sample, because the request was initiated.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_EQ(JourneyLogger::EVENT_INITIATED | JourneyLogger::EVENT_USER_ABORTED,
+            buckets[0].min);
 }
 
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
index 1a8f9dc..fa54754 100644
--- a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
@@ -635,14 +635,6 @@
   histogram_tester.ExpectTotalCount("PaymentRequest.NumberOfSelectionEdits", 0);
   histogram_tester.ExpectTotalCount("PaymentRequest.NumberOfSuggestionsShown",
                                     0);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserHadSuggestionsForEverything", 0);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserDidNotHaveSuggestionsForEverything", 0);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserHadInitialFormOfPayment", 0);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserHadSuggestionsForEverything", 0);
 }
 
 class PaymentRequestCompleteSuggestionsForEverythingTest
@@ -672,16 +664,6 @@
   // Navigate away to abort the Payment Request and trigger the logs.
   NavigateTo("/payment_request_email_test.html");
 
-  // The fact that the user had a form of payment on file should be recorded.
-  histogram_tester.ExpectUniqueSample(
-      "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      0);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -719,16 +701,6 @@
   // Navigate away to abort the Payment Request and trigger the logs.
   NavigateTo("/payment_request_email_test.html");
 
-  // The fact that the user had no form of payment on file should be recorded.
-  histogram_tester.ExpectUniqueSample(
-      "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      0);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -772,16 +744,6 @@
   // Navigate away to abort the Payment Request and trigger the logs.
   NavigateTo("/payment_request_email_test.html");
 
-  // The fact that the user had no form of payment on file should be recorded.
-  histogram_tester.ExpectUniqueSample(
-      "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-  histogram_tester.ExpectTotalCount(
-      "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      0);
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
diff --git a/chrome/common/media_router/discovery/media_sink_internal.cc b/chrome/common/media_router/discovery/media_sink_internal.cc
index f78ca1a..66071dd 100644
--- a/chrome/common/media_router/discovery/media_sink_internal.cc
+++ b/chrome/common/media_router/discovery/media_sink_internal.cc
@@ -177,7 +177,8 @@
 bool CastSinkExtraData::operator==(const CastSinkExtraData& other) const {
   return ip_address == other.ip_address && port == other.port &&
          model_name == other.model_name && capabilities == other.capabilities &&
-         cast_channel_id == other.cast_channel_id;
+         cast_channel_id == other.cast_channel_id &&
+         discovered_by_dial == other.discovered_by_dial;
 }
 
 }  // namespace media_router
diff --git a/chrome/common/media_router/discovery/media_sink_internal.h b/chrome/common/media_router/discovery/media_sink_internal.h
index 7babd960..83fcea8 100644
--- a/chrome/common/media_router/discovery/media_sink_internal.h
+++ b/chrome/common/media_router/discovery/media_sink_internal.h
@@ -49,6 +49,9 @@
   // browser reconnects to a device.
   int cast_channel_id = 0;
 
+  // True if Cast channel is opened from DIAL sink.
+  bool discovered_by_dial = false;
+
   CastSinkExtraData();
   CastSinkExtraData(const CastSinkExtraData& other);
   ~CastSinkExtraData();
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 7427f13c..b521f46 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -996,6 +996,10 @@
 // Boolean pref indicating whether a user has enabled Tether.
 const char kInstantTetheringEnabled[] = "tether.enabled";
 
+// Boolean pref indicating whether this device supports BLE advertising.
+const char kInstantTetheringBleAdvertisingSupported[] =
+    "tether.ble_advertising_supported";
+
 // Boolean pref indicating whether someone can cast to the device.
 const char kCastReceiverEnabled[] = "cast_receiver.enabled";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 2e5464a7..f9e7d8a1 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -332,6 +332,7 @@
 extern const char kEnableQuickUnlockFingerprint[];
 extern const char kInstantTetheringAllowed[];
 extern const char kInstantTetheringEnabled[];
+extern const char kInstantTetheringBleAdvertisingSupported[];
 extern const char kCastReceiverEnabled[];
 extern const char kCastReceiverName[];
 #endif  // defined(OS_CHROMEOS)
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 37dfef2..b1d2ffa4 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -250,6 +250,9 @@
 // Enables ARC OptIn flow in OOBE.
 const char kEnableArcOOBEOptIn[] = "enable-arc-oobe-optin";
 
+// Enables the Cast Receiver.
+const char kEnableCastReceiver[] = "enable-cast-receiver";
+
 // Enables native ChromeVox support for Arc.
 const char kEnableChromeVoxArcSupport[] = "enable-chromevox-arc-support";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 0e84ffe..701cfe4 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -80,6 +80,7 @@
 CHROMEOS_EXPORT extern const char kEnableAndroidWallpapersApp[];
 CHROMEOS_EXPORT extern const char kEnableArc[];
 CHROMEOS_EXPORT extern const char kEnableArcOOBEOptIn[];
+CHROMEOS_EXPORT extern const char kEnableCastReceiver[];
 CHROMEOS_EXPORT extern const char kEnableChromeVoxArcSupport[];
 CHROMEOS_EXPORT extern const char kEnableConsumerKiosk[];
 CHROMEOS_EXPORT extern const char kEnableDataSaverPrompt[];
diff --git a/chromeos/components/tether/initializer.cc b/chromeos/components/tether/initializer.cc
index 6eb75e3..1eb416e 100644
--- a/chromeos/components/tether/initializer.cc
+++ b/chromeos/components/tether/initializer.cc
@@ -39,22 +39,11 @@
 #include "components/cryptauth/remote_beacon_seed_fetcher.h"
 #include "components/prefs/pref_service.h"
 #include "components/proximity_auth/logging/logging.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
 
 namespace chromeos {
 
 namespace tether {
 
-namespace {
-
-// TODO (hansberry): Experiment with intervals to determine ideal advertising
-//                   interval parameters.
-constexpr int64_t kMinAdvertisingIntervalMilliseconds = 100;
-constexpr int64_t kMaxAdvertisingIntervalMilliseconds = 100;
-
-}  // namespace
-
 // static
 Initializer* Initializer::instance_ = nullptr;
 
@@ -67,13 +56,8 @@
     NetworkStateHandler* network_state_handler,
     ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
     NetworkConnect* network_connect,
-    NetworkConnectionHandler* network_connection_handler) {
-  if (!device::BluetoothAdapterFactory::IsBluetoothSupported()) {
-    PA_LOG(WARNING) << "Bluetooth is not supported on this device; cannot "
-                    << "initialize Tether feature.";
-    return;
-  }
-
+    NetworkConnectionHandler* network_connection_handler,
+    scoped_refptr<device::BluetoothAdapter> adapter) {
   if (instance_) {
     // The Tether feature has already been initialized. No need to do anything.
     return;
@@ -84,7 +68,7 @@
       new Initializer(cryptauth_service, std::move(notification_presenter),
                       pref_service, token_service, network_state_handler,
                       managed_network_configuration_handler, network_connect,
-                      network_connection_handler);
+                      network_connection_handler, adapter);
 }
 
 // static
@@ -112,7 +96,8 @@
     NetworkStateHandler* network_state_handler,
     ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
     NetworkConnect* network_connect,
-    NetworkConnectionHandler* network_connection_handler)
+    NetworkConnectionHandler* network_connection_handler,
+    scoped_refptr<device::BluetoothAdapter> adapter)
     : cryptauth_service_(cryptauth_service),
       notification_presenter_(notification_presenter),
       pref_service_(pref_service),
@@ -122,6 +107,7 @@
           managed_network_configuration_handler),
       network_connect_(network_connect),
       network_connection_handler_(network_connection_handler),
+      adapter_(adapter),
       weak_ptr_factory_(this) {
   if (!token_service_->RefreshTokenIsAvailable(
           cryptauth_service_->GetAccountId())) {
@@ -132,7 +118,7 @@
   }
 
   PA_LOG(INFO) << "Refresh token is available; initializing tether feature.";
-  FetchBluetoothAdapter();
+  CreateComponent();
 }
 
 Initializer::~Initializer() {
@@ -140,11 +126,6 @@
   network_state_handler_->set_tether_sort_delegate(nullptr);
 }
 
-void Initializer::FetchBluetoothAdapter() {
-  device::BluetoothAdapterFactory::GetAdapter(base::Bind(
-      &Initializer::OnBluetoothAdapterFetched, weak_ptr_factory_.GetWeakPtr()));
-}
-
 void Initializer::OnRefreshTokensLoaded() {
   if (!token_service_->RefreshTokenIsAvailable(
           cryptauth_service_->GetAccountId())) {
@@ -156,25 +137,10 @@
   PA_LOG(INFO) << "Refresh token has loaded; initializing tether feature.";
 
   token_service_->RemoveObserver(this);
-  FetchBluetoothAdapter();
+  CreateComponent();
 }
 
-void Initializer::OnBluetoothAdapterFetched(
-    scoped_refptr<device::BluetoothAdapter> adapter) {
-  PA_LOG(INFO) << "Successfully fetched Bluetooth adapter. Setting advertising "
-               << "interval.";
-
-  adapter->SetAdvertisingInterval(
-      base::TimeDelta::FromMilliseconds(kMinAdvertisingIntervalMilliseconds),
-      base::TimeDelta::FromMilliseconds(kMaxAdvertisingIntervalMilliseconds),
-      base::Bind(&Initializer::OnBluetoothAdapterAdvertisingIntervalSet,
-                 weak_ptr_factory_.GetWeakPtr(), adapter),
-      base::Bind(&Initializer::OnBluetoothAdapterAdvertisingIntervalError,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void Initializer::OnBluetoothAdapterAdvertisingIntervalSet(
-    scoped_refptr<device::BluetoothAdapter> adapter) {
+void Initializer::CreateComponent() {
   PA_LOG(INFO) << "Successfully set Bluetooth advertisement interval. "
                << "Initializing tether feature.";
 
@@ -186,7 +152,7 @@
       base::MakeUnique<cryptauth::RemoteBeaconSeedFetcher>(
           cryptauth_service_->GetCryptAuthDeviceManager());
   ble_connection_manager_ = base::MakeUnique<BleConnectionManager>(
-      cryptauth_service_, adapter, local_device_data_provider_.get(),
+      cryptauth_service_, adapter_, local_device_data_provider_.get(),
       remote_beacon_seed_fetcher_.get(),
       cryptauth::BluetoothThrottlerImpl::GetInstance());
   tether_host_response_recorder_ =
@@ -269,12 +235,6 @@
   host_scan_scheduler_->ScheduleScan();
 }
 
-void Initializer::OnBluetoothAdapterAdvertisingIntervalError(
-    device::BluetoothAdvertisement::ErrorCode status) {
-  PA_LOG(ERROR) << "Failed to set Bluetooth advertisement interval; "
-                << "cannot use tether feature. Error code: " << status;
-}
-
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chromeos/components/tether/initializer.h b/chromeos/components/tether/initializer.h
index 004e69f2..c58993c 100644
--- a/chromeos/components/tether/initializer.h
+++ b/chromeos/components/tether/initializer.h
@@ -71,7 +71,8 @@
       NetworkStateHandler* network_state_handler,
       ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
       NetworkConnect* network_connect,
-      NetworkConnectionHandler* network_connection_handler);
+      NetworkConnectionHandler* network_connection_handler,
+      scoped_refptr<device::BluetoothAdapter> adapter);
 
   // Shuts down the tether feature, destroying all internal classes. This should
   // be called before the dependencies passed to Init() are destroyed.
@@ -92,19 +93,14 @@
       NetworkStateHandler* network_state_handler,
       ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
       NetworkConnect* network_connect,
-      NetworkConnectionHandler* network_connection_handler);
+      NetworkConnectionHandler* network_connection_handler,
+      scoped_refptr<device::BluetoothAdapter> adapter);
   ~Initializer() override;
 
   // OAuth2TokenService::Observer:
   void OnRefreshTokensLoaded() override;
 
-  void FetchBluetoothAdapter();
-  void OnBluetoothAdapterFetched(
-      scoped_refptr<device::BluetoothAdapter> adapter);
-  void OnBluetoothAdapterAdvertisingIntervalSet(
-      scoped_refptr<device::BluetoothAdapter> adapter);
-  void OnBluetoothAdapterAdvertisingIntervalError(
-      device::BluetoothAdvertisement::ErrorCode status);
+  void CreateComponent();
   void OnPreCrashStateRestored();
 
   cryptauth::CryptAuthService* cryptauth_service_;
@@ -115,6 +111,7 @@
   ManagedNetworkConfigurationHandler* managed_network_configuration_handler_;
   NetworkConnect* network_connect_;
   NetworkConnectionHandler* network_connection_handler_;
+  scoped_refptr<device::BluetoothAdapter> adapter_;
 
   // Declare new objects in the order that they will be created during
   // initialization to ensure that they are destroyed in the correct order. This
diff --git a/chromeos/components/tether/initializer_unittest.cc b/chromeos/components/tether/initializer_unittest.cc
index 3608c25d..ae8266bb6 100644
--- a/chromeos/components/tether/initializer_unittest.cc
+++ b/chromeos/components/tether/initializer_unittest.cc
@@ -151,8 +151,7 @@
     Initializer* initializer = new Initializer(
         cryptauth_service, notification_presenter, pref_service, token_service,
         network_state_handler, managed_network_configuration_handler,
-        network_connect, network_connection_handler);
-    initializer->OnBluetoothAdapterAdvertisingIntervalSet(adapter);
+        network_connect, network_connection_handler, adapter);
     delete initializer;
   }
 
diff --git a/components/metrics/net/network_metrics_provider.cc b/components/metrics/net/network_metrics_provider.cc
index b6d92f8..c8fe163 100644
--- a/components/metrics/net/network_metrics_provider.cc
+++ b/components/metrics/net/network_metrics_provider.cc
@@ -449,6 +449,15 @@
     return;
   }
 
+  if (min_effective_connection_type_ ==
+          net::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
+      max_effective_connection_type_ ==
+          net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
+    min_effective_connection_type_ = type;
+    max_effective_connection_type_ = type;
+    return;
+  }
+
   min_effective_connection_type_ =
       std::min(min_effective_connection_type_, effective_connection_type_);
   max_effective_connection_type_ =
@@ -457,6 +466,9 @@
   DCHECK_EQ(
       min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
       max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
+  DCHECK_EQ(
+      min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+      max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
 }
 
 }  // namespace metrics
diff --git a/components/metrics/net/network_metrics_provider.h b/components/metrics/net/network_metrics_provider.h
index 0b23d70..0e732f2 100644
--- a/components/metrics/net/network_metrics_provider.h
+++ b/components/metrics/net/network_metrics_provider.h
@@ -65,6 +65,8 @@
   FRIEND_TEST_ALL_PREFIXES(NetworkMetricsProviderTest, EffectiveConnectionType);
   FRIEND_TEST_ALL_PREFIXES(NetworkMetricsProviderTest,
                            ECTAmbiguousOnConnectionTypeChange);
+  FRIEND_TEST_ALL_PREFIXES(NetworkMetricsProviderTest,
+                           ECTNotAmbiguousOnOffline);
 
   // Listens to the changes in the effective conection type.
   class EffectiveConnectionTypeObserver;
diff --git a/components/metrics/net/network_metrics_provider_unittest.cc b/components/metrics/net/network_metrics_provider_unittest.cc
index 469a409..f9670b4 100644
--- a/components/metrics/net/network_metrics_provider_unittest.cc
+++ b/components/metrics/net/network_metrics_provider_unittest.cc
@@ -97,7 +97,6 @@
   // Running a request would cause the effective connection type to be computed
   // as 2G, and observers to be notified.
   estimator.RunOneRequest();
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
             network_metrics_provider.effective_connection_type_);
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
@@ -117,7 +116,6 @@
   // Running a request would cause the effective connection type to be computed
   // as SLOW_2G, and observers to be notified.
   estimator.RunOneRequest();
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
             network_metrics_provider.effective_connection_type_);
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
@@ -166,7 +164,6 @@
   // Running a request would cause the effective connection type to be computed
   // as 2G, and observers to be notified.
   estimator.RunOneRequest();
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
             network_metrics_provider.effective_connection_type_);
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
@@ -193,4 +190,47 @@
             system_profile.network().max_effective_connection_type());
 }
 
+// Verifies that the effective connection type is not set to UNKNOWN when the
+// connection type is OFFLINE.
+TEST_F(NetworkMetricsProviderTest, ECTNotAmbiguousOnOffline) {
+  for (net::EffectiveConnectionType force_ect :
+       {net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+        net::EFFECTIVE_CONNECTION_TYPE_OFFLINE}) {
+    std::unique_ptr<net::NetworkQualityEstimatorParams> params =
+        base::MakeUnique<net::NetworkQualityEstimatorParams>(
+            std::map<std::string, std::string>());
+    net::NetworkQualityEstimatorParams* params_ptr = params.get();
+    net::TestNetworkQualityEstimator estimator(std::move(params));
+
+    std::unique_ptr<NetworkMetricsProvider::NetworkQualityEstimatorProvider>
+        estimator_provider(base::WrapUnique(
+            new TestNetworkQualityEstimatorProvider(&estimator)));
+    SystemProfileProto system_profile;
+    NetworkMetricsProvider network_metrics_provider(
+        std::move(estimator_provider));
+
+    params_ptr->SetForcedEffectiveConnectionType(
+        net::EFFECTIVE_CONNECTION_TYPE_2G);
+    estimator.RunOneRequest();
+
+    params_ptr->SetForcedEffectiveConnectionType(force_ect);
+    estimator.RunOneRequest();
+    network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
+    EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+              system_profile.network().min_effective_connection_type());
+    EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+              system_profile.network().max_effective_connection_type());
+
+    params_ptr->SetForcedEffectiveConnectionType(
+        net::EFFECTIVE_CONNECTION_TYPE_4G);
+    estimator.RunOneRequest();
+
+    network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
+    EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G,
+              system_profile.network().min_effective_connection_type());
+    EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G,
+              system_profile.network().max_effective_connection_type());
+  }
+}
+
 }  // namespace metrics
\ No newline at end of file
diff --git a/components/metrics/proto/ukm/report.proto b/components/metrics/proto/ukm/report.proto
index 8627d5d..bca7902 100644
--- a/components/metrics/proto/ukm/report.proto
+++ b/components/metrics/proto/ukm/report.proto
@@ -25,6 +25,10 @@
   // that is incremented each time the user relaunches Chrome.
   optional int32 session_id = 5;
 
+  // The report id for this record.  Report ids increase sequentially from
+  // one within a session.
+  optional int32 report_id = 6;
+
   // Information about the user's browser and system configuration.
   optional metrics.SystemProfileProto system_profile = 2;
 
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc
index f57b008..14c89929 100644
--- a/components/payments/core/journey_logger.cc
+++ b/components/payments/core/journey_logger.cc
@@ -101,6 +101,10 @@
 }
 
 void JourneyLogger::SetCanMakePaymentValue(bool value) {
+  // Do not log the outcome of canMakePayment in incognito mode.
+  if (is_incognito_)
+    return;
+
   SetEventOccurred(value ? EVENT_CAN_MAKE_PAYMENT_TRUE
                          : EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
@@ -160,7 +164,6 @@
   DCHECK(!has_recorded_);
   has_recorded_ = true;
 
-  RecordCanMakePaymentStats(completion_status);
   RecordUrlKeyedMetrics(completion_status);
   RecordEventsMetric(completion_status);
 
@@ -179,16 +182,8 @@
 
 void JourneyLogger::RecordSectionSpecificStats(
     CompletionStatus completion_status) {
-  // Record whether the user had suggestions for each requested information.
-  bool user_had_all_requested_information = true;
-
-  // Record whether the user had at least one complete suggestion for each
-  // requested section.
-  bool user_had_complete_suggestions_ = true;
-
   for (int i = 0; i < NUMBER_OF_SECTIONS; ++i) {
     std::string name_suffix = GetHistogramNameSuffix(i, completion_status);
-
     // Only log the metrics for a section if it was requested by the merchant.
     if (sections_[i].is_requested_) {
       base::UmaHistogramCustomCounts(
@@ -207,93 +202,8 @@
           "PaymentRequest.NumberOfSuggestionsShown." + name_suffix,
           std::min(sections_[i].number_suggestions_shown_, MAX_EXPECTED_SAMPLE),
           MIN_EXPECTED_SAMPLE, MAX_EXPECTED_SAMPLE, NUMBER_BUCKETS);
-
-      if (sections_[i].number_suggestions_shown_ == 0) {
-        user_had_all_requested_information = false;
-        user_had_complete_suggestions_ = false;
-      } else if (!sections_[i].has_complete_suggestion_) {
-        user_had_complete_suggestions_ = false;
-      }
     }
   }
-
-  // Record metrics about completion based on whether the user had suggestions
-  // for each requested information.
-  if (user_had_all_requested_information) {
-    base::UmaHistogramEnumeration(
-        "PaymentRequest.UserHadSuggestionsForEverything."
-        "EffectOnCompletion",
-        completion_status, COMPLETION_STATUS_MAX);
-  } else {
-    base::UmaHistogramEnumeration(
-        "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-        "EffectOnCompletion",
-        completion_status, COMPLETION_STATUS_MAX);
-  }
-
-  // Record metrics about completion based on whether the user had complete
-  // suggestions for each requested information.
-  if (user_had_complete_suggestions_) {
-    base::UmaHistogramEnumeration(
-        "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-        "EffectOnCompletion",
-        completion_status, COMPLETION_STATUS_MAX);
-  } else {
-    base::UmaHistogramEnumeration(
-        "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-        "EffectOnCompletion",
-        completion_status, COMPLETION_STATUS_MAX);
-  }
-}
-
-void JourneyLogger::RecordCanMakePaymentStats(
-    CompletionStatus completion_status) {
-  // CanMakePayment always returns true in incognito mode. Don't log the
-  // metrics.
-  if (is_incognito_)
-    return;
-
-  // Record CanMakePayment usage.
-  UMA_HISTOGRAM_ENUMERATION("PaymentRequest.CanMakePayment.Usage",
-                            WasCanMakePaymentUsed() ? CAN_MAKE_PAYMENT_USED
-                                                    : CAN_MAKE_PAYMENT_NOT_USED,
-                            CAN_MAKE_PAYMENT_USE_MAX);
-
-  RecordCanMakePaymentEffectOnShow();
-  RecordCanMakePaymentEffectOnCompletion(completion_status);
-}
-
-void JourneyLogger::RecordCanMakePaymentEffectOnShow() {
-  if (!WasCanMakePaymentUsed())
-    return;
-
-  int effect_on_trigger = 0;
-  if (WasPaymentRequestTriggered())
-    effect_on_trigger |= CMP_EFFECT_ON_SHOW_DID_SHOW;
-  if (CouldMakePayment())
-    effect_on_trigger |= CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT;
-
-  UMA_HISTOGRAM_ENUMERATION("PaymentRequest.CanMakePayment.Used.EffectOnShow",
-                            static_cast<CmpEffectOnShow>(effect_on_trigger),
-                            CMP_EFFECT_ON_SHOW_MAX);
-}
-
-void JourneyLogger::RecordCanMakePaymentEffectOnCompletion(
-    CompletionStatus completion_status) {
-  if (!WasPaymentRequestTriggered())
-    return;
-
-  std::string histogram_name = "PaymentRequest.CanMakePayment.";
-  if (!WasCanMakePaymentUsed()) {
-    histogram_name += "NotUsed.WithShowEffectOnCompletion";
-  } else if (CouldMakePayment()) {
-    histogram_name += "Used.TrueWithShowEffectOnCompletion";
-  } else {
-    histogram_name += "Used.FalseWithShowEffectOnCompletion";
-  }
-
-  base::UmaHistogramEnumeration(histogram_name, completion_status,
-                                COMPLETION_STATUS_MAX);
 }
 
 void JourneyLogger::RecordEventsMetric(CompletionStatus completion_status) {
@@ -349,15 +259,6 @@
   builder->AddMetric(internal::kUKMEventsMetricName, events_);
 }
 
-bool JourneyLogger::WasCanMakePaymentUsed() {
-  return (events_ & EVENT_CAN_MAKE_PAYMENT_FALSE) > 0 ||
-         (events_ & EVENT_CAN_MAKE_PAYMENT_TRUE) > 0;
-}
-
-bool JourneyLogger::CouldMakePayment() {
-  return (events_ & EVENT_CAN_MAKE_PAYMENT_TRUE) > 0;
-}
-
 bool JourneyLogger::WasPaymentRequestTriggered() {
   return (events_ & EVENT_SHOWN) > 0 || (events_ & EVENT_SKIPPED_SHOW) > 0;
 }
diff --git a/components/payments/core/journey_logger.h b/components/payments/core/journey_logger.h
index f7665b1..6b8104a 100644
--- a/components/payments/core/journey_logger.h
+++ b/components/payments/core/journey_logger.h
@@ -43,15 +43,6 @@
     SECTION_MAX,
   };
 
-  // For the CanMakePayment histograms.
-  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
-  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: CanMakePaymentUsage
-  enum CanMakePaymentUsage {
-    CAN_MAKE_PAYMENT_USED = 0,
-    CAN_MAKE_PAYMENT_NOT_USED = 1,
-    CAN_MAKE_PAYMENT_USE_MAX,
-  };
-
   // The payment method that was used by the user to complete the transaction.
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
   // GENERATED_JAVA_CLASS_NAME_OVERRIDE: SelectedPaymentMethod
@@ -62,17 +53,6 @@
     SELECTED_PAYMENT_METHOD_MAX = 3,
   };
 
-  // Used to mesure the impact of the CanMakePayment return value on whether the
-  // Payment Request is shown to the user.
-  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
-  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: CanMakePaymentEffectOnShow
-  enum CmpEffectOnShow {
-    CMP_EFFECT_ON_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW = 0,
-    CMP_EFFECT_ON_SHOW_DID_SHOW = 1 << 0,
-    CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT = 1 << 1,
-    CMP_EFFECT_ON_SHOW_MAX = 4,
-  };
-
   // Used to log different parameters' effect on whether the transaction was
   // completed.
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
@@ -226,19 +206,6 @@
   // merchant.
   void RecordSectionSpecificStats(CompletionStatus completion_status);
 
-  // Records the metrics related the the CanMakePayment method unless in
-  // incognito mode.
-  void RecordCanMakePaymentStats(CompletionStatus completion_status);
-
-  // Records CanMakePayment's return value effect on whether the Payment Request
-  // was shown or not.
-  void RecordCanMakePaymentEffectOnShow();
-
-  // Records the completion status depending on the the usage and return value
-  // of the CanMakePaymentMethod.
-  void RecordCanMakePaymentEffectOnCompletion(
-      CompletionStatus completion_status);
-
   // Records the metric about the different events that happened during the
   // Payment Request.
   void RecordEventsMetric(CompletionStatus completion_status);
@@ -246,12 +213,6 @@
   // Records the Payment Request Url Keyed Metrics.
   void RecordUrlKeyedMetrics(CompletionStatus completion_status);
 
-  // Returns whether canMakePayment was used.
-  bool WasCanMakePaymentUsed();
-
-  // Returns whether the answer to canMakePayment was true or false;
-  bool CouldMakePayment();
-
   // Returns whether this Payment Request was triggered (shown or skipped show).
   bool WasPaymentRequestTriggered();
 
diff --git a/components/payments/core/journey_logger_unittest.cc b/components/payments/core/journey_logger_unittest.cc
index c7124dc..acb1e4ab 100644
--- a/components/payments/core/journey_logger_unittest.cc
+++ b/components/payments/core/journey_logger_unittest.cc
@@ -27,15 +27,13 @@
 
   logger.SetCompleted();
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-
-  // There should be no completion stats since PR was not shown to the user
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix(
-          "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
 
 // Tests the canMakePayment stats for the case where the merchant does not use
@@ -46,26 +44,20 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The merchant does not query CanMakePayment, show the PaymentRequest and the
   // user aborts it.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
   logger.SetRequestedInformation(true, false, false, false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-
-  // There should be a record for an abort when CanMakePayment is not used but
-  // the PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant does not use
@@ -76,26 +68,20 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The merchant does not query CanMakePayment, show the PaymentRequest and
   // there is an abort not initiated by the user.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
   logger.SetRequestedInformation(true, false, false, false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-
-  // There should be a record for an abort when CanMakePayment is not used but
-  // the PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant does not use
@@ -106,26 +92,20 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The merchant does not query CanMakePayment, show the PaymentRequest and the
   // user completes it.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
   logger.SetRequestedInformation(true, false, false, false);
   logger.SetCompleted();
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-
-  // There should be a record for an abort when CanMakePayment is not used but
-  // the PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -136,30 +116,18 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetCanMakePaymentValue(false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being false and not
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW,
-      1);
-
-  // There should be no completion stats since PR was not shown to the user.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix(
-          "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -170,29 +138,18 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user can make payment and the PaymentRequest is not shown.
   logger.SetCanMakePaymentValue(true);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being true and not
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT, 1);
-
-  // There should be no completion stats since PR was not shown to the user.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix(
-          "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -203,11 +160,6 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user cannot make payment, the Payment Request is shown but is aborted
   // by the user.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
@@ -215,19 +167,14 @@
   logger.SetCanMakePaymentValue(false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being false and
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-  // There should be a record for an abort when CanMakePayment is false but the
-  // PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -238,30 +185,20 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user cannot make payment, the Payment Request is shown but is aborted.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
   logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being false and
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-  // There should be a record for an abort when CanMakePayment is false but the
-  // PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -272,11 +209,6 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user cannot make payment, the payment request is shown and is
   // completed.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
@@ -284,20 +216,14 @@
   logger.SetCanMakePaymentValue(false);
   logger.SetCompleted();
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being false and
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-
-  // There should be a record for an completion when CanMakePayment is false but
-  // the PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -308,11 +234,6 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user can make payment, the Payment Request is shown and aborted by the
   // user.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
@@ -320,21 +241,14 @@
   logger.SetCanMakePaymentValue(true);
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being true and not
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
-          JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
-      1);
-  // There should be a record for an abort when CanMakePayment is true and the
-  // PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -345,32 +259,21 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
-  // The user can make a payment, the request is shown but the user aborts.
+  // The user can make a payment, the request is shown but the transaction is
+  // aborted.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
   logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(true);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being true and not
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
-          JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
-      1);
-  // There should be a record for an abort when CanMakePayment is true and the
-  // PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
 }
 
 // Tests the canMakePayment stats for the case where the merchant uses it,
@@ -381,11 +284,6 @@
   JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user can make a payment, the request is shown and the user completes
   // the checkout.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
@@ -393,21 +291,14 @@
   logger.SetCanMakePaymentValue(true);
   logger.SetCompleted();
 
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
-  // The CanMakePayment effect on show should be recorded as being true and not
-  // shown.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.EffectOnShow",
-      JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
-          JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
-      1);
-  // There should be a record for a completion when CanMakePayment is true and
-  // the PR is shown to the user.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
 }
 
 // Tests the canMakePayment metrics are not logged if the Payment Request was
@@ -418,11 +309,6 @@
   JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""),
                        /*ukm_recorder=*/nullptr);
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // The user can make a payment, the request is shown and the user completes
   // the checkout.
   logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
@@ -430,10 +316,14 @@
   logger.SetCanMakePaymentValue(true);
   logger.SetCompleted();
 
-  // Expect no log for CanMakePayment.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
 }
 
 // Tests that the completion status metrics based on whether the user had
@@ -459,17 +349,6 @@
   // Simulate that the user completes the checkout.
   logger.SetCompleted();
 
-  // Make sure that the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
-  // Make sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -510,17 +389,6 @@
   // Simulate that the user aborts the checkout.
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  // Make sure the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
-  // Make sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -561,17 +429,6 @@
   // Simulate that the checkout is aborted.
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  // Make sure the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
-  // Make sure that the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -613,17 +470,6 @@
   // Simulate that the user completes the checkout.
   logger.SetCompleted();
 
-  // Make sure the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
-  // Make sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -664,18 +510,6 @@
   // Simulate that the user completes the checkout.
   logger.SetCompleted();
 
-  // Make sure the expected metrics was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
-  // Make sure the opposite metrics was not logged.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix(
-          "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -716,18 +550,6 @@
   // Simulate that the user aborts the checkout.
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  // Make sure the metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
-  // Make sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserHadSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -768,18 +590,6 @@
   // Simulate that the the checkout is aborted.
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  // Make sure the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
-  // Make sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserHadSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -821,18 +631,6 @@
   // Simulate that the user aborts the checkout.
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  // Make sure the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
-  // Make sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserHadSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -875,18 +673,6 @@
   // Simulate that the the checkout is aborted.
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  // Make sure the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
-  // Makes sure the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -931,18 +717,6 @@
   // Simulate that the the checkout is aborted.
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  // Make sure that the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
-  // Make sure that the opposite metric was not logged.
-  EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
-                  "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-                  "EffectOnCompletion"),
-              testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -987,19 +761,6 @@
   // Simulate that the the checkout is aborted.
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
-  // Make sure that the expected metric was logged.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserHadCompleteSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
-  // Make sure that the opposite metric was not logged.
-  EXPECT_THAT(
-      histogram_tester.GetTotalCountsForPrefix(
-          "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
-          "EffectOnCompletion"),
-      testing::ContainerEq(base::HistogramTester::CountsMap()));
-
   // Make sure the correct events were logged.
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -1047,27 +808,40 @@
   logger1.SetCompleted();
   logger2.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
-  // Make sure the appropriate metrics were logged for logger1.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
-  // Make sure the appropriate metrics were logged for logger2.
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
-      "EffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-  histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
-                                     JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
-                                     1);
-  histogram_tester.ExpectBucketCount(
-      "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
-      JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(2U, buckets.size());
+  // logger2
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_FALSE(buckets[0].min &
+               JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+  // logger1
+  EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_FALSE(buckets[1].min &
+               JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+  EXPECT_TRUE(buckets[1].min &
+              JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+  EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_OTHER_ABORTED);
+  EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_COMPLETED);
+  EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_USER_ABORTED);
+  EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+  EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+  EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+  EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+  EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+  EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
 }
 
 // Tests that the Payment Request UKMs are logged correctly when the user aborts
diff --git a/components/ukm/ukm_service.cc b/components/ukm/ukm_service.cc
index 7ca995bb..8a2a2e4 100644
--- a/components/ukm/ukm_service.cc
+++ b/components/ukm/ukm_service.cc
@@ -34,12 +34,6 @@
 // initialization work.
 constexpr int kInitializationDelaySeconds = 5;
 
-// True if we should record session ids in the UKM Report proto.
-bool ShouldRecordSessionId() {
-  return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "RecordSessionId",
-                                                 false);
-}
-
 // Generates a new client id and stores it in prefs.
 uint64_t GenerateClientId(PrefService* pref_service) {
   uint64_t client_id = 0;
@@ -73,6 +67,7 @@
     : pref_service_(pref_service),
       client_id_(0),
       session_id_(0),
+      report_count_(0),
       client_(client),
       reporting_service_(client, pref_service),
       initialize_started_(false),
@@ -192,6 +187,7 @@
 void UkmService::ResetClientId() {
   client_id_ = GenerateClientId(pref_service_);
   session_id_ = LoadSessionId(pref_service_);
+  report_count_ = 0;
 }
 
 void UkmService::RegisterMetricsProvider(
@@ -211,6 +207,7 @@
   DVLOG(1) << "UkmService::StartInitTask";
   client_id_ = LoadOrGenerateClientId(pref_service_);
   session_id_ = LoadSessionId(pref_service_);
+  report_count_ = 0;
 
   metrics_providers_.AsyncInit(base::Bind(&UkmService::FinishedInitTask,
                                           self_ptr_factory_.GetWeakPtr()));
@@ -242,8 +239,8 @@
 
   Report report;
   report.set_client_id(client_id_);
-  if (ShouldRecordSessionId())
-    report.set_session_id(session_id_);
+  report.set_session_id(session_id_);
+  report.set_report_id(++report_count_);
 
   StoreRecordingsInReport(&report);
 
diff --git a/components/ukm/ukm_service.h b/components/ukm/ukm_service.h
index c7e18cf..22b7ef5 100644
--- a/components/ukm/ukm_service.h
+++ b/components/ukm/ukm_service.h
@@ -116,6 +116,9 @@
   // The UKM session id stored in prefs.
   int32_t session_id_;
 
+  // The number of reports generated this session.
+  int32_t report_count_;
+
   // Used to interact with the embedder. Weak pointer; must outlive |this|
   // instance.
   metrics::MetricsServiceClient* const client_;
diff --git a/components/ukm/ukm_service_unittest.cc b/components/ukm/ukm_service_unittest.cc
index 4059680e..75b383ab 100644
--- a/components/ukm/ukm_service_unittest.cc
+++ b/components/ukm/ukm_service_unittest.cc
@@ -209,7 +209,7 @@
 
   Report proto_report = GetPersistedReport();
   EXPECT_EQ(1, proto_report.sources_size());
-  EXPECT_FALSE(proto_report.has_session_id());
+  EXPECT_TRUE(proto_report.has_session_id());
   const Source& proto_source = proto_report.sources(0);
 
   EXPECT_EQ(id, proto_source.id());
@@ -428,30 +428,24 @@
 }
 
 TEST_F(UkmServiceTest, RecordSessionId) {
-  for (bool should_record_session_id : {true, false}) {
-    base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
-    ScopedUkmFeatureParams params(
-        base::FeatureList::OVERRIDE_ENABLE_FEATURE,
-        {{"RecordSessionId", should_record_session_id ? "true" : "false"}});
+  ClearPrefs();
+  UkmService service(&prefs_, &client_);
+  TestRecordingHelper recorder(&service);
+  EXPECT_EQ(0, GetPersistedLogCount());
+  service.Initialize();
+  task_runner_->RunUntilIdle();
+  service.EnableRecording();
+  service.EnableReporting();
 
-    ClearPrefs();
-    UkmService service(&prefs_, &client_);
-    TestRecordingHelper recorder(&service);
-    EXPECT_EQ(0, GetPersistedLogCount());
-    service.Initialize();
-    task_runner_->RunUntilIdle();
-    service.EnableRecording();
-    service.EnableReporting();
+  auto id = UkmRecorder::GetNewSourceID();
+  recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
 
-    auto id = UkmRecorder::GetNewSourceID();
-    recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
+  service.Flush();
+  EXPECT_EQ(1, GetPersistedLogCount());
 
-    service.Flush();
-    EXPECT_EQ(1, GetPersistedLogCount());
-
-    auto proto_report = GetPersistedReport();
-    EXPECT_EQ(should_record_session_id, proto_report.has_session_id());
-  }
+  auto proto_report = GetPersistedReport();
+  EXPECT_TRUE(proto_report.has_session_id());
+  EXPECT_EQ(1, proto_report.report_id());
 }
 
 TEST_F(UkmServiceTest, SourceSize) {
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index d094ec1f9..4055636 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -89,11 +89,13 @@
 using blink::WebSelection;
 using blink::WebSize;
 using blink::WebBrowserControlsState;
+using blink::WebLayerTreeView;
 
 namespace content {
 namespace {
 
-using ReportTimeCallback = base::Callback<void(bool, double)>;
+using ReportTimeCallback =
+    base::Callback<void(WebLayerTreeView::SwapResult, double)>;
 
 double MonotonicallyIncreasingTime() {
   return static_cast<double>(base::TimeTicks::Now().ToInternalValue()) /
@@ -131,12 +133,30 @@
 void ReportTimeSwapPromise::DidSwap() {
   task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(callback_, true, MonotonicallyIncreasingTime()));
+      base::BindOnce(callback_, WebLayerTreeView::SwapResult::kDidSwap,
+                     MonotonicallyIncreasingTime()));
 }
 
 cc::SwapPromise::DidNotSwapAction ReportTimeSwapPromise::DidNotSwap(
     cc::SwapPromise::DidNotSwapReason reason) {
-  task_runner_->PostTask(FROM_HERE, base::BindOnce(callback_, false, 0));
+  WebLayerTreeView::SwapResult result;
+  switch (reason) {
+    case cc::SwapPromise::DidNotSwapReason::SWAP_FAILS:
+      result = WebLayerTreeView::SwapResult::kDidNotSwapSwapFails;
+      break;
+    case cc::SwapPromise::DidNotSwapReason::COMMIT_FAILS:
+      result = WebLayerTreeView::SwapResult::kDidNotSwapCommitFails;
+      break;
+    case cc::SwapPromise::DidNotSwapReason::COMMIT_NO_UPDATE:
+      result = WebLayerTreeView::SwapResult::kDidNotSwapCommitNoUpdate;
+      break;
+    case cc::SwapPromise::DidNotSwapReason::ACTIVATION_FAILS:
+      result = WebLayerTreeView::SwapResult::kDidNotSwapActivationFails;
+      break;
+  }
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(callback_, result, MonotonicallyIncreasingTime()));
   return cc::SwapPromise::DidNotSwapAction::BREAK_PROMISE;
 }
 
@@ -724,6 +744,11 @@
   return layer_tree_host_->SendMessageToMicroBenchmark(id, std::move(value));
 }
 
+void RenderWidgetCompositor::SetViewportSize(
+    const gfx::Size& device_viewport_size) {
+  layer_tree_host_->SetViewportSize(device_viewport_size);
+}
+
 viz::FrameSinkId RenderWidgetCompositor::GetFrameSinkId() {
   return frame_sink_id_;
 }
@@ -741,11 +766,6 @@
   return animation_host_.get();
 }
 
-void RenderWidgetCompositor::SetViewportSize(
-    const WebSize& device_viewport_size) {
-  layer_tree_host_->SetViewportSize(device_viewport_size);
-}
-
 WebSize RenderWidgetCompositor::GetViewportSize() const {
   return layer_tree_host_->device_viewport_size();
 }
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 083ef48c..cfaa25e 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -54,7 +54,8 @@
     : NON_EXPORTED_BASE(public blink::WebLayerTreeView),
       NON_EXPORTED_BASE(public cc::LayerTreeHostClient),
       NON_EXPORTED_BASE(public cc::LayerTreeHostSingleThreadClient) {
-  using ReportTimeCallback = base::Callback<void(bool, double)>;
+  using ReportTimeCallback =
+      base::Callback<void(blink::WebLayerTreeView::SwapResult, double)>;
 
  public:
   // Attempt to construct and initialize a compositor instance for the widget
@@ -118,13 +119,13 @@
   void SetIsForOopif(bool is_for_oopif);
   void SetContentSourceId(uint32_t source_id);
   void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id);
+  void SetViewportSize(const gfx::Size& device_viewport_size);
 
   // WebLayerTreeView implementation.
   viz::FrameSinkId GetFrameSinkId() override;
   void SetRootLayer(const blink::WebLayer& layer) override;
   void ClearRootLayer() override;
   cc::AnimationHost* CompositorAnimationHost() override;
-  void SetViewportSize(const blink::WebSize& device_viewport_size) override;
   blink::WebSize GetViewportSize() const override;
   virtual blink::WebFloatPoint adjustEventPointForPinchZoom(
       const blink::WebFloatPoint& point) const;
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index c60e8fc..a68560c 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -482,10 +482,6 @@
     self.Fail('deqp/functional/gles3/framebufferblit/conversion_33.html',
         ['mac', ('nvidia', 0xfe9)], bug=654187)
 
-    # When this fails on this configuration, it fails multiple times in a row.
-    self.Fail('deqp/functional/gles3/shaderoperator/common_functions.html',
-        ['mac', 'nvidia'], bug=702336)
-
     # Mac AMD
     # TODO(kbr): uncomment the following two exepectations after test
     # has been made more robust.
@@ -493,8 +489,6 @@
     #     ['mac', 'amd'], bug=735483)
     # self.Fail('conformance2/rendering/texture-switch-performance.html',
     #     ['mac', 'amd'], bug=735483)
-    self.Fail('deqp/functional/gles3/shaderoperator/common_functions.html',
-        ['mac', 'amd'], bug=702336)
     self.Fail('deqp/functional/gles3/transformfeedback/' +
         'array_interleaved_lines.html',
         ['mac', 'amd'], bug=483282)
@@ -588,8 +582,6 @@
         ['mac', 'amd'], bug=642822)
 
     # Mac Intel
-    self.Flaky('deqp/functional/gles3/shaderoperator/common_functions.html',
-        ['mac', 'intel'], bug=702336)
     self.Fail('conformance2/rendering/framebuffer-texture-level1.html',
         ['mac', 'intel'], bug=680278)
     self.Fail('conformance2/textures/misc/angle-stuck-depth-textures.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py b/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
index 1fc4fbc..241255a 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
@@ -206,7 +206,7 @@
 
   def _CheckTestCompletion(self):
     self.tab.action_runner.WaitForJavaScriptCondition(
-        'webglTestHarness._finished', timeout=300)
+        'webglTestHarness._finished', timeout=self._GetTestTimeout())
     if not self._DidWebGLTestSucceed(self.tab):
       self.fail(self._WebGLTestMessages(self.tab))
 
@@ -221,7 +221,7 @@
   def _RunExtensionCoverageTest(self, test_path, *args):
     self._NavigateTo(test_path, self._GetExtensionHarnessScript())
     self.tab.action_runner.WaitForJavaScriptCondition(
-        'window._loaded', timeout=300)
+        'window._loaded', timeout=self._GetTestTimeout())
     extension_list = args[0]
     webgl_version = args[1]
     context_type = "webgl2" if webgl_version == 2 else "webgl"
@@ -237,7 +237,7 @@
   def _RunExtensionTest(self, test_path, *args):
     self._NavigateTo(test_path, self._GetExtensionHarnessScript())
     self.tab.action_runner.WaitForJavaScriptCondition(
-        'window._loaded', timeout=300)
+        'window._loaded', timeout=self._GetTestTimeout())
     extension = args[0]
     webgl_version = args[1]
     context_type = "webgl2" if webgl_version == 2 else "webgl"
@@ -246,6 +246,13 @@
       extension=extension, context_type=context_type)
     self._CheckTestCompletion()
 
+  def _GetTestTimeout(self):
+    timeout = 300
+    if self._is_asan:
+      # Asan runs much slower and needs a longer timeout
+      timeout *= 2
+    return timeout
+
   @classmethod
   def SetupWebGLBrowserArgs(cls, browser_args):
     # --test-type=gpu is used only to suppress the "Google API Keys are missing"
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index 17c2162f..d50b690 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -250,6 +250,9 @@
 }
 
 void ShellBrowserMainParts::PostMainMessageLoopRun() {
+  // Close apps before shutting down browser context and extensions system.
+  desktop_controller_->CloseAppWindows();
+
   // NOTE: Please destroy objects in the reverse order of their creation.
   browser_main_delegate_->Shutdown();
   content::ShellDevToolsManagerDelegate::StopHttpHandler();
diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h
index 40fe3d57..23267992 100644
--- a/gpu/command_buffer/common/constants.h
+++ b/gpu/command_buffer/common/constants.h
@@ -75,7 +75,7 @@
 const size_t kDefaultMaxProgramCacheMemoryBytes = 6 * 1024 * 1024;
 #else
 const size_t kDefaultMaxProgramCacheMemoryBytes = 2 * 1024 * 1024;
-const size_t kLowEndMaxProgramCacheMemoryBytes = 512 * 1024;
+const size_t kLowEndMaxProgramCacheMemoryBytes = 128 * 1024;
 #endif
 
 // Namespace used to separate various command buffer types.
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 54c4888..2627a222 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -95,7 +95,9 @@
       builders { name: "win_chromium_compile_dbg_ng" }
       builders { name: "win_chromium_rel_ng" }
       builders { name: "win_chromium_x64_rel_ng" }
-      builders { name: "win_clang" }
+      # https://crbug.com/753184 temporarily disable this builder to
+      # shed load (?)
+      # builders { name: "win_clang" }
     }
   }
 
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
index ddf777ee3..403fecd5 100644
--- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -442,7 +442,9 @@
 - (CollectionViewItem*)accountItemDetailWithError {
   CollectionViewAccountItem* accountItemDetail =
       [[CollectionViewAccountItem alloc] initWithType:ItemTypeAccountDetail];
-  accountItemDetail.image = [UIImage imageNamed:@"default_avatar"];
+  // TODO(crbug.com/754032): ios_default_avatar image is from a downstream iOS
+  // internal repository. It should be used through a provider API instead.
+  accountItemDetail.image = [UIImage imageNamed:@"ios_default_avatar"];
   accountItemDetail.text = @"Account User Name";
   accountItemDetail.detailText =
       @"Syncing to AccountUserNameAccount@example.com";
@@ -455,7 +457,9 @@
 - (CollectionViewItem*)accountItemCheckMark {
   CollectionViewAccountItem* accountItemCheckMark =
       [[CollectionViewAccountItem alloc] initWithType:ItemTypeAccountCheckMark];
-  accountItemCheckMark.image = [UIImage imageNamed:@"default_avatar"];
+  // TODO(crbug.com/754032): ios_default_avatar image is from a downstream iOS
+  // internal repository. It should be used through a provider API instead.
+  accountItemCheckMark.image = [UIImage imageNamed:@"ios_default_avatar"];
   accountItemCheckMark.text = @"Lorem ipsum dolor sit amet, consectetur "
                               @"adipiscing elit, sed do eiusmod tempor "
                               @"incididunt ut labore et dolore magna aliqua.";
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn
index 3ad3410..e297c9a 100644
--- a/net/android/BUILD.gn
+++ b/net/android/BUILD.gn
@@ -87,6 +87,10 @@
     "//base:base_java",
     "//base:base_java_test_support",
   ]
+
+  data_deps = [
+    "//net:test_support",
+  ]
 }
 
 source_set("java_test_native_support") {
@@ -173,6 +177,7 @@
 
 java_cpp_enum("net_java_test_support_enums_srcjar") {
   sources = [
+    "../test/embedded_test_server/embedded_test_server.h",
     "../test/url_request/url_request_failed_job.h",
   ]
 }
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index afb0a1e..94de2728 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -223,15 +223,13 @@
       "static_spki_hashes": [
         "LetsEncryptAuthorityPrimary_X1_X3",
         "LetsEncryptAuthorityBackup_X2_X4",
-        "VeriSignClass3_G4",
-        "VeriSignClass3_G5",
-        "VeriSignUniversal",
         "DigiCertGlobalRoot",
         "DigiCertEVRoot",
         "DigiCertAssuredIDRoot",
-        "COMODOCertificationAuthority",
         "AddTrustExternalCARoot",
-        "BaltimoreCyberTrustRoot"
+        "BaltimoreCyberTrustRoot",
+        "COMODORSACertificationAuthority",
+        "COMODOECCCertificationAuthority"
       ],
       "report_uri": "https://log.ncsccs.com/report/hpkp"
     }
@@ -33314,7 +33312,6 @@
     { "name": "crypto.is", "include_subdomains": true, "mode": "force-https", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
     { "name": "ritter.vg", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload", "expect_staple": true, "expect_staple_report_uri": "https://asac.casa/expectstaple.jsp" },
     { "name": "tails.boum.org", "include_subdomains": true, "mode": "force-https" },
-    { "name": "0.me.uk", "include_subdomains": true, "mode": "force-https", "pins": "ncsccs" },
     { "name": "ncsccs.com", "include_subdomains": true, "mode": "force-https", "pins": "ncsccs" },
     { "name": "themathematician.uk", "include_subdomains": true, "mode": "force-https", "pins": "ncsccs" },
     { "name": "baas-becking.biology.utah.edu", "include_subdomains": true, "mode": "force-https" },
@@ -33363,15 +33360,6 @@
       "expect_ct_report_uri": "https://tobiassachs.report-uri.io/r/default/ct/reportOnly"
     },
     {
-      "name": "secretintelligence.0.me.uk",
-      "mode": "force-https", "include_subdomains": true,
-      "pins": "ncsccs",
-      "expect_staple": true, "include_subdomains_for_expect_staple": true,
-      "expect_staple_report_uri": "https://log.ncsccs.com/report/expectocsp",
-      "expect_ct": true,
-      "expect_ct_report_uri": "https://log.ncsccs.com/report/expectct"
-    },
-    {
       "name": "cloudflare.com",
       "mode": "force-https", "include_subdomains": false,
       "expect_staple": true,
@@ -33395,6 +33383,14 @@
       "expect_staple": true, "include_subdomains_for_expect_staple": true,
       "expect_staple_report_uri": "https://weeblr.report-uri.io/r/default/staple/reportOnly"
     },
+    {
+      "name": "0.me.uk",
+      "mode": "force-https", "include_subdomains": true, "pins": "ncsccs",
+      "expect_staple": true, "include_subdomains_for_expect_staple": true,
+      "expect_staple_report_uri": "https://log.ncsccs.com/report/expectstaple",
+      "expect_ct": true,
+      "expect_ct_report_uri": "https://log.ncsccs.com/report/expectct"
+    },
     // END OF MANUAL ENTRIES
 
     // TODO(lgarron): hstspreload.org can't scan IPv6-only sites due to Google
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 52ccb69..2ea4f0b8 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -1550,4 +1550,60 @@
 0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap
 lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf
 +AZxAeKCINT+b72x
------END CERTIFICATE-----
\ No newline at end of file
+-----END CERTIFICATE-----
+
+# https://support.comodo.com/index.php?/Knowledgebase/Article/View/969/108/root-comodo-rsa-certification-authority-sha-2
+COMODORSACertificationAuthority
+-----BEGIN CERTIFICATE-----
+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
+MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
+6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
+pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
+9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
+/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
+Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
+qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
+SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
+u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
+Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
+crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
+/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
+wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
+4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
+2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
+FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
+CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
+boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
+jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
+S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
+QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
+0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
+NVOFBkpdn627G190
+-----END CERTIFICATE-----
+
+# https://bugzilla.mozilla.org/show_bug.cgi?id=421946
+COMODOECCCertificationAuthority
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
+IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
+MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
+ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
+T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
+FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
+cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
+BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
+fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
+GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 6e39d433..3528b40e 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -353,7 +353,7 @@
     base::TimeTicks now = tick_clock_->NowTicks();
     last_main_frame_request_ = now;
 
-    MaybeComputeEffectiveConnectionType();
+    ComputeEffectiveConnectionType();
     effective_connection_type_at_last_main_frame_ = effective_connection_type_;
     estimated_quality_at_last_main_frame_ = network_quality_;
 
@@ -377,6 +377,8 @@
                      weak_ptr_factory_.GetWeakPtr(), measuring_delay),
           measuring_delay);
     }
+  } else {
+    MaybeComputeEffectiveConnectionType();
   }
   throughput_analyzer_->NotifyStartTransaction(request);
 }
diff --git a/net/nqe/network_quality_estimator_test_util.cc b/net/nqe/network_quality_estimator_test_util.cc
index 17af4235..ff39d6f 100644
--- a/net/nqe/network_quality_estimator_test_util.cc
+++ b/net/nqe/network_quality_estimator_test_util.cc
@@ -87,6 +87,27 @@
   EXPECT_TRUE(embedded_test_server_.Start());
 }
 
+TestNetworkQualityEstimator::TestNetworkQualityEstimator(
+    std::unique_ptr<NetworkQualityEstimatorParams> params)
+    : TestNetworkQualityEstimator(std::move(params),
+                                  base::MakeUnique<BoundTestNetLog>()) {}
+
+TestNetworkQualityEstimator::TestNetworkQualityEstimator(
+    std::unique_ptr<NetworkQualityEstimatorParams> params,
+    std::unique_ptr<BoundTestNetLog> net_log)
+    : NetworkQualityEstimator(std::unique_ptr<ExternalEstimateProvider>(),
+                              std::move(params),
+                              net_log->bound().net_log()),
+      current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
+      accuracy_recording_intervals_set_(false),
+      rand_double_(0.0),
+      embedded_test_server_(base::FilePath(kTestFilePath)),
+      suppress_notifications_for_testing_(false),
+      net_log_(std::move(net_log)) {
+  // Set up the embedded test server.
+  EXPECT_TRUE(embedded_test_server_.Start());
+}
+
 TestNetworkQualityEstimator::~TestNetworkQualityEstimator() {}
 
 void TestNetworkQualityEstimator::RunOneRequest() {
diff --git a/net/nqe/network_quality_estimator_test_util.h b/net/nqe/network_quality_estimator_test_util.h
index b536718..34a4e0e 100644
--- a/net/nqe/network_quality_estimator_test_util.h
+++ b/net/nqe/network_quality_estimator_test_util.h
@@ -60,6 +60,9 @@
       bool suppress_notifications_for_testing,
       std::unique_ptr<BoundTestNetLog> net_log);
 
+  explicit TestNetworkQualityEstimator(
+      std::unique_ptr<NetworkQualityEstimatorParams> params);
+
   ~TestNetworkQualityEstimator() override;
 
   // Runs one URL request to completion.
@@ -233,6 +236,10 @@
     explicit LocalHttpTestServer(const base::FilePath& document_root);
   };
 
+  TestNetworkQualityEstimator(
+      std::unique_ptr<NetworkQualityEstimatorParams> params,
+      std::unique_ptr<BoundTestNetLog> net_log);
+
   // NetworkQualityEstimator implementation that returns the overridden
   // network
   // id (instead of invoking platform APIs).
diff --git a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
index d0a8ae3f..153760e 100644
--- a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
+++ b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
@@ -17,6 +17,8 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.net.X509Util;
+import org.chromium.net.test.util.CertTestUtil;
 
 import java.io.File;
 
@@ -61,6 +63,12 @@
     private Context mContext;
     private final Object mImplMonitor = new Object();
 
+    // Whether the server should use HTTP or HTTPS.
+    public enum ServerHTTPSSetting {
+        USE_HTTP,
+        USE_HTTPS,
+    }
+
     /**
      * Exception class raised on failure in the EmbeddedTestServer.
      */
@@ -125,8 +133,10 @@
      *
      *  @param context The context to use to bind the service. This will also be used to unbind
      *          the service at server destruction time.
+     *  @param httpsSetting Whether the server should use HTTPS.
      */
-    public void initializeNative(Context context) throws InterruptedException {
+    public void initializeNative(Context context, ServerHTTPSSetting httpsSetting)
+            throws InterruptedException {
         mContext = context;
 
         Intent intent = new Intent(EMBEDDED_TEST_SERVER_SERVICE);
@@ -144,7 +154,7 @@
             Log.i(TAG, "EmbeddedTestServer service connected.");
             boolean initialized = false;
             try {
-                initialized = mImpl.initializeNative();
+                initialized = mImpl.initializeNative(httpsSetting == ServerHTTPSSetting.USE_HTTPS);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to initialize native server.", e);
                 initialized = false;
@@ -153,6 +163,16 @@
             if (!initialized) {
                 throw new EmbeddedTestServerFailure("Failed to initialize native server.");
             }
+
+            if (httpsSetting == ServerHTTPSSetting.USE_HTTPS) {
+                try {
+                    String rootCertPemPath = mImpl.getRootCertPemPath();
+                    X509Util.addTestRootCertificate(CertTestUtil.pemToDer(rootCertPemPath));
+                } catch (Exception e) {
+                    throw new EmbeddedTestServerFailure(
+                            "Failed to install root certificate from native server.", e);
+                }
+            }
         }
     }
 
@@ -194,6 +214,22 @@
         }
     }
 
+    /** Configure the server to use a particular type of SSL certificate.
+     *
+     * @param serverCertificate The type of certificate the server should use.
+     */
+    public void setSSLConfig(int serverCertificate) {
+        try {
+            synchronized (mImplMonitor) {
+                checkServiceLocked();
+                mImpl.setSSLConfig(serverCertificate);
+            }
+        } catch (RemoteException e) {
+            throw new EmbeddedTestServerFailure(
+                    "Failed to set server certificate: " + e.toString());
+        }
+    }
+
     /** Serve files from the provided directory.
      *
      *  @param directory The directory from which files should be served.
@@ -309,6 +345,25 @@
         return initializeAndStartServer(server, context);
     }
 
+    /** Create and initialize an HTTPS server with the default handlers.
+     *
+     *  This handles native object initialization, server configuration, and server initialization.
+     *  On returning, the server is ready for use.
+     *
+     *  @param context The context in which the server will run.
+     *  @param serverCertificate The certificate option that the server will use.
+     *  @return The created server.
+     */
+    public static EmbeddedTestServer createAndStartHTTPSServer(
+            Context context, int serverCertificate) throws InterruptedException {
+        Assert.assertNotEquals("EmbeddedTestServer should not be created on UiThread, "
+                        + "the instantiation will hang forever waiting for tasks"
+                        + " to post to UI thread",
+                Looper.getMainLooper(), Looper.myLooper());
+        EmbeddedTestServer server = new EmbeddedTestServer();
+        return initializeAndStartHTTPSServer(server, context, serverCertificate);
+    }
+
     /** Initialize a server with the default handlers.
      *
      *  This handles native object initialization, server configuration, and server initialization.
@@ -320,7 +375,7 @@
      */
     public static <T extends EmbeddedTestServer> T initializeAndStartServer(
             T server, Context context) throws InterruptedException {
-        server.initializeNative(context);
+        server.initializeNative(context, ServerHTTPSSetting.USE_HTTP);
         server.addDefaultHandlers("");
         if (!server.start()) {
             throw new EmbeddedTestServerFailure("Failed to start serving using default handlers.");
@@ -328,6 +383,28 @@
         return server;
     }
 
+    /** Initialize a server with the default handlers that uses HTTPS with the given certificate
+     * option.
+     *
+     *  This handles native object initialization, server configuration, and server initialization.
+     *  On returning, the server is ready for use.
+     *
+     *  @param server The server instance that will be initialized.
+     *  @param context The context in which the server will run.
+     *  @param serverCertificate The certificate option that the server will use.
+     *  @return The created server.
+     */
+    public static <T extends EmbeddedTestServer> T initializeAndStartHTTPSServer(
+            T server, Context context, int serverCertificate) throws InterruptedException {
+        server.initializeNative(context, ServerHTTPSSetting.USE_HTTPS);
+        server.addDefaultHandlers("");
+        server.setSSLConfig(serverCertificate);
+        if (!server.start()) {
+            throw new EmbeddedTestServerFailure("Failed to start serving using default handlers.");
+        }
+        return server;
+    }
+
     /** Get the full URL for the given relative URL.
      *
      *  @param relativeUrl The relative URL for which a full URL will be obtained.
diff --git a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerImpl.java b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerImpl.java
index 6455fb2..cbe092d 100644
--- a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerImpl.java
+++ b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerImpl.java
@@ -61,10 +61,11 @@
 
     /** Initialize the native EmbeddedTestServer object.
      *
+     *  @param https True if the server should use HTTPS, and false otherwise.
      *  @return Whether the native object was successfully initialized.
      */
     @Override
-    public boolean initializeNative() {
+    public boolean initializeNative(final boolean https) {
         // This is necessary as EmbeddedTestServerImpl is in a different process than the tests
         // using it, so it needs to initialize its own application context.
         ContextUtils.initApplicationContext(mContext.getApplicationContext());
@@ -82,7 +83,9 @@
         runOnHandlerThread(new Callable<Void>() {
             @Override
             public Void call() {
-                if (mNativeEmbeddedTestServer == 0) nativeInit(UrlUtils.getIsolatedTestRoot());
+                if (mNativeEmbeddedTestServer == 0) {
+                    nativeInit(UrlUtils.getIsolatedTestRoot(), https);
+                }
                 assert mNativeEmbeddedTestServer != 0;
                 return null;
             }
@@ -107,6 +110,20 @@
         });
     }
 
+    /** Returns the path to a PEM file containing the server's root certificate.
+     *
+     *  @return The path to a PEM file containing the server's root certificate.
+     */
+    @Override
+    public String getRootCertPemPath() {
+        return runOnHandlerThread(new Callable<String>() {
+            @Override
+            public String call() {
+                return nativeGetRootCertPemPath(mNativeEmbeddedTestServer);
+            }
+        });
+    }
+
     /** Add the default handlers and serve files from the provided directory relative to the
      *  external storage directory.
      *
@@ -124,6 +141,21 @@
         });
     }
 
+    /** Configure the server to use a particular type of SSL certificate.
+     *
+     * @param serverCertificate The type of certificate the server should use.
+     */
+    @Override
+    public void setSSLConfig(final int serverCertificate) {
+        runOnHandlerThread(new Callable<Void>() {
+            @Override
+            public Void call() {
+                nativeSetSSLConfig(mNativeEmbeddedTestServer, serverCertificate);
+                return null;
+            }
+        });
+    }
+
     /** Register multiple request handlers.
      *  Handlers must be registered before starting the server.
      *
@@ -263,12 +295,15 @@
         mNativeEmbeddedTestServer = 0;
     }
 
-    private native void nativeInit(String testDataDir);
+    private native void nativeInit(String testDataDir, boolean https);
     private native void nativeDestroy(long nativeEmbeddedTestServerAndroid);
     private native boolean nativeStart(long nativeEmbeddedTestServerAndroid);
+    private native String nativeGetRootCertPemPath(long nativeEmbeddedTestServerAndroid);
     private native boolean nativeShutdownAndWaitUntilComplete(long nativeEmbeddedTestServerAndroid);
     private native void nativeAddDefaultHandlers(
             long nativeEmbeddedTestServerAndroid, String directoryPath);
+    private native void nativeSetSSLConfig(
+            long nativeEmbeddedTestServerAndroid, int serverCertificate);
     private native void nativeRegisterRequestHandler(
             long nativeEmbeddedTestServerAndroid, long handler);
     private native String nativeGetURL(long nativeEmbeddedTestServerAndroid, String relativeUrl);
diff --git a/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl b/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl
index 707c3f7a..7a6e2031 100644
--- a/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl
+++ b/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl
@@ -9,7 +9,7 @@
 interface IEmbeddedTestServerImpl {
 
     /** Initialize the native object. */
-    boolean initializeNative();
+    boolean initializeNative(boolean https);
 
     /** Start the server.
      *
@@ -17,6 +17,12 @@
      */
     boolean start();
 
+    /** Get the path of the server's root certificate.
+     *
+     *  @return The pathname of a PEM file containing the server's root certificate.
+     */
+    String getRootCertPemPath();
+
     /** Add the default handlers and serve files from the provided directory relative to the
      *  external storage directory.
      *
@@ -25,6 +31,12 @@
      */
     void addDefaultHandlers(String directoryPath);
 
+    /** Configure the server to use a particular type of SSL certificate.
+     *
+     * @param serverCertificate The type of certificate the server should use.
+     */
+    void setSSLConfig(int serverCertificate);
+
     /** Serve files from the provided directory.
      *
      *  @param directoryPath The path of the directory from which files should be served.
diff --git a/net/test/embedded_test_server/android/embedded_test_server_android.cc b/net/test/embedded_test_server/android/embedded_test_server_android.cc
index 7c82de5..a9c38cb 100644
--- a/net/test/embedded_test_server/android/embedded_test_server_android.cc
+++ b/net/test/embedded_test_server/android/embedded_test_server_android.cc
@@ -39,8 +39,12 @@
 
 EmbeddedTestServerAndroid::EmbeddedTestServerAndroid(
     JNIEnv* env,
-    const JavaRef<jobject>& jobj)
-    : weak_java_server_(env, jobj), test_server_(), connection_listener_(this) {
+    const JavaRef<jobject>& jobj,
+    jboolean jhttps)
+    : weak_java_server_(env, jobj),
+      test_server_(jhttps ? EmbeddedTestServer::TYPE_HTTPS
+                          : EmbeddedTestServer::TYPE_HTTP),
+      connection_listener_(this) {
   test_server_.SetConnectionListener(&connection_listener_);
   Java_EmbeddedTestServerImpl_setNativePtr(env, jobj,
                                            reinterpret_cast<intptr_t>(this));
@@ -56,6 +60,13 @@
   return test_server_.Start();
 }
 
+ScopedJavaLocalRef<jstring> EmbeddedTestServerAndroid::GetRootCertPemPath(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jobj) const {
+  return base::android::ConvertUTF8ToJavaString(
+      env, test_server_.GetRootCertPemPath().value());
+}
+
 jboolean EmbeddedTestServerAndroid::ShutdownAndWaitUntilComplete(
     JNIEnv* env,
     const JavaParamRef<jobject>& jobj) {
@@ -80,6 +91,13 @@
   test_server_.AddDefaultHandlers(directory);
 }
 
+void EmbeddedTestServerAndroid::SetSSLConfig(JNIEnv* jenv,
+                                             const JavaParamRef<jobject>& jobj,
+                                             jint jserver_certificate) {
+  test_server_.SetSSLConfig(
+      static_cast<EmbeddedTestServer::ServerCertificate>(jserver_certificate));
+}
+
 typedef std::unique_ptr<HttpResponse> (*HandleRequestPtr)(
     const HttpRequest& request);
 
@@ -119,12 +137,13 @@
 
 static void Init(JNIEnv* env,
                  const JavaParamRef<jobject>& jobj,
-                 const JavaParamRef<jstring>& jtest_data_dir) {
+                 const JavaParamRef<jstring>& jtest_data_dir,
+                 jboolean jhttps) {
   TRACE_EVENT0("native", "EmbeddedTestServerAndroid::Init");
   base::FilePath test_data_dir(
       base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
   base::InitAndroidTestPaths(test_data_dir);
-  new EmbeddedTestServerAndroid(env, jobj);
+  new EmbeddedTestServerAndroid(env, jobj, jhttps);
 }
 
 // static
diff --git a/net/test/embedded_test_server/android/embedded_test_server_android.h b/net/test/embedded_test_server/android/embedded_test_server_android.h
index bc993c9..ea679940 100644
--- a/net/test/embedded_test_server/android/embedded_test_server_android.h
+++ b/net/test/embedded_test_server/android/embedded_test_server_android.h
@@ -22,13 +22,18 @@
 class EmbeddedTestServerAndroid {
  public:
   EmbeddedTestServerAndroid(JNIEnv* env,
-                            const base::android::JavaRef<jobject>& obj);
+                            const base::android::JavaRef<jobject>& obj,
+                            jboolean jhttps);
   ~EmbeddedTestServerAndroid();
 
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
   jboolean Start(JNIEnv* env, const base::android::JavaParamRef<jobject>& jobj);
 
+  base::android::ScopedJavaLocalRef<jstring> GetRootCertPemPath(
+      JNIEnv* jenv,
+      const base::android::JavaParamRef<jobject>& jobj) const;
+
   jboolean ShutdownAndWaitUntilComplete(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jobj);
@@ -43,6 +48,10 @@
       const base::android::JavaParamRef<jobject>& jobj,
       const base::android::JavaParamRef<jstring>& jdirectory_path);
 
+  void SetSSLConfig(JNIEnv* jenv,
+                    const base::android::JavaParamRef<jobject>& jobj,
+                    jint jserver_certificate);
+
   void RegisterRequestHandler(JNIEnv* jenv,
                               const base::android::JavaParamRef<jobject>& jobj,
                               jlong handler);
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 83112a2..78e182f8 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -53,12 +53,13 @@
       weak_factory_(this) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (is_using_ssl_) {
-    base::ThreadRestrictions::ScopedAllowIO allow_io_for_importing_test_cert;
-    TestRootCerts* root_certs = TestRootCerts::GetInstance();
-    base::FilePath certs_dir(GetTestCertsDirectory());
-    root_certs->AddFromFile(certs_dir.AppendASCII("root_ca_cert.pem"));
-  }
+  if (!is_using_ssl_)
+    return;
+  base::ThreadRestrictions::ScopedAllowIO allow_io_for_importing_test_cert;
+  TestRootCerts* root_certs = TestRootCerts::GetInstance();
+  bool added_root_certs = root_certs->AddFromFile(GetRootCertPemPath());
+  DCHECK(added_root_certs)
+      << "Failed to install root cert from EmbeddedTestServer";
 }
 
 EmbeddedTestServer::~EmbeddedTestServer() {
@@ -184,6 +185,11 @@
       &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this)));
 }
 
+// static
+base::FilePath EmbeddedTestServer::GetRootCertPemPath() {
+  return GetTestCertsDirectory().AppendASCII("root_ca_cert.pem");
+}
+
 void EmbeddedTestServer::ShutdownOnIOThread() {
   DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
   weak_factory_.InvalidateWeakPtrs();
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h
index f2a9307..dbcf508 100644
--- a/net/test/embedded_test_server/embedded_test_server.h
+++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -92,6 +92,8 @@
     TYPE_HTTPS,
   };
 
+  // A Java counterpart will be generated for this enum.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net.test
   enum ServerCertificate {
     CERT_OK,
 
@@ -151,6 +153,8 @@
     return listen_socket_.get() != NULL;
   }
 
+  static base::FilePath GetRootCertPemPath();
+
   HostPortPair host_port_pair() const {
     return HostPortPair::FromURL(base_url_);
   }
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 3652fd2d..96a5b12 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -639,6 +639,10 @@
   return false;
 }
 
+bool IsLinkArea(PDFiumPage::Area area) {
+  return area == PDFiumPage::WEBLINK_AREA || area == PDFiumPage::DOCLINK_AREA;
+}
+
 }  // namespace
 
 bool InitializeSDK() {
@@ -1738,28 +1742,50 @@
 }
 
 bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) {
-  if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT) {
-    if (selection_.empty())
-      return false;
-    std::vector<pp::Rect> selection_rect_vector;
-    GetAllScreenRectsUnion(&selection_, GetVisibleRect().point(),
-                           &selection_rect_vector);
-    pp::Point point = event.GetPosition();
-    for (const auto& rect : selection_rect_vector) {
-      if (rect.Contains(point.x(), point.y()))
-        return false;
-    }
-    SelectionChangeInvalidator selection_invalidator(this);
-    selection_.clear();
-    return true;
+  if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
+    return OnLeftMouseDown(event);
+  if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
+    return OnMiddleMouseDown(event);
+  if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT)
+    return OnRightMouseDown(event);
+  return false;
+}
+
+void PDFiumEngine::OnSingleClick(int page_index, int char_index) {
+  SetSelecting(true);
+  selection_.push_back(PDFiumRange(pages_[page_index].get(), char_index, 0));
+}
+
+void PDFiumEngine::OnMultipleClick(int click_count,
+                                   int page_index,
+                                   int char_index) {
+  // It would be more efficient if the SDK could support finding a space, but
+  // now it doesn't.
+  int start_index = char_index;
+  do {
+    base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index);
+    // For double click, we want to select one word so we look for whitespace
+    // boundaries.  For triple click, we want the whole line.
+    if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))
+      break;
+  } while (--start_index >= 0);
+  if (start_index)
+    start_index++;
+
+  int end_index = char_index;
+  int total = pages_[page_index]->GetCharCount();
+  while (end_index++ <= total) {
+    base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index);
+    if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))
+      break;
   }
 
-  if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
-      event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) {
-    return false;
-  }
+  selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
+                                   end_index - start_index));
+}
 
-  SetMouseLeftButtonDown(event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT);
+bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
+  SetMouseLeftButtonDown(true);
 
   auto selection_invalidator =
       base::MakeUnique<SelectionChangeInvalidator>(this);
@@ -1777,13 +1803,9 @@
 
   // Decide whether to open link or not based on user action in mouse up and
   // mouse move events.
-  if (area == PDFiumPage::WEBLINK_AREA || area == PDFiumPage::DOCLINK_AREA)
+  if (IsLinkArea(area))
     return true;
 
-  // Prevent middle mouse button from selecting texts.
-  if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
-    return false;
-
   if (page_index != -1) {
     last_page_mouse_down_ = page_index;
     double page_x;
@@ -1838,37 +1860,47 @@
   return true;
 }
 
-void PDFiumEngine::OnSingleClick(int page_index, int char_index) {
-  SetSelecting(true);
-  selection_.push_back(PDFiumRange(pages_[page_index].get(), char_index, 0));
+bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) {
+  SetMouseLeftButtonDown(false);
+
+  SelectionChangeInvalidator selection_invalidator(this);
+  selection_.clear();
+
+  int unused_page_index = -1;
+  int unused_char_index = -1;
+  int unused_form_type = FPDF_FORMFIELD_UNKNOWN;
+  PDFiumPage::LinkTarget target;
+  PDFiumPage::Area area =
+      GetCharIndex(event.GetPosition(), &unused_page_index, &unused_char_index,
+                   &unused_form_type, &target);
+  mouse_down_state_.Set(area, target);
+
+  // Decide whether to open link or not based on user action in mouse up and
+  // mouse move events.
+  if (IsLinkArea(area))
+    return true;
+
+  // Prevent middle mouse button from selecting texts.
+  return false;
 }
 
-void PDFiumEngine::OnMultipleClick(int click_count,
-                                   int page_index,
-                                   int char_index) {
-  // It would be more efficient if the SDK could support finding a space, but
-  // now it doesn't.
-  int start_index = char_index;
-  do {
-    base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index);
-    // For double click, we want to select one word so we look for whitespace
-    // boundaries.  For triple click, we want the whole line.
-    if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))
-      break;
-  } while (--start_index >= 0);
-  if (start_index)
-    start_index++;
+bool PDFiumEngine::OnRightMouseDown(const pp::MouseInputEvent& event) {
+  DCHECK_EQ(PP_INPUTEVENT_MOUSEBUTTON_RIGHT, event.GetButton());
 
-  int end_index = char_index;
-  int total = pages_[page_index]->GetCharCount();
-  while (end_index++ <= total) {
-    base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index);
-    if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))
-      break;
+  if (selection_.empty())
+    return false;
+
+  std::vector<pp::Rect> selection_rect_vector;
+  GetAllScreenRectsUnion(&selection_, GetVisibleRect().point(),
+                         &selection_rect_vector);
+  pp::Point point = event.GetPosition();
+  for (const auto& rect : selection_rect_vector) {
+    if (rect.Contains(point.x(), point.y()))
+      return false;
   }
-
-  selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
-                                   end_index - start_index));
+  SelectionChangeInvalidator selection_invalidator(this);
+  selection_.clear();
+  return true;
 }
 
 bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) {
@@ -2004,10 +2036,8 @@
 
   // We're selecting but right now we're not over text, so don't change the
   // current selection.
-  if (area != PDFiumPage::TEXT_AREA && area != PDFiumPage::WEBLINK_AREA &&
-      area != PDFiumPage::DOCLINK_AREA) {
+  if (area != PDFiumPage::TEXT_AREA && !IsLinkArea(area))
     return false;
-  }
 
   SelectionChangeInvalidator selection_invalidator(this);
   return ExtendSelection(page_index, char_index);
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 7dd2cee..fc3dd35 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -349,6 +349,9 @@
 
   void OnSingleClick(int page_index, int char_index);
   void OnMultipleClick(int click_count, int page_index, int char_index);
+  bool OnLeftMouseDown(const pp::MouseInputEvent& event);
+  bool OnMiddleMouseDown(const pp::MouseInputEvent& event);
+  bool OnRightMouseDown(const pp::MouseInputEvent& event);
 
   // Starts a progressive paint operation given a rectangle in screen
   // coordinates. Returns the index in progressive_rects_.
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 91b56566..681c2fb 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -18,7 +18,6 @@
 #include "cc/ipc/selection_struct_traits.h"
 #include "cc/ipc/shared_quad_state_struct_traits.h"
 #include "cc/ipc/surface_id_struct_traits.h"
-#include "cc/ipc/surface_sequence_struct_traits.h"
 #include "cc/ipc/texture_mailbox_struct_traits.h"
 #include "cc/ipc/transferable_resource_struct_traits.h"
 #include "cc/output/compositor_frame.h"
@@ -42,9 +41,11 @@
 #include "services/viz/public/cpp/compositing/resource_settings_struct_traits.h"
 #include "services/viz/public/cpp/compositing/returned_resource_struct_traits.h"
 #include "services/viz/public/cpp/compositing/surface_info_struct_traits.h"
+#include "services/viz/public/cpp/compositing/surface_sequence_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
 #include "services/viz/public/interfaces/compositing/returned_resource.mojom.h"
 #include "services/viz/public/interfaces/compositing/surface_info.mojom.h"
+#include "services/viz/public/interfaces/compositing/surface_sequence.mojom.h"
 #include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
 #include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
 #include "skia/public/interfaces/image_filter_struct_traits.h"
@@ -98,6 +99,19 @@
             output.buffer_to_texture_target_map);
 }
 
+TEST_F(StructTraitsTest, SurfaceSequence) {
+  const FrameSinkId frame_sink_id(2016, 1234);
+  const uint32_t sequence = 0xfbadbeef;
+
+  SurfaceSequence input(frame_sink_id, sequence);
+  SurfaceSequence output;
+  mojom::SurfaceSequence::Deserialize(mojom::SurfaceSequence::Serialize(&input),
+                                      &output);
+
+  EXPECT_EQ(frame_sink_id, output.frame_sink_id);
+  EXPECT_EQ(sequence, output.sequence);
+}
+
 // Note that this is a fairly trivial test of CompositorFrame serialization as
 // most of the heavy lifting has already been done by CompositorFrameMetadata,
 // RenderPass, and QuadListBasic unit tests.
diff --git a/services/viz/public/cpp/compositing/surface_sequence.typemap b/services/viz/public/cpp/compositing/surface_sequence.typemap
new file mode 100644
index 0000000..b2377ba
--- /dev/null
+++ b/services/viz/public/cpp/compositing/surface_sequence.typemap
@@ -0,0 +1,12 @@
+# 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.
+
+mojom = "//services/viz/public/interfaces/compositing/surface_sequence.mojom"
+public_headers = [ "//components/viz/common/surfaces/surface_sequence.h" ]
+traits_headers =
+    [ "//services/viz/public/cpp/compositing/surface_sequence_struct_traits.h" ]
+deps = [
+  "//components/viz/common",
+]
+type_mappings = [ "viz.mojom.SurfaceSequence=viz::SurfaceSequence" ]
diff --git a/cc/ipc/surface_sequence_struct_traits.h b/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
similarity index 60%
rename from cc/ipc/surface_sequence_struct_traits.h
rename to services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
index ead28b37..24563cb02 100644
--- a/cc/ipc/surface_sequence_struct_traits.h
+++ b/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_IPC_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
-#define CC_IPC_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
+#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
 
-#include "cc/ipc/surface_sequence.mojom-shared.h"
 #include "components/viz/common/surfaces/surface_sequence.h"
+#include "services/viz/public/interfaces/compositing/surface_sequence.mojom-shared.h"
 
 namespace mojo {
 
 template <>
-struct StructTraits<cc::mojom::SurfaceSequenceDataView, viz::SurfaceSequence> {
+struct StructTraits<viz::mojom::SurfaceSequenceDataView, viz::SurfaceSequence> {
   static const viz::FrameSinkId& frame_sink_id(const viz::SurfaceSequence& id) {
     return id.frame_sink_id;
   }
@@ -20,7 +20,7 @@
     return id.sequence;
   }
 
-  static bool Read(cc::mojom::SurfaceSequenceDataView data,
+  static bool Read(viz::mojom::SurfaceSequenceDataView data,
                    viz::SurfaceSequence* out) {
     viz::FrameSinkId frame_sink_id;
     if (!data.ReadFrameSinkId(&frame_sink_id))
@@ -32,4 +32,4 @@
 
 }  // namespace mojo
 
-#endif  // CC_IPC_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/typemaps.gni b/services/viz/public/cpp/compositing/typemaps.gni
index db606faf..e287bc7 100644
--- a/services/viz/public/cpp/compositing/typemaps.gni
+++ b/services/viz/public/cpp/compositing/typemaps.gni
@@ -6,5 +6,6 @@
   "//services/viz/public/cpp/compositing/compositor_frame.typemap",
   "//services/viz/public/cpp/compositing/resource_settings.typemap",
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
+  "//services/viz/public/cpp/compositing/surface_sequence.typemap",
   "//services/viz/public/cpp/compositing/surface_info.typemap",
 ]
diff --git a/services/viz/public/interfaces/compositing/BUILD.gn b/services/viz/public/interfaces/compositing/BUILD.gn
index 4f10daa0..3ca8344a 100644
--- a/services/viz/public/interfaces/compositing/BUILD.gn
+++ b/services/viz/public/interfaces/compositing/BUILD.gn
@@ -11,6 +11,7 @@
     "resource_settings.mojom",
     "returned_resource.mojom",
     "surface_info.mojom",
+    "surface_sequence.mojom",
   ]
 
   public_deps = [
diff --git a/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom b/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
index 2951b77..fde38d4f 100644
--- a/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
+++ b/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
@@ -9,7 +9,6 @@
 import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
 import "cc/ipc/surface_id.mojom";
-import "cc/ipc/surface_sequence.mojom";
 import "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom";
 import "services/viz/public/interfaces/compositing/compositor_frame.mojom";
 import "services/viz/public/interfaces/compositing/returned_resource.mojom";
diff --git a/cc/ipc/surface_sequence.mojom b/services/viz/public/interfaces/compositing/surface_sequence.mojom
similarity index 87%
rename from cc/ipc/surface_sequence.mojom
rename to services/viz/public/interfaces/compositing/surface_sequence.mojom
index ba02ee5..d23159f 100644
--- a/cc/ipc/surface_sequence.mojom
+++ b/services/viz/public/interfaces/compositing/surface_sequence.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
 import "cc/ipc/frame_sink_id.mojom";
 
@@ -10,7 +10,6 @@
 // dependencies between frames. A sequence number may be satisfied once, and
 // may be depended on once.
 struct SurfaceSequence {
-  FrameSinkId frame_sink_id;
+  cc.mojom.FrameSinkId frame_sink_id;
   uint32 sequence;
 };
- 
diff --git a/testing/buildbot/filters/fuchsia.base_unittests.filter b/testing/buildbot/filters/fuchsia.base_unittests.filter
index 3af890a..9fb4b64 100644
--- a/testing/buildbot/filters/fuchsia.base_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.base_unittests.filter
@@ -25,6 +25,16 @@
 -ProcessMemoryDumpTest.CountResidentBytes
 -ProcessMemoryDumpTest.CountResidentBytesInSharedMemory
 -ProcessMemoryDumpTest.TakeAllDumpsFrom
+-SysInfoTest.AmountOfFreeDiskSpace
+-SysInfoTest.AmountOfMem
+-SysInfoTest.AmountOfTotalDiskSpace
+
+# CancelableSyncSocket tests fail: https://crbug.com/741783
+-CancelableSyncSocket*
+
+# These tests all rely on being able to set the exit code of an externally
+# terminated process, which mx_task_kill() does not support.
+# https://crbug.com/753490.
 -ProcessTest.Terminate
 -ProcessTest.TerminateCurrentProcessImmediatelyWithNonZeroExitCode
 -ProcessTest.TerminateCurrentProcessImmediatelyWithZeroExitCode
@@ -32,12 +42,6 @@
 -ProcessUtilTest.GetTerminationStatusCrash
 -ProcessUtilTest.GetTerminationStatusSigKill
 -ProcessUtilTest.GetTerminationStatusSigTerm
--SysInfoTest.AmountOfFreeDiskSpace
--SysInfoTest.AmountOfMem
--SysInfoTest.AmountOfTotalDiskSpace
-
-# CancelableSyncSocket tests fail: https://crbug.com/741783
--CancelableSyncSocket*
 
 # These tests are occasionally flaking. See https://crbug.com/738275. Please be
 # pretty confident you've fixed their rarely-flakiness before re-enabling.
diff --git a/testing/buildbot/filters/fuchsia.ui_base_unittests.filter b/testing/buildbot/filters/fuchsia.ui_base_unittests.filter
index 9ff1f700..5e608d4 100644
--- a/testing/buildbot/filters/fuchsia.ui_base_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.ui_base_unittests.filter
@@ -5,6 +5,9 @@
 -*DataPackTest.*
 -ResourceBundleImageTest.*
 
+# Failing after turning on Ozone/Aura. We probably don't have any need for this.
+-OSExchangeDataTest.*
+
 # Flaking, see https://crbug.com/752220.
 -ClipboardTest/0.ClearTest
 -L10nUtilTest.TimeDurationFormatAllLocales
diff --git a/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html b/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html
index b02ba400..d0f00058 100644
--- a/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html
+++ b/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html
@@ -56,6 +56,14 @@
     assert_less_than_equal(navigator.mimeTypes[i-1].type.localeCompare(navigator.mimeTypes[i].type), 0);
   }
 }, "Tests that navigator.plugins returns plugins sorted in alphabetical order by plugin name.");
+
+test(function() {
+  assert_greater_than_equal(navigator.plugins.length, 1, "At least one plugin must be available.");
+  assert_greater_than_equal(navigator.mimeTypes.length, 1, "At least one mime type must be available.");
+  assert_equals(null, navigator.plugins.item(navigator.plugins.length));
+  assert_equals(null, navigator.mimeTypes.item(navigator.mimeTypes.length));
+  assert_equals(null, navigator.plugins[0].item(navigator.plugins[0].length));
+}, "Tests out-of-bounds access in navigator.plugins");
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/huge-buffer.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/huge-buffer.html
new file mode 100644
index 0000000..c9d8eed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/huge-buffer.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>
+      Test Creation of Huge AudioBuffer
+    </title>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit.js"></script>
+  </head>
+  <body>
+    <script id="layout-test-code">
+      let audit = Audit.createTaskRunner();
+
+      audit.define('huge buffer', (task, should) => {
+        // Set options to try to allocate a huge amount of memory in an
+        // AudioBuffer. This should fail gracefully with an error instead of
+        // crashing with an OOM error.
+        let options = {
+          numberOfChannels: 32,
+          length: 1 << 30,
+          sampleRate: 16000
+        };
+        should(
+            () => new AudioBuffer(options),
+            'new AudioBuffer(' + JSON.stringify(options) + ')')
+            .throw('NotSupportedError');
+        task.done();
+      });
+
+      audit.run();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp b/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp
index 4a16fb18..cc00c3ba 100644
--- a/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp
+++ b/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp
@@ -20,12 +20,15 @@
 
 namespace blink {
 
-OffscreenFontSelector::OffscreenFontSelector(
-    const GenericFontFamilySettings& settings)
-    : generic_font_family_settings_(settings) {}
+OffscreenFontSelector::OffscreenFontSelector() {}
 
 OffscreenFontSelector::~OffscreenFontSelector() {}
 
+void OffscreenFontSelector::UpdateGenericFontFamilySettings(
+    const GenericFontFamilySettings& settings) {
+  generic_font_family_settings_ = settings;
+}
+
 void OffscreenFontSelector::RegisterForInvalidationCallbacks(
     FontSelectorClient* client) {}
 
diff --git a/third_party/WebKit/Source/core/css/OffscreenFontSelector.h b/third_party/WebKit/Source/core/css/OffscreenFontSelector.h
index 494e33e..0a5897e 100644
--- a/third_party/WebKit/Source/core/css/OffscreenFontSelector.h
+++ b/third_party/WebKit/Source/core/css/OffscreenFontSelector.h
@@ -20,10 +20,7 @@
 
 class CORE_EXPORT OffscreenFontSelector : public FontSelector {
  public:
-  static OffscreenFontSelector* Create(
-      const GenericFontFamilySettings& settings) {
-    return new OffscreenFontSelector(settings);
-  }
+  static OffscreenFontSelector* Create() { return new OffscreenFontSelector(); }
   ~OffscreenFontSelector() override;
 
   unsigned Version() const override { return 1; }
@@ -48,15 +45,17 @@
 
   void FontCacheInvalidated() override;
 
+  void UpdateGenericFontFamilySettings(const GenericFontFamilySettings&);
+
   DECLARE_VIRTUAL_TRACE();
 
  protected:
-  explicit OffscreenFontSelector(const GenericFontFamilySettings&);
+  explicit OffscreenFontSelector();
 
   void DispatchInvalidationCallbacks();
 
  private:
-  const GenericFontFamilySettings generic_font_family_settings_;
+  GenericFontFamilySettings generic_font_family_settings_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebViewTest.cpp b/third_party/WebKit/Source/core/exported/WebViewTest.cpp
index 42724c9..af31524 100644
--- a/third_party/WebKit/Source/core/exported/WebViewTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebViewTest.cpp
@@ -246,6 +246,10 @@
   }
 
  protected:
+  void SetViewportSize(const WebSize& size) {
+    web_view_helper_.SetViewportSize(size);
+  }
+
   std::string RegisterMockedHttpURLLoad(const std::string& file_name) {
     return URLTestHelpers::RegisterMockedURLLoadFromBase(
                WebString::FromUTF8(base_url_), testing::CoreTestDataPath(),
@@ -4598,7 +4602,7 @@
   WebViewImpl* web_view_impl =
       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
   web_view_impl->Resize(WebSize(100, 150));
-  web_view_impl->LayerTreeView()->SetViewportSize(WebSize(100, 150));
+  SetViewportSize(WebSize(100, 150));
   VisualViewport* visual_viewport =
       &web_view_impl->GetPage()->GetVisualViewport();
   DevToolsEmulator* dev_tools_emulator = web_view_impl->GetDevToolsEmulator();
@@ -4673,7 +4677,7 @@
   WebViewImpl* web_view_impl =
       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
   web_view_impl->Resize(WebSize(100, 150));
-  web_view_impl->LayerTreeView()->SetViewportSize(WebSize(100, 150));
+  SetViewportSize(WebSize(100, 150));
   LocalFrameView* frame_view =
       web_view_impl->MainFrameImpl()->GetFrame()->View();
   DevToolsEmulator* dev_tools_emulator = web_view_impl->GetDevToolsEmulator();
diff --git a/third_party/WebKit/Source/core/frame/FrameTestHelpers.cpp b/third_party/WebKit/Source/core/frame/FrameTestHelpers.cpp
index 3f9593a..a031b5d 100644
--- a/third_party/WebKit/Source/core/frame/FrameTestHelpers.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameTestHelpers.cpp
@@ -36,7 +36,6 @@
 #include "core/frame/WebLocalFrameImpl.h"
 #include "platform/testing/URLTestHelpers.h"
 #include "platform/testing/UnitTestHelpers.h"
-#include "platform/testing/WebLayerTreeViewImplForTesting.h"
 #include "platform/wtf/Functional.h"
 #include "platform/wtf/PtrUtil.h"
 #include "platform/wtf/StdLibExtras.h"
@@ -333,6 +332,11 @@
   return ToWebRemoteFrameImpl(web_view_->MainFrame());
 }
 
+void WebViewHelper::SetViewportSize(const WebSize& viewport_size) {
+  test_web_view_client_->GetLayerTreeViewForTesting()->SetViewportSize(
+      viewport_size);
+}
+
 void WebViewHelper::Resize(WebSize size) {
   test_web_view_client_->ClearAnimationScheduled();
   WebView()->Resize(size);
@@ -425,6 +429,11 @@
   self_owned_.reset();
 }
 
+WebLayerTreeViewImplForTesting*
+TestWebViewClient::GetLayerTreeViewForTesting() {
+  return layer_tree_view_.get();
+}
+
 WebLayerTreeView* TestWebViewClient::InitializeLayerTreeView() {
   layer_tree_view_ = WTF::MakeUnique<WebLayerTreeViewImplForTesting>();
   return layer_tree_view_.get();
diff --git a/third_party/WebKit/Source/core/frame/FrameTestHelpers.h b/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
index e9011df38..0b9a0ec 100644
--- a/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
+++ b/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
@@ -40,6 +40,7 @@
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/scroll/ScrollbarTheme.h"
+#include "platform/testing/WebLayerTreeViewImplForTesting.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebCachePolicy.h"
 #include "public/platform/WebMouseEvent.h"
@@ -258,6 +259,8 @@
  public:
   ~TestWebViewClient() override {}
 
+  WebLayerTreeViewImplForTesting* GetLayerTreeViewForTesting();
+
   // WebViewClient:
   WebLayerTreeView* InitializeLayerTreeView() override;
   void ScheduleAnimation() override { animation_scheduled_ = true; }
@@ -269,7 +272,7 @@
  private:
   friend class TestWebViewWidgetClient;
 
-  std::unique_ptr<WebLayerTreeView> layer_tree_view_;
+  std::unique_ptr<WebLayerTreeViewImplForTesting> layer_tree_view_;
   bool animation_scheduled_ = false;
 };
 
@@ -327,6 +330,8 @@
   WebLocalFrameImpl* LocalMainFrame() const;
   WebRemoteFrameImpl* RemoteMainFrame() const;
 
+  void SetViewportSize(const WebSize&);
+
  private:
   void InitializeWebView(TestWebViewClient*);
 
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 1a62583..0af7065 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -37,10 +37,12 @@
 #include "build/build_config.h"
 #include "core/HTMLNames.h"
 #include "core/InputTypeNames.h"
+#include "core/css/CSSFontSelector.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "core/dom/ElementTraversal.h"
 #include "core/dom/ExceptionCode.h"
+#include "core/dom/StyleEngine.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/fileapi/File.h"
 #include "core/frame/LocalFrame.h"
@@ -1465,4 +1467,8 @@
   SetNeedsCompositingUpdate();
 }
 
+FontSelector* HTMLCanvasElement::GetFontSelector() {
+  return GetDocument().GetStyleEngine().GetFontSelector();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index cf6bac6a..aabbe4c6 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -165,6 +165,8 @@
   ImageBuffer* GetImageBuffer() const override { return image_buffer_.get(); }
   ImageBuffer* GetOrCreateImageBuffer() override;
 
+  FontSelector* GetFontSelector() override;
+
   bool ShouldBeDirectComposited() const;
 
   void PrepareSurfaceForPaintingIfNeeded();
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextHost.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextHost.h
index bef3cdd7..d942035 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextHost.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextHost.h
@@ -18,6 +18,7 @@
 
 namespace blink {
 
+class FontSelector;
 class StaticBitmapImage;
 class KURL;
 
@@ -52,6 +53,8 @@
 
   virtual bool IsWebGLAllowed() const = 0;
 
+  virtual FontSelector* GetFontSelector() = 0;
+
   // TODO(fserb): remove this.
   virtual bool IsOffscreenCanvas() const { return false; }
 
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index f8f0f8c..8afad95 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -5,8 +5,11 @@
 #include "core/offscreencanvas/OffscreenCanvas.h"
 
 #include <memory>
+#include "core/css/CSSFontSelector.h"
+#include "core/css/OffscreenFontSelector.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/dom/StyleEngine.h"
 #include "core/fileapi/Blob.h"
 #include "core/html/ImageData.h"
 #include "core/html/canvas/CanvasAsyncBlobCreator.h"
@@ -14,6 +17,7 @@
 #include "core/html/canvas/CanvasRenderingContext.h"
 #include "core/html/canvas/CanvasRenderingContextFactory.h"
 #include "core/imagebitmap/ImageBitmap.h"
+#include "core/workers/WorkerGlobalScope.h"
 #include "platform/graphics/Image.h"
 #include "platform/graphics/ImageBuffer.h"
 #include "platform/graphics/OffscreenCanvasFrameDispatcherImpl.h"
@@ -408,6 +412,13 @@
   return resolver->Promise();
 }
 
+FontSelector* OffscreenCanvas::GetFontSelector() {
+  if (GetExecutionContext()->IsDocument()) {
+    return ToDocument(execution_context_)->GetStyleEngine().GetFontSelector();
+  }
+  return ToWorkerGlobalScope(execution_context_)->GetFontSelector();
+}
+
 DEFINE_TRACE(OffscreenCanvas) {
   visitor->Trace(context_);
   visitor->Trace(execution_context_);
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
index 763a3909..76dc52bc 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
@@ -152,6 +152,8 @@
 
   bool IsWebGLAllowed() const override { return true; }
 
+  FontSelector* GetFontSelector() override;
+
   DECLARE_VIRTUAL_TRACE();
 
  private:
diff --git a/third_party/WebKit/Source/core/page/PageOverlayTest.cpp b/third_party/WebKit/Source/core/page/PageOverlayTest.cpp
index 40f6894..e8468ef 100644
--- a/third_party/WebKit/Source/core/page/PageOverlayTest.cpp
+++ b/third_party/WebKit/Source/core/page/PageOverlayTest.cpp
@@ -90,6 +90,8 @@
         WTF::MakeUnique<SolidColorOverlay>(SK_ColorYELLOW));
   }
 
+  void SetViewportSize(const WebSize& size) { helper_.SetViewportSize(size); }
+
   template <typename OverlayType>
   void RunPageOverlayTestWithAcceleratedCompositing();
 
@@ -117,8 +119,7 @@
 
 TEST_F(PageOverlayTest, PageOverlay_AcceleratedCompositing) {
   Initialize(kAcceleratedCompositing);
-  GetWebView()->LayerTreeView()->SetViewportSize(
-      WebSize(kViewportWidth, kViewportHeight));
+  SetViewportSize(WebSize(kViewportWidth, kViewportHeight));
 
   std::unique_ptr<PageOverlay> page_overlay = CreateSolidYellowOverlay();
   page_overlay->Update();
diff --git a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
index 1af03ea..752d7c2 100644
--- a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
+++ b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
@@ -11,6 +11,7 @@
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/loader/fetch/ResourceFetcher.h"
 #include "platform/wtf/Functional.h"
+#include "public/platform/WebLayerTreeView.h"
 
 namespace blink {
 
@@ -90,7 +91,7 @@
     return;
 
   // Skip document background-only paints.
-  if (paint_timing_->FirstPaint() == 0.0)
+  if (paint_timing_->FirstPaintRendered() == 0.0)
     return;
 
   provisional_first_meaningful_paint_ = MonotonicallyIncreasingTime();
@@ -120,7 +121,7 @@
 // This is called only on FirstMeaningfulPaintDetector for main frame.
 void FirstMeaningfulPaintDetector::NotifyInputEvent() {
   // Ignore user inputs before first paint.
-  if (paint_timing_->FirstPaint() == 0.0)
+  if (paint_timing_->FirstPaintRendered() == 0.0)
     return;
   had_user_input_ = kHadUserInput;
 }
@@ -159,7 +160,7 @@
 
 void FirstMeaningfulPaintDetector::Network0QuietTimerFired(TimerBase*) {
   if (!GetDocument() || network0_quiet_reached_ || ActiveConnections() > 0 ||
-      !paint_timing_->FirstContentfulPaint())
+      !paint_timing_->FirstContentfulPaintRendered())
     return;
   network0_quiet_reached_ = true;
 
@@ -167,14 +168,14 @@
     // Enforce FirstContentfulPaint <= FirstMeaningfulPaint.
     first_meaningful_paint0_quiet_ =
         std::max(provisional_first_meaningful_paint_,
-                 paint_timing_->FirstContentfulPaint());
+                 paint_timing_->FirstContentfulPaintRendered());
   }
   ReportHistograms();
 }
 
 void FirstMeaningfulPaintDetector::Network2QuietTimerFired(TimerBase*) {
   if (!GetDocument() || network2_quiet_reached_ || ActiveConnections() > 2 ||
-      !paint_timing_->FirstContentfulPaint())
+      !paint_timing_->FirstContentfulPaintRendered())
     return;
   network2_quiet_reached_ = true;
 
@@ -186,10 +187,11 @@
         provisional_first_meaningful_paint_);
     // Enforce FirstContentfulPaint <= FirstMeaningfulPaint.
     if (provisional_first_meaningful_paint_ <
-        paint_timing_->FirstContentfulPaint()) {
-      first_meaningful_paint2_quiet_ = paint_timing_->FirstContentfulPaint();
+        paint_timing_->FirstContentfulPaintRendered()) {
+      first_meaningful_paint2_quiet_ =
+          paint_timing_->FirstContentfulPaintRendered();
       first_meaningful_paint2_quiet_swap_ =
-          paint_timing_->FirstContentfulPaintSwap();
+          paint_timing_->FirstContentfulPaint();
       // It's possible that this timer fires between when the first contentful
       // paint is set and its SwapPromise is fulfilled. If this happens, defer
       // until NotifyFirstContentfulPaint() is called.
@@ -267,18 +269,27 @@
                        WrapCrossThreadWeakPersistent(this), event));
 }
 
-void FirstMeaningfulPaintDetector::ReportSwapTime(PaintEvent event,
-                                                  bool did_swap,
-                                                  double timestamp) {
+void FirstMeaningfulPaintDetector::ReportSwapTime(
+    PaintEvent event,
+    WebLayerTreeView::SwapResult result,
+    double timestamp) {
   DCHECK(event == PaintEvent::kProvisionalFirstMeaningfulPaint);
   DCHECK_GT(outstanding_swap_promise_count_, 0U);
   --outstanding_swap_promise_count_;
 
-  // TODO(shaseley): Add UMAs here to see how often swaps fail. If this happens,
-  // the FMP will be 0.0 if this is the provisional timestamp we end up using.
-  if (!did_swap)
-    return;
-
+  // If the swap fails for any reason, we use the timestamp when the SwapPromise
+  // was broken. |result| == WebLayerTreeView::SwapResult::kDidNotSwapSwapFails
+  // usually means the compositor decided not swap because there was no actual
+  // damage, which can happen when what's being painted isn't visible. In this
+  // case, the timestamp will be consistent with the case where the swap
+  // succeeds, as they both capture the time up to swap. In other failure cases
+  // (aborts during commit), this timestamp is an improvement over the blink
+  // paint time, but does not capture some time we're interested in, e.g.  image
+  // decoding.
+  //
+  // TODO(crbug.com/738235): Consider not reporting any timestamp when failing
+  // for reasons other than kDidNotSwapSwapFails.
+  paint_timing_->ReportSwapResultHistogram(result);
   provisional_first_meaningful_paint_swap_ = timestamp;
 
   if (defer_first_meaningful_paint_ == kDeferOutstandingSwapPromises &&
diff --git a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.h b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.h
index 1bd25b66..48fe9a50 100644
--- a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.h
+++ b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.h
@@ -10,6 +10,7 @@
 #include "platform/Timer.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Noncopyable.h"
+#include "public/platform/WebLayerTreeView.h"
 
 namespace blink {
 
@@ -49,7 +50,7 @@
   void NotifyInputEvent();
   void NotifyPaint();
   void CheckNetworkStable();
-  void ReportSwapTime(PaintEvent, bool did_swap, double timestamp);
+  void ReportSwapTime(PaintEvent, WebLayerTreeView::SwapResult, double);
   void NotifyFirstContentfulPaint(double swap_stamp);
 
   DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetectorTest.cpp b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetectorTest.cpp
index 34663ed..3bf0cd53 100644
--- a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetectorTest.cpp
+++ b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetectorTest.cpp
@@ -9,6 +9,7 @@
 #include "core/testing/DummyPageHolder.h"
 #include "platform/testing/TestingPlatformSupport.h"
 #include "platform/wtf/text/StringBuilder.h"
+#include "public/platform/WebLayerTreeView.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -76,20 +77,23 @@
 
   void ClearFirstPaintSwapPromise() {
     platform_->AdvanceClockSeconds(0.001);
-    GetPaintTiming().ReportSwapTime(PaintEvent::kFirstPaint, true,
+    GetPaintTiming().ReportSwapTime(PaintEvent::kFirstPaint,
+                                    WebLayerTreeView::SwapResult::kDidSwap,
                                     MonotonicallyIncreasingTime());
   }
 
   void ClearFirstContentfulPaintSwapPromise() {
     platform_->AdvanceClockSeconds(0.001);
-    GetPaintTiming().ReportSwapTime(PaintEvent::kFirstContentfulPaint, true,
+    GetPaintTiming().ReportSwapTime(PaintEvent::kFirstContentfulPaint,
+                                    WebLayerTreeView::SwapResult::kDidSwap,
                                     MonotonicallyIncreasingTime());
   }
 
   void ClearProvisionalFirstMeaningfulPaintSwapPromise() {
     platform_->AdvanceClockSeconds(0.001);
     Detector().ReportSwapTime(PaintEvent::kProvisionalFirstMeaningfulPaint,
-                              true, MonotonicallyIncreasingTime());
+                              WebLayerTreeView::SwapResult::kDidSwap,
+                              MonotonicallyIncreasingTime());
   }
 
   unsigned OutstandingDetectorSwapPromiseCount() {
@@ -123,8 +127,8 @@
   SimulateLayoutAndPaint(1);
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
   SimulateNetworkStable();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, OneLayout) {
@@ -133,15 +137,15 @@
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   double after_paint = AdvanceClockAndGetTime();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
   SimulateNetworkStable();
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(),
+            GetPaintTiming().FirstPaintRendered());
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
-            GetPaintTiming().FirstPaint());
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+            GetPaintTiming().FirstMeaningfulPaintRendered());
+  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_paint);
   EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_paint);
-  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_paint);
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantSecond) {
@@ -155,12 +159,12 @@
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   double after_layout2 = AdvanceClockAndGetTime();
   SimulateNetworkStable();
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_layout1);
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_layout1);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_layout1);
+  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_layout2);
   EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_layout2);
-  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_layout2);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantFirst) {
@@ -172,12 +176,12 @@
   SimulateLayoutAndPaint(1);
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
   SimulateNetworkStable();
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(),
+            GetPaintTiming().FirstPaintRendered());
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
-            GetPaintTiming().FirstPaint());
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstPaint());
+            GetPaintTiming().FirstPaintRendered());
+  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_layout1);
   EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_layout1);
-  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_layout1);
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, FirstMeaningfulPaintCandidate) {
@@ -220,14 +224,14 @@
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   SimulateNetworkStable();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
   MarkFirstContentfulPaintAndClearSwapPromise();
   SimulateNetworkStable();
+  EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -239,12 +243,12 @@
   platform_->AdvanceClockSeconds(0.001);
   MarkFirstContentfulPaintAndClearSwapPromise();
   SimulateNetworkStable();
+  EXPECT_GE(GetPaintTiming().FirstMeaningfulPaintRendered(),
+            GetPaintTiming().FirstContentfulPaintRendered());
   EXPECT_GE(GetPaintTiming().FirstMeaningfulPaint(),
             GetPaintTiming().FirstContentfulPaint());
-  EXPECT_GE(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstContentfulPaintSwap());
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, Network2QuietThen0Quiet) {
@@ -262,14 +266,13 @@
   SimulateNetwork0Quiet();
 
   // The first paint is FirstMeaningfulPaint.
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
-  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_first_paint);
-  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            after_first_paint_swap);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_first_paint);
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint);
+  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint_swap);
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, Network0QuietThen2Quiet) {
@@ -288,14 +291,15 @@
   SimulateNetwork2Quiet();
 
   // The second paint is FirstMeaningfulPaint.
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_first_paint);
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_first_paint);
+  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(),
+            after_second_paint);
   EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_second_paint);
-  EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_second_paint);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, Network0QuietTimer) {
@@ -347,8 +351,8 @@
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   SimulateNetworkStable();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest, UserInteractionBeforeFirstPaint) {
@@ -358,10 +362,10 @@
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   SimulateNetworkStable();
+  EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -370,13 +374,13 @@
   SimulateLayoutAndPaint(10);
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
   SimulateNetworkStable();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
+  EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -389,22 +393,22 @@
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 2U);
   // Having outstanding swap promises should defer setting FMP.
   SimulateNetworkStable();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
   // Clearing the first swap promise should have no effect on FMP.
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
   double after_first_swap = AdvanceClockAndGetTime();
   // Clearing the last outstanding swap promise should set FMP.
   ClearProvisionalFirstMeaningfulPaintSwapPromise();
   EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), after_first_swap);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_swap);
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -418,20 +422,20 @@
   GetPaintTiming().MarkFirstContentfulPaint();
   // FCP > FMP candidate, but still waiting for FCP swap.
   SimulateNetworkStable();
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
   // Trigger notifying the detector about the FCP swap.
   ClearFirstContentfulPaintSwapPromise();
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), 0.0);
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), 0.0);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(), 0.0);
+  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(),
+            GetPaintTiming().FirstContentfulPaintRendered());
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(),
             GetPaintTiming().FirstContentfulPaint());
-  EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstContentfulPaintSwap());
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(),
             after_first_meaningful_paint_candidate);
-  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintSwap(),
-            GetPaintTiming().FirstMeaningfulPaint());
+  EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
+            GetPaintTiming().FirstMeaningfulPaintRendered());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintEvent.h b/third_party/WebKit/Source/core/paint/PaintEvent.h
index 26182adb..291f6a2 100644
--- a/third_party/WebKit/Source/core/paint/PaintEvent.h
+++ b/third_party/WebKit/Source/core/paint/PaintEvent.h
@@ -8,11 +8,13 @@
 namespace blink {
 
 // Paint events that either PaintTiming or FirstMeaningfulPaintDetector receive
-// GPU swap times for.
+// SwapPromise swap times for.
 enum class PaintEvent {
   kFirstPaint,
   kFirstContentfulPaint,
   kProvisionalFirstMeaningfulPaint,
+  kFirstTextPaint,
+  kFirstImagePaint,
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintTiming.cpp b/third_party/WebKit/Source/core/paint/PaintTiming.cpp
index 1934f5cf..9862a7d 100644
--- a/third_party/WebKit/Source/core/paint/PaintTiming.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintTiming.cpp
@@ -55,7 +55,6 @@
   if (first_paint_ != 0.0)
     return;
   SetFirstPaint(MonotonicallyIncreasingTime());
-  NotifyPaintTimingChanged();
 }
 
 void PaintTiming::MarkFirstContentfulPaint() {
@@ -66,7 +65,6 @@
   if (first_contentful_paint_ != 0.0)
     return;
   SetFirstContentfulPaint(MonotonicallyIncreasingTime());
-  NotifyPaintTimingChanged();
 }
 
 void PaintTiming::MarkFirstTextPaint() {
@@ -74,10 +72,7 @@
     return;
   first_text_paint_ = MonotonicallyIncreasingTime();
   SetFirstContentfulPaint(first_text_paint_);
-  TRACE_EVENT_MARK_WITH_TIMESTAMP1(
-      "loading,rail,devtools.timeline", "firstTextPaint",
-      TraceEvent::ToTraceTimestamp(first_text_paint_), "frame", GetFrame());
-  NotifyPaintTimingChanged();
+  RegisterNotifySwapTime(PaintEvent::kFirstTextPaint);
 }
 
 void PaintTiming::MarkFirstImagePaint() {
@@ -85,10 +80,7 @@
     return;
   first_image_paint_ = MonotonicallyIncreasingTime();
   SetFirstContentfulPaint(first_image_paint_);
-  TRACE_EVENT_MARK_WITH_TIMESTAMP1(
-      "loading,rail,devtools.timeline", "firstImagePaint",
-      TraceEvent::ToTraceTimestamp(first_image_paint_), "frame", GetFrame());
-  NotifyPaintTimingChanged();
+  RegisterNotifySwapTime(PaintEvent::kFirstImagePaint);
 }
 
 void PaintTiming::SetFirstMeaningfulPaintCandidate(double timestamp) {
@@ -105,16 +97,22 @@
     double swap_stamp,
     FirstMeaningfulPaintDetector::HadUserInput had_input) {
   DCHECK_EQ(first_meaningful_paint_, 0.0);
-  TRACE_EVENT_MARK_WITH_TIMESTAMP2("loading,rail,devtools.timeline",
-                                   "firstMeaningfulPaint",
-                                   TraceEvent::ToTraceTimestamp(stamp), "frame",
-                                   GetFrame(), "afterUserInput", had_input);
+  DCHECK_EQ(first_meaningful_paint_swap_, 0.0);
+  DCHECK_GT(stamp, 0.0);
+  DCHECK_GT(swap_stamp, 0.0);
+
+  TRACE_EVENT_MARK_WITH_TIMESTAMP2(
+      "loading,rail,devtools.timeline", "firstMeaningfulPaint",
+      TraceEvent::ToTraceTimestamp(swap_stamp), "frame", GetFrame(),
+      "afterUserInput", had_input);
 
   // Notify FMP for UMA only if there's no user input before FMP, so that layout
   // changes caused by user interactions wouldn't be considered as FMP.
   if (had_input == FirstMeaningfulPaintDetector::kNoUserInput) {
     first_meaningful_paint_ = stamp;
     first_meaningful_paint_swap_ = swap_stamp;
+    ReportSwapTimeDeltaHistogram(first_meaningful_paint_,
+                                 first_meaningful_paint_swap_);
     NotifyPaintTimingChanged();
   }
 
@@ -166,8 +164,6 @@
   if (first_paint_ != 0.0)
     return;
   first_paint_ = stamp;
-  TRACE_EVENT_INSTANT1("loading,rail,devtools.timeline", "firstPaint",
-                       TRACE_EVENT_SCOPE_PROCESS, "frame", GetFrame());
   RegisterNotifySwapTime(PaintEvent::kFirstPaint);
 }
 
@@ -176,10 +172,7 @@
     return;
   SetFirstPaint(stamp);
   first_contentful_paint_ = stamp;
-  TRACE_EVENT_INSTANT1("loading,rail,devtools.timeline", "firstContentfulPaint",
-                       TRACE_EVENT_SCOPE_PROCESS, "frame", GetFrame());
   RegisterNotifySwapTime(PaintEvent::kFirstContentfulPaint);
-  GetFrame()->Loader().Progress().DidFirstContentfulPaint();
 }
 
 void PaintTiming::RegisterNotifySwapTime(PaintEvent event) {
@@ -188,9 +181,8 @@
                                    WrapCrossThreadWeakPersistent(this), event));
 }
 
-void PaintTiming::RegisterNotifySwapTime(
-    PaintEvent event,
-    WTF::Function<void(bool, double)> callback) {
+void PaintTiming::RegisterNotifySwapTime(PaintEvent event,
+                                         ReportTimeCallback callback) {
   // ReportSwapTime on layerTreeView will queue a swap-promise, the callback is
   // called when the swap for current render frame completes or fails to happen.
   if (!GetFrame() || !GetFrame()->GetPage())
@@ -203,26 +195,110 @@
 }
 
 void PaintTiming::ReportSwapTime(PaintEvent event,
-                                 bool did_swap,
+                                 WebLayerTreeView::SwapResult result,
                                  double timestamp) {
-  if (!did_swap)
-    return;
-  Performance* performance = GetPerformanceInstance(GetFrame());
+  // If the swap fails for any reason, we use the timestamp when the SwapPromise
+  // was broken. |result| == WebLayerTreeView::SwapResult::kDidNotSwapSwapFails
+  // usually means the compositor decided not swap because there was no actual
+  // damage, which can happen when what's being painted isn't visible. In this
+  // case, the timestamp will be consistent with the case where the swap
+  // succeeds, as they both capture the time up to swap. In other failure cases
+  // (aborts during commit), this timestamp is an improvement over the blink
+  // paint time, but does not capture some time we're interested in, e.g.  image
+  // decoding.
+  //
+  // TODO(crbug.com/738235): Consider not reporting any timestamp when failing
+  // for reasons other than kDidNotSwapSwapFails.
+  ReportSwapResultHistogram(result);
   switch (event) {
     case PaintEvent::kFirstPaint:
-      first_paint_swap_ = timestamp;
-      if (performance)
-        performance->AddFirstPaintTiming(first_paint_);
+      SetFirstPaintSwap(timestamp);
       return;
     case PaintEvent::kFirstContentfulPaint:
-      first_contentful_paint_swap_ = timestamp;
-      if (performance)
-        performance->AddFirstContentfulPaintTiming(first_contentful_paint_);
-      fmp_detector_->NotifyFirstContentfulPaint(timestamp);
+      SetFirstContentfulPaintSwap(timestamp);
+      return;
+    case PaintEvent::kFirstTextPaint:
+      SetFirstTextPaintSwap(timestamp);
+      return;
+    case PaintEvent::kFirstImagePaint:
+      SetFirstImagePaintSwap(timestamp);
       return;
     default:
       NOTREACHED();
   }
 }
 
+void PaintTiming::SetFirstPaintSwap(double stamp) {
+  DCHECK_EQ(first_paint_swap_, 0.0);
+  first_paint_swap_ = stamp;
+  TRACE_EVENT_INSTANT_WITH_TIMESTAMP1(
+      "loading,rail,devtools.timeline", "firstPaint", TRACE_EVENT_SCOPE_PROCESS,
+      TraceEvent::ToTraceTimestamp(first_paint_swap_), "frame", GetFrame());
+  Performance* performance = GetPerformanceInstance(GetFrame());
+  if (performance)
+    performance->AddFirstPaintTiming(first_paint_swap_);
+  ReportSwapTimeDeltaHistogram(first_paint_, first_paint_swap_);
+  NotifyPaintTimingChanged();
+}
+
+void PaintTiming::SetFirstContentfulPaintSwap(double stamp) {
+  DCHECK_EQ(first_contentful_paint_swap_, 0.0);
+  first_contentful_paint_swap_ = stamp;
+  TRACE_EVENT_INSTANT_WITH_TIMESTAMP1(
+      "loading,rail,devtools.timeline", "firstContentfulPaint",
+      TRACE_EVENT_SCOPE_PROCESS,
+      TraceEvent::ToTraceTimestamp(first_contentful_paint_swap_), "frame",
+      GetFrame());
+  Performance* performance = GetPerformanceInstance(GetFrame());
+  if (performance)
+    performance->AddFirstContentfulPaintTiming(first_contentful_paint_swap_);
+  if (GetFrame())
+    GetFrame()->Loader().Progress().DidFirstContentfulPaint();
+  ReportSwapTimeDeltaHistogram(first_contentful_paint_,
+                               first_contentful_paint_swap_);
+  NotifyPaintTimingChanged();
+  fmp_detector_->NotifyFirstContentfulPaint(first_contentful_paint_swap_);
+}
+
+void PaintTiming::SetFirstTextPaintSwap(double stamp) {
+  DCHECK_EQ(first_text_paint_swap_, 0.0);
+  first_text_paint_swap_ = stamp;
+  TRACE_EVENT_MARK_WITH_TIMESTAMP1(
+      "loading,rail,devtools.timeline", "firstTextPaint",
+      TraceEvent::ToTraceTimestamp(first_text_paint_swap_), "frame",
+      GetFrame());
+  ReportSwapTimeDeltaHistogram(first_text_paint_, first_text_paint_swap_);
+  NotifyPaintTimingChanged();
+}
+
+void PaintTiming::SetFirstImagePaintSwap(double stamp) {
+  DCHECK_EQ(first_image_paint_swap_, 0.0);
+  first_image_paint_swap_ = stamp;
+  TRACE_EVENT_MARK_WITH_TIMESTAMP1(
+      "loading,rail,devtools.timeline", "firstImagePaint",
+      TraceEvent::ToTraceTimestamp(first_image_paint_swap_), "frame",
+      GetFrame());
+  ReportSwapTimeDeltaHistogram(first_image_paint_, first_image_paint_swap_);
+  NotifyPaintTimingChanged();
+}
+
+void PaintTiming::ReportSwapResultHistogram(
+    const WebLayerTreeView::SwapResult result) {
+  DEFINE_STATIC_LOCAL(EnumerationHistogram, did_swap_histogram,
+                      ("PageLoad.Internal.Renderer.PaintTiming.SwapResult",
+                       WebLayerTreeView::SwapResult::kSwapResultMax));
+  did_swap_histogram.Count(result);
+}
+
+void PaintTiming::ReportSwapTimeDeltaHistogram(double timestamp,
+                                               double swap_timestamp) {
+  DEFINE_STATIC_LOCAL(
+      CustomCountHistogram, swap_time_diff_histogram,
+      ("PageLoad.Internal.Renderer.PaintTiming.SwapTimeDelta", 0, 10000, 50));
+  DCHECK_GT(timestamp, 0.0);
+  DCHECK_GT(swap_timestamp, 0.0);
+  DCHECK_GE(swap_timestamp, timestamp);
+  swap_time_diff_histogram.Count((swap_timestamp - timestamp) * 1000.0);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintTiming.h b/third_party/WebKit/Source/core/paint/PaintTiming.h
index db3f9fd7..cdf70667 100644
--- a/third_party/WebKit/Source/core/paint/PaintTiming.h
+++ b/third_party/WebKit/Source/core/paint/PaintTiming.h
@@ -14,6 +14,7 @@
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Functional.h"
 #include "platform/wtf/Noncopyable.h"
+#include "public/platform/WebLayerTreeView.h"
 
 namespace blink {
 
@@ -26,23 +27,26 @@
       public Supplement<Document> {
   WTF_MAKE_NONCOPYABLE(PaintTiming);
   USING_GARBAGE_COLLECTED_MIXIN(PaintTiming);
+  friend class FirstMeaningfulPaintDetector;
+  using ReportTimeCallback =
+      WTF::Function<void(WebLayerTreeView::SwapResult, double)>;
 
  public:
   virtual ~PaintTiming() {}
 
   static PaintTiming& From(Document&);
 
-  // mark*() methods record the time for the given paint event, record a trace
-  // event, and notify that paint timing has changed. These methods do nothing
+  // Mark*() methods record the time for the given paint event and queue a swap
+  // promise to record the |first_*_swap_| timestamp. These methods do nothing
   // (early return) if a time has already been recorded for the given paint
   // event.
   void MarkFirstPaint();
 
-  // markFirstTextPaint, markFirstImagePaint, and markFirstContentfulPaint
+  // MarkFirstTextPaint, MarkFirstImagePaint, and MarkFirstContentfulPaint
   // will also record first paint if first paint hasn't been recorded yet.
   void MarkFirstContentfulPaint();
 
-  // markFirstTextPaint and markFirstImagePaint will also record first
+  // MarkFirstTextPaint and MarkFirstImagePaint will also record first
   // contentful paint if first contentful paint hasn't been recorded yet.
   void MarkFirstTextPaint();
   void MarkFirstImagePaint();
@@ -58,32 +62,26 @@
   // given paint event has not yet occurred. See the comments for
   // monotonicallyIncreasingTime in wtf/CurrentTime.h for additional details.
 
-  // firstPaint returns the first time that anything was painted for the
+  // FirstPaint returns the first time that anything was painted for the
   // current document.
-  double FirstPaint() const { return first_paint_; }
+  double FirstPaint() const { return first_paint_swap_; }
 
-  // firstContentfulPaint returns the first time that 'contentful' content was
+  // FirstContentfulPaint returns the first time that 'contentful' content was
   // painted. For instance, the first time that text or image content was
   // painted.
-  double FirstContentfulPaint() const { return first_contentful_paint_; }
-  double FirstContentfulPaintSwap() const {
-    return first_contentful_paint_swap_;
-  }
+  double FirstContentfulPaint() const { return first_contentful_paint_swap_; }
 
-  // firstTextPaint returns the first time that text content was painted.
-  double FirstTextPaint() const { return first_text_paint_; }
+  // FirstTextPaint returns the first time that text content was painted.
+  double FirstTextPaint() const { return first_text_paint_swap_; }
 
-  // firstImagePaint returns the first time that image content was painted.
-  double FirstImagePaint() const { return first_image_paint_; }
+  // FirstImagePaint returns the first time that image content was painted.
+  double FirstImagePaint() const { return first_image_paint_swap_; }
 
-  // firstMeaningfulPaint returns the first time that page's primary content
+  // FirstMeaningfulPaint returns the first time that page's primary content
   // was painted.
-  double FirstMeaningfulPaint() const { return first_meaningful_paint_; }
-  double FirstMeaningfulPaintSwap() const {
-    return first_meaningful_paint_swap_;
-  }
+  double FirstMeaningfulPaint() const { return first_meaningful_paint_swap_; }
 
-  // firstMeaningfulPaintCandidate indicates the first time we considered a
+  // FirstMeaningfulPaintCandidate indicates the first time we considered a
   // paint to qualify as the potentially first meaningful paint. Unlike
   // firstMeaningfulPaint, this signal is available in real time, but it may be
   // an optimistic (i.e., too early) estimate.
@@ -95,9 +93,12 @@
     return *fmp_detector_;
   }
 
-  void RegisterNotifySwapTime(PaintEvent,
-                              WTF::Function<void(bool, double)> callback);
-  void ReportSwapTime(PaintEvent, bool did_swap, double timestamp);
+  void RegisterNotifySwapTime(PaintEvent, ReportTimeCallback);
+  void ReportSwapTime(PaintEvent,
+                      WebLayerTreeView::SwapResult,
+                      double timestamp);
+
+  void ReportSwapResultHistogram(const WebLayerTreeView::SwapResult);
 
   DECLARE_VIRTUAL_TRACE();
 
@@ -106,26 +107,52 @@
   LocalFrame* GetFrame() const;
   void NotifyPaintTimingChanged();
 
-  // set*() set the timing for the given paint event to the given timestamp
-  // and record a trace event if the value is currently zero, but do not
-  // notify that paint timing changed. These methods can be invoked from other
-  // mark*() or set*() methods to make sure that first paint is marked as part
-  // of marking first contentful paint, or that first contentful paint is
-  // marked as part of marking first text/image paint, for example.
+  // Set*() set the timing for the given paint event to the given timestamp if
+  // the value is currently zero, and queue a swap promise to record the
+  // |first_*_swap_| timestamp. These methods can be invoked from other Mark*()
+  // or Set*() methods to make sure that first paint is marked as part of
+  // marking first contentful paint, or that first contentful paint is marked as
+  // part of marking first text/image paint, for example.
   void SetFirstPaint(double stamp);
 
   // setFirstContentfulPaint will also set first paint time if first paint
   // time has not yet been recorded.
   void SetFirstContentfulPaint(double stamp);
 
+  // Set*Swap() are called when the SwapPromise is fulfilled and the swap
+  // timestamp is available. These methods will record trace events, update Web
+  // Perf API (FP and FCP only), and notify that paint timing has changed, which
+  // triggers UMAs and UKMS.
+  // |stamp| is the swap timestamp used for tracing, UMA, UKM, and Web Perf API.
+  void SetFirstPaintSwap(double stamp);
+  void SetFirstContentfulPaintSwap(double stamp);
+  void SetFirstImagePaintSwap(double stamp);
+  void SetFirstTextPaintSwap(double stamp);
+
   void RegisterNotifySwapTime(PaintEvent);
   void ReportUserInputHistogram(
       FirstMeaningfulPaintDetector::HadUserInput had_input);
+  void ReportSwapTimeDeltaHistogram(double timestamp, double swap_timestamp);
 
+  double FirstPaintRendered() const { return first_paint_; }
+
+  double FirstContentfulPaintRendered() const {
+    return first_contentful_paint_;
+  }
+
+  double FirstMeaningfulPaintRendered() const {
+    return first_meaningful_paint_;
+  }
+
+  // TODO(crbug/738235): Non first_*_swap_ variables are only being tracked to
+  // compute deltas for reporting histograms and should be removed once we
+  // confirm the deltas and discrepancies look reasonable.
   double first_paint_ = 0.0;
   double first_paint_swap_ = 0.0;
   double first_text_paint_ = 0.0;
+  double first_text_paint_swap_ = 0.0;
   double first_image_paint_ = 0.0;
+  double first_image_paint_swap_ = 0.0;
   double first_contentful_paint_ = 0.0;
   double first_contentful_paint_swap_ = 0.0;
   double first_meaningful_paint_ = 0.0;
@@ -133,6 +160,43 @@
   double first_meaningful_paint_candidate_ = 0.0;
 
   Member<FirstMeaningfulPaintDetector> fmp_detector_;
+
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, NoFirstPaint);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, OneLayout);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           TwoLayoutsSignificantSecond);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           TwoLayoutsSignificantFirst);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           FirstMeaningfulPaintCandidate);
+  FRIEND_TEST_ALL_PREFIXES(
+      FirstMeaningfulPaintDetectorTest,
+      OnlyOneFirstMeaningfulPaintCandidateBeforeNetworkStable);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           NetworkStableBeforeFirstContentfulPaint);
+  FRIEND_TEST_ALL_PREFIXES(
+      FirstMeaningfulPaintDetectorTest,
+      FirstMeaningfulPaintShouldNotBeBeforeFirstContentfulPaint);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           Network2QuietThen0Quiet);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           Network0QuietThen2Quiet);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           Network0QuietTimer);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           Network2QuietTimer);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           FirstMeaningfulPaintAfterUserInteraction);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           UserInteractionBeforeFirstPaint);
+  FRIEND_TEST_ALL_PREFIXES(
+      FirstMeaningfulPaintDetectorTest,
+      WaitForSingleOutstandingSwapPromiseAfterNetworkStable);
+  FRIEND_TEST_ALL_PREFIXES(
+      FirstMeaningfulPaintDetectorTest,
+      WaitForMultipleOutstandingSwapPromisesAfterNetworkStable);
+  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
+                           WaitForFirstContentfulPaintSwapAfterNetworkStable);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/resize_observer/README.md b/third_party/WebKit/Source/core/resize_observer/README.md
new file mode 100644
index 0000000..47f9aa44
--- /dev/null
+++ b/third_party/WebKit/Source/core/resize_observer/README.md
@@ -0,0 +1,68 @@
+# ResizeObserver
+
+Implements ResizeObserver [spec]( https://github.com/WICG/ResizeObserver), which has a nice [explainer](https://github.com/WICG/ResizeObserver/blob/master/explainer.md).
+
+The purpose of ResizeObserver is to expose a ResizeObserver DOM API that
+notifies observer when Element's size has changed.
+
+# Architecture overview
+
+The externally exposed APIs are:
+
+[`ResizeObserver.idl`](ResizeObserver.idl) implements a general observer pattern, observe(), unobserve(), disconnect().
+
+[`ResizeObserverEntry.idl`](ResizeObserverEntry.idl) represents an observation to be delivered, with target and contentRect.
+
+Classes used internally are:
+
+[`ResizeObservation`](ResizeObservation.h) internal representation of an Element that is being observed, and its last observed size.
+
+[`ResizeObserverController`](ResizeObservationController.h) ties Document to its ResizeObservers.
+
+# Notification lifecycle
+
+ResizeObserver needs to deliver notifications before every animation frame.
+
+There are 2 phases of notification lifecycle:
+
+###### 1) Size change detection
+
+`ResizeObservation` stores last observed element size.
+
+There are 2 ways to detect size change. One way is "pull", where every watched
+Element's size is compared to last observed size. This is inefficient, because
+all observed Elements must be polled in every frame.
+
+That is why we use "push", where Element sets a flag that it's size has changed.
+The flag gets set by calling `Element::SetNeedsResizeObserverUpdate()`. This
+notifies ResizeObservation, which also notifies ResizeObserver.
+`SetNeedsResizeObserverUpdate` has to be carefully added to all places
+that might trigger a resize observation.
+
+###### 2) Notification delivery
+
+Notification delivery is done by calling `LocalFrameView::NotifyResizeObservers()`
+for every rAF. It calls `ResizeObserverController::DeliverObservations()`
+which delivers observations for all ResizeObservers that have detected size changes.
+`DeliverObservations()` will not run if size has not changed. To deliver initial
+observation, ResizeObserver must call `LocalFrameView::ScheduleAnimation`.
+
+# Object lifetime
+
+ResizeObserver objects are garbage collected. Figuring out how to arrange references
+to ensure proper lifetime is tricky.
+
+ResizeObserver must be kept alive as long as at least one of these is true:
+1) There is a Javascript reference to ResizeObserver.
+2) There is an active observation. This happens when Javascript has no more
+references to ResizeObserver, but observations should still be delivered.
+
+You can use the reference chain below to trace object lifetime chain:
+```
+Javascript => ResizeObserver
+Element.resize_observer_data_ => ResizeObserver, ResizeObservation
+Document.resize_observer_controller_ => ResizeObserverController
+ResizeObserver => ResizeObserverEntry
+ResizeObserver => ResizeObserverCallback
+ResizeObserverEntry => Element
+```
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index c524206..03842d7 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -32,6 +32,7 @@
 #include "bindings/core/v8/SourceLocation.h"
 #include "bindings/core/v8/V8AbstractEventListener.h"
 #include "bindings/core/v8/WorkerOrWorkletScriptController.h"
+#include "core/css/OffscreenFontSelector.h"
 #include "core/dom/ContextLifecycleNotifier.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/SuspendableObject.h"
@@ -370,7 +371,8 @@
       thread_(thread),
       event_queue_(WorkerEventQueue::Create(this)),
       timers_(TaskRunnerHelper::Get(TaskType::kTimer, this)),
-      time_origin_(time_origin) {
+      time_origin_(time_origin),
+      font_selector_(OffscreenFontSelector::Create()) {
   InstanceCounters::IncrementCounter(
       InstanceCounters::kWorkerGlobalScopeCounter);
   SetSecurityOrigin(SecurityOrigin::Create(url));
@@ -406,6 +408,8 @@
     std::unique_ptr<WorkerSettings> worker_settings) {
   worker_settings_ = std::move(worker_settings);
   worker_settings_->MakeGenericFontFamilySettingsAtomic();
+  font_selector_->UpdateGenericFontFamilySettings(
+      worker_settings_->GetGenericFontFamilySettings());
 }
 
 void WorkerGlobalScope::ExceptionThrown(ErrorEvent* event) {
@@ -433,6 +437,7 @@
   visitor->Trace(timers_);
   visitor->Trace(event_listeners_);
   visitor->Trace(pending_error_events_);
+  visitor->Trace(font_selector_);
   EventTargetWithInlineData::Trace(visitor);
   SecurityContext::Trace(visitor);
   WorkerOrWorkletGlobalScope::Trace(visitor);
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index 9fdd4397..40f364f 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -6,9 +6,9 @@
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
+ * 2. Redistributions in binary form must reproduce the above copyright
  *
  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -48,6 +48,7 @@
 
 class ConsoleMessage;
 class ExceptionState;
+class OffscreenFontSelector;
 class V8AbstractEventListener;
 class WorkerLocation;
 class WorkerNavigator;
@@ -130,6 +131,8 @@
   WorkerEventQueue* GetEventQueue() const final;
   bool IsSecureContext(String& error_message) const override;
 
+  OffscreenFontSelector* GetFontSelector() { return font_selector_; }
+
   CoreProbeSink* GetProbeSink() final;
 
   // EventTarget
@@ -224,6 +227,8 @@
 
   HeapHashMap<int, Member<ErrorEvent>> pending_error_events_;
   int last_pending_error_event_id_ = 0;
+
+  Member<OffscreenFontSelector> font_selector_;
 };
 
 DEFINE_TYPE_CASTS(WorkerGlobalScope,
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 32e02d67..7637740 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -473,8 +473,7 @@
       DCHECK(font_lru_list_.Contains(new_font));
       font_lru_list_.erase(new_font);
       font_lru_list_.insert(new_font);
-      ModifiableState().SetFont(
-          i->value, canvas()->GetDocument().GetStyleEngine().GetFontSelector());
+      ModifiableState().SetFont(i->value, host()->GetFontSelector());
     } else {
       MutableStylePropertySet* parsed_style =
           canvas_font_cache->ParseFont(new_font);
@@ -508,17 +507,13 @@
       font_lru_list_.insert(new_font);
       PruneLocalFontCache(canvas_font_cache->HardMaxFonts());  // hard limit
       should_prune_local_font_cache_ = true;  // apply soft limit
-      ModifiableState().SetFont(
-          final_font,
-          canvas()->GetDocument().GetStyleEngine().GetFontSelector());
+      ModifiableState().SetFont(final_font, host()->GetFontSelector());
     }
   } else {
     Font resolved_font;
     if (!canvas_font_cache->GetFontUsingDefaultStyle(new_font, resolved_font))
       return;
-    ModifiableState().SetFont(
-        resolved_font,
-        canvas()->GetDocument().GetStyleEngine().GetFontSelector());
+    ModifiableState().SetFont(resolved_font, host()->GetFontSelector());
   }
 
   // The parse succeeded.
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index fb1ff16..7daad30 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -35,8 +35,6 @@
     Settings* settings = ToDocument(execution_context)->GetSettings();
     if (settings->GetDisableReadingFromCanvas())
       canvas->SetDisableReadingFromCanvasTrue();
-    font_selector_ =
-        OffscreenFontSelector::Create(settings->GetGenericFontFamilySettings());
     return;
   }
   dirty_rect_for_commit_.setEmpty();
@@ -44,12 +42,9 @@
       ToWorkerGlobalScope(execution_context)->GetWorkerSettings();
   if (worker_settings && worker_settings->DisableReadingFromCanvas())
     canvas->SetDisableReadingFromCanvasTrue();
-  font_selector_ = OffscreenFontSelector::Create(
-      worker_settings->GetGenericFontFamilySettings());
 }
 
 DEFINE_TRACE(OffscreenCanvasRenderingContext2D) {
-  visitor->Trace(font_selector_);
   CanvasRenderingContext::Trace(visitor);
   BaseRenderingContext2D::Trace(visitor);
 }
@@ -298,7 +293,7 @@
   FontDescription desc = FontStyleResolver::ComputeFont(*style);
 
   Font font = Font(desc);
-  ModifiableState().SetFont(font, font_selector_);
+  ModifiableState().SetFont(font, host()->GetFontSelector());
   ModifiableState().SetUnparsedFont(new_font);
 }
 
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
index 4cc50ef..425e3af 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -14,7 +14,6 @@
 namespace blink {
 
 class Font;
-class OffscreenFontSelector;
 class TextMetrics;
 
 class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
@@ -140,8 +139,6 @@
   String ColorSpaceAsString() const override;
   CanvasPixelFormat PixelFormat() const override;
   SkIRect dirty_rect_for_commit_;
-
-  Member<OffscreenFontSelector> font_selector_;
 };
 
 DEFINE_TYPE_CASTS(OffscreenCanvasRenderingContext2D,
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp b/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp
index 3e883d5..7ad0ec8 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp
@@ -162,7 +162,7 @@
 
   switch (policy) {
     case kZeroInitialize:
-      buffer = WTF::Float32Array::Create(length);
+      buffer = WTF::Float32Array::CreateOrNull(length);
       break;
     case kDontInitialize:
       buffer = WTF::Float32Array::CreateUninitializedOrNull(length);
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
index db0a8214..cb634a1 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
@@ -95,7 +95,7 @@
   std::unique_ptr<FakeGraphicsLayer> clip_layer_;
 
  private:
-  std::unique_ptr<WebLayerTreeView> layer_tree_view_;
+  std::unique_ptr<WebLayerTreeViewImplForTesting> layer_tree_view_;
   FakeGraphicsLayerClient client_;
 };
 
diff --git a/third_party/WebKit/Source/platform/plugins/PluginData.cpp b/third_party/WebKit/Source/platform/plugins/PluginData.cpp
index c4fb8d7..5eb6af5f 100644
--- a/third_party/WebKit/Source/platform/plugins/PluginData.cpp
+++ b/third_party/WebKit/Source/platform/plugins/PluginData.cpp
@@ -53,7 +53,7 @@
 }
 
 const MimeClassInfo* PluginInfo::GetMimeClassInfo(size_t index) const {
-  if (index > mimes_.size())
+  if (index >= mimes_.size())
     return nullptr;
   return mimes_[index];
 }
diff --git a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
index 90e3280..612fa5a 100644
--- a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
+++ b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
@@ -53,6 +53,13 @@
          layer_tree_host_.get();
 }
 
+void WebLayerTreeViewImplForTesting::SetViewportSize(
+    const WebSize& device_viewport_size) {
+  gfx::Size gfx_size(std::max(0, device_viewport_size.width),
+                     std::max(0, device_viewport_size.height));
+  layer_tree_host_->SetViewportSize(gfx_size);
+}
+
 void WebLayerTreeViewImplForTesting::SetRootLayer(const blink::WebLayer& root) {
   layer_tree_host_->SetRootLayer(
       static_cast<const cc_blink::WebLayerImpl*>(&root)->layer());
@@ -66,21 +73,6 @@
   return animation_host_.get();
 }
 
-void WebLayerTreeViewImplForTesting::SetViewportSize(
-    const WebSize& unused_deprecated,
-    const WebSize& device_viewport_size) {
-  gfx::Size gfx_size(std::max(0, device_viewport_size.width),
-                     std::max(0, device_viewport_size.height));
-  layer_tree_host_->SetViewportSize(gfx_size);
-}
-
-void WebLayerTreeViewImplForTesting::SetViewportSize(
-    const WebSize& device_viewport_size) {
-  gfx::Size gfx_size(std::max(0, device_viewport_size.width),
-                     std::max(0, device_viewport_size.height));
-  layer_tree_host_->SetViewportSize(gfx_size);
-}
-
 WebSize WebLayerTreeViewImplForTesting::GetViewportSize() const {
   return WebSize(layer_tree_host_->device_viewport_size().width(),
                  layer_tree_host_->device_viewport_size().height());
diff --git a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
index 6efd9cba..46a4058 100644
--- a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
+++ b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
@@ -36,14 +36,12 @@
   static cc::LayerTreeSettings DefaultLayerTreeSettings();
   cc::LayerTreeHost* GetLayerTreeHost() { return layer_tree_host_.get(); }
   bool HasLayer(const WebLayer&);
+  void SetViewportSize(const blink::WebSize&);
 
   // blink::WebLayerTreeView implementation.
   void SetRootLayer(const blink::WebLayer&) override;
   void ClearRootLayer() override;
   cc::AnimationHost* CompositorAnimationHost() override;
-  virtual void SetViewportSize(const blink::WebSize& unused_deprecated,
-                               const blink::WebSize& device_viewport_size);
-  void SetViewportSize(const blink::WebSize&) override;
   WebSize GetViewportSize() const override;
   void SetDeviceScaleFactor(float) override;
   void SetBackgroundColor(blink::WebColor) override;
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index 4bffc342..9e93d3b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -78,7 +78,7 @@
         _, show_ref_output = self.run(['git', 'show-ref', 'origin/master'], cwd=local_wpt.path)
         import_commit = 'wpt@%s' % show_ref_output.split()[0]
 
-        _log.info('Importing wpt@%s to Chromium %s', import_commit, chromium_commit)
+        _log.info('Importing %s to Chromium %s', import_commit, chromium_commit)
 
         commit_message = self._commit_message(chromium_commit, import_commit)
 
diff --git a/third_party/WebKit/public/blink_typemaps.gni b/third_party/WebKit/public/blink_typemaps.gni
index 7bb342b..aab6457 100644
--- a/third_party/WebKit/public/blink_typemaps.gni
+++ b/third_party/WebKit/public/blink_typemaps.gni
@@ -7,7 +7,7 @@
   "//cc/ipc/frame_sink_id.typemap",
   "//cc/ipc/local_surface_id.typemap",
   "//cc/ipc/surface_id.typemap",
-  "//cc/ipc/surface_sequence.typemap",
+  "//services/viz/public/cpp/compositing/surface_sequence.typemap",
   "//gpu/ipc/common/mailbox_holder_for_blink.typemap",
   "//gpu/ipc/common/sync_token.typemap",
   "//services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap",
diff --git a/third_party/WebKit/public/platform/WebLayerTreeView.h b/third_party/WebKit/public/platform/WebLayerTreeView.h
index 358409e9..a341f0e 100644
--- a/third_party/WebKit/public/platform/WebLayerTreeView.h
+++ b/third_party/WebKit/public/platform/WebLayerTreeView.h
@@ -35,6 +35,7 @@
 #include "WebImageLayer.h"
 #include "WebSize.h"
 #include "base/callback.h"
+#include "cc/output/swap_promise.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 
 #include "third_party/skia/include/core/SkImage.h"
@@ -53,9 +54,22 @@
 class WebSelection;
 
 class WebLayerTreeView {
-  using ReportTimeCallback = base::Callback<void(bool, double)>;
-
  public:
+  // SwapResult mirrors the values of cc::SwapPromise::DidNotSwapReason, and
+  // should be kept consistent with it. SwapResult additionally adds a success
+  // value (kDidSwap).
+  // These values are written to logs. New enum values can be added, but
+  // existing enums must never be renumbered, deleted or reused.
+  enum SwapResult {
+    kDidSwap = 0,
+    kDidNotSwapSwapFails = 1,
+    kDidNotSwapCommitFails = 2,
+    kDidNotSwapCommitNoUpdate = 3,
+    kDidNotSwapActivationFails = 4,
+    kSwapResultMax,
+  };
+  using ReportTimeCallback = base::Callback<void(SwapResult, double)>;
+
   virtual ~WebLayerTreeView() {}
 
   // Initialization and lifecycle --------------------------------------
@@ -70,7 +84,6 @@
   // View properties ---------------------------------------------------
 
   // Viewport size is given in physical pixels.
-  virtual void SetViewportSize(const WebSize& device_viewport_size) {}
   virtual WebSize GetViewportSize() const { return WebSize(); }
 
   virtual void SetDeviceScaleFactor(float) {}
diff --git a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
index 870a31817..d7f62a09 100644
--- a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
+++ b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
@@ -6,13 +6,13 @@
 
 import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/surface_id.mojom";
-import "cc/ipc/surface_sequence.mojom";
 import "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom";
 import "services/viz/public/interfaces/compositing/surface_info.mojom";
+import "services/viz/public/interfaces/compositing/surface_sequence.mojom";
 
 interface OffscreenCanvasSurface {
-  Require(cc.mojom.SurfaceId surface_id, cc.mojom.SurfaceSequence sequence);
-  Satisfy(cc.mojom.SurfaceSequence sequence);
+  Require(cc.mojom.SurfaceId surface_id, viz.mojom.SurfaceSequence sequence);
+  Satisfy(viz.mojom.SurfaceSequence sequence);
 };
 
 interface OffscreenCanvasSurfaceClient {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3d561bc..b8274150 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3429,6 +3429,11 @@
   <int value="1" label="Needs to be clearred"/>
 </enum>
 
+<enum name="BooleanNetworkQuietBeforeSwap">
+  <int value="0" label="FMP OK, network not yet quiet"/>
+  <int value="1" label="FMP not OK, network was already quiet"/>
+</enum>
+
 <enum name="BooleanNullStream">
   <int value="0" label="Stream is not a nullptr"/>
   <int value="1" label="Stream is a nullptr"/>
@@ -4200,6 +4205,7 @@
   <int value="1" label="Omnibox Focus"/>
   <int value="2" label="New Tab Creation"/>
   <int value="3" label="Expand Button Pressed"/>
+  <int value="4" label="Browser Startup"/>
 </enum>
 
 <enum name="ChromeNotifierServiceActionType">
@@ -36438,6 +36444,14 @@
   <int value="1" label="YUY2"/>
 </enum>
 
+<enum name="SwapResult">
+  <int value="0" label="Swap was successful"/>
+  <int value="1" label="Swap was unsuccessful (swap fails)"/>
+  <int value="2" label="Swap was unsuccessful (commit fails)"/>
+  <int value="3" label="Swap was unsuccessful (commit no update)"/>
+  <int value="4" label="Swap was unsuccessful (activation fails)"/>
+</enum>
+
 <enum name="SwReporterRunningTimeRegistryError">
   <int value="0" label="No error"/>
   <int value="1" label="Registry key invalid"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 148e47d9..5799cad8 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -52380,6 +52380,37 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Internal.Renderer.PaintTiming.SwapResult"
+    enum="SwapResult">
+  <owner>panicker@chromium.org</owner>
+  <summary>
+    For first paint, first contentful paint, first meaningful paint, first text
+    paint, and first image paint, we use the swap timestamp of the corresponding
+    paint, which is the timestamp the CC SwapPromise was positively fulfilled
+    (i.e. DidSwap() was invoked). If the swap did not occur (DidNotSwap() was
+    invoked), we use the timestamp when the swap promise fails. However, in the
+    future we may stop reporting timestamps for certain failure reasons. This
+    metric records whether or not the swap occurred, and the reason for failure
+    if it failed. The distribution of this metric will help determine the effect
+    of not reporting timestamps in certain cases.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Internal.Renderer.PaintTiming.SwapTimeDelta"
+    units="ms">
+  <owner>panicker@chromium.org</owner>
+  <summary>
+    Records the delta between the renderer timestamp and swap timestamp for
+    first paint, first contentful paint, first meaningful paint, first text
+    paint, and first image paint. The renderer timestamp is recorded on the
+    Paint path, while the swap timestamp is the result of a CC SwapPromise
+    (queued on the Paint path) either being successfully fulfilled, or broken in
+    cases where the swap did not occur. As we switch to using the swap
+    timestamps in place of their renderer counterparts, this metric allows us to
+    see the discrepancies between the two timestamps.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Navigation.RedirectChainLength" units="urls">
   <owner>csharrison@chromium.org</owner>
   <summary>
@@ -54345,6 +54376,9 @@
 <histogram
     name="PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the flow was completed when CanMakePayment was not called by the
@@ -54354,6 +54388,9 @@
 
 <histogram name="PaymentRequest.CanMakePayment.Usage"
     enum="CanMakePaymentUsage">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the merchant used the CanMakePayment method during a Payment
@@ -54363,6 +54400,9 @@
 
 <histogram name="PaymentRequest.CanMakePayment.Used.EffectOnShow"
     enum="PaymentRequestCanMakePaymentEffectOnShow">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     The effect of the CanMakePayment return value on whether Show was called.
@@ -54372,6 +54412,9 @@
 <histogram
     name="PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the flow was completed when CanMakePayment was called by the
@@ -54382,6 +54425,9 @@
 <histogram
     name="PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the flow was completed when CanMakePayment was called by the
@@ -54522,6 +54568,9 @@
 <histogram
     name="PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything.EffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the flow was completed when the user did not have a complete
@@ -54546,6 +54595,9 @@
 <histogram
     name="PaymentRequest.UserDidNotHaveSuggestionsForEverything.EffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the flow was completed when the user did not have suggestions
@@ -54556,6 +54608,9 @@
 <histogram
     name="PaymentRequest.UserHadCompleteSuggestionsForEverything.EffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
+  <obsolete>
+    M62+ Part of PaymentRequest.Events
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether the flow was completed when the user had at least one complete
@@ -97548,23 +97603,25 @@
   <suffix name="OtherAborted"
       label="The Payment Request was aborted but not but the user"/>
   <affected-histogram name="PaymentRequest.NumberOfSelectionAdds.ContactInfo"/>
-  <affected-histogram name="PaymentRequest.NumberOfSelectionAdds.CreditCards"/>
+  <affected-histogram
+      name="PaymentRequest.NumberOfSelectionAdds.PaymentMethod"/>
   <affected-histogram
       name="PaymentRequest.NumberOfSelectionAdds.ShippingAddress"/>
   <affected-histogram
       name="PaymentRequest.NumberOfSelectionChanges.ContactInfo"/>
   <affected-histogram
-      name="PaymentRequest.NumberOfSelectionChanges.CreditCards"/>
+      name="PaymentRequest.NumberOfSelectionChanges.PaymentMethod"/>
   <affected-histogram
       name="PaymentRequest.NumberOfSelectionChanges.ShippingAddress"/>
   <affected-histogram name="PaymentRequest.NumberOfSelectionEdits.ContactInfo"/>
-  <affected-histogram name="PaymentRequest.NumberOfSelectionEdits.CreditCards"/>
+  <affected-histogram
+      name="PaymentRequest.NumberOfSelectionEdits.PaymentMethod"/>
   <affected-histogram
       name="PaymentRequest.NumberOfSelectionEdits.ShippingAddress"/>
   <affected-histogram
       name="PaymentRequest.NumberOfSuggestionsShown.ContactInfo"/>
   <affected-histogram
-      name="PaymentRequest.NumberOfSuggestionsShown.CreditCards"/>
+      name="PaymentRequest.NumberOfSuggestionsShown.PaymentMethod"/>
   <affected-histogram
       name="PaymentRequest.NumberOfSuggestionsShown.ShippingAddress"/>
 </histogram_suffixes>
@@ -97572,8 +97629,14 @@
 <histogram_suffixes name="PaymentRequestSection" separator=".">
   <suffix name="ContactInfo"
       label="For the contact info section of a Payment Request"/>
+  <suffix name="PaymentMethod"
+      label="For the payment method section of a Payment Request"/>
   <suffix name="CreditCards"
-      label="For the credit card section of a Payment Request"/>
+      label="For the payment method section of a Payment Request">
+    <obsolete>
+      Renamed to PaymentMethod.
+    </obsolete>
+  </suffix>
   <suffix name="ShippingAddress"
       label="For the shipping address section of a Payment Request"/>
   <affected-histogram name="PaymentRequest.NumberOfSelectionAdds"/>
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index 71cd4889..dc4fef9 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -100,6 +100,12 @@
     battor #Flaky on android, crbug.com/618330.
 }
 
+# The list of benchmark names to be excluded from our smoke tests.
+_BLACK_LIST_TEST_NAMES = [
+   'memory.long_running_idle_gmail_background_tbmv2',
+   'tab_switching.typical_25',
+]
+
 
 def MergeDecorators(method, method_attribute, benchmark, benchmark_attribute):
   # Do set union of attributes to eliminate duplicates.
@@ -124,6 +130,8 @@
   for benchmark in all_benchmarks:
     if sys.modules[benchmark.__module__] in _BLACK_LIST_TEST_MODULES:
       continue
+    if benchmark.Name() in _BLACK_LIST_TEST_NAMES:
+      continue
 
     class BenchmarkSmokeTest(unittest.TestCase):
       pass
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 4302cfb..20811b3 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -61,6 +61,9 @@
 // Padding space in pixels between pages.
 constexpr int kPagePadding = 40;
 
+// Extra page padding which ensures that the page break space for apps are 48px.
+constexpr int kExtraPagePdding = 36;
+
 // Preferred tile size when showing in fixed layout.
 constexpr int kPreferredTileWidth = 100;
 constexpr int kPreferredTileHeight = 100;
@@ -1303,22 +1306,24 @@
     gfx::Vector2d offset = CalculateTransitionOffset(view_index.page);
     const PaginationModel::Transition& transition =
         pagination_model_.transition();
-    // When transition is progressing, eliminate empty spaces between pages.
     if (is_fullscreen_app_list_enabled_ && transition.progress > 0) {
       const int current_page = pagination_model_.selected_page();
       const bool forward = transition.target_page > current_page ? true : false;
-      // When transiting to previous page, eliminate empty space from just
-      // previous page since only the previous page is visiable; vice versa.
+      // When transiting to previous page, ensure 48px page break space from
+      // just previous page since only the previous page could be visiable;
+      // and vice versa.
       if (!forward && view_index.page == current_page - 1) {
         if (view_index.page == 0) {
           offset.set_y(offset.y() + GetHeightOnTopOfAllAppsTiles(0) -
                        GetHeightOnTopOfAllAppsTiles(1) -
-                       2 * kTileVerticalPadding);
+                       2 * kTileVerticalPadding - kExtraPagePdding);
         } else {
-          offset.set_y(offset.y() + GetHeightOnTopOfAllAppsTiles(current_page));
+          offset.set_y(offset.y() + GetHeightOnTopOfAllAppsTiles(current_page) -
+                       kExtraPagePdding);
         }
       } else if (forward && view_index.page == current_page + 1) {
-        offset.set_y(offset.y() - GetHeightOnTopOfAllAppsTiles(current_page));
+        offset.set_y(offset.y() - GetHeightOnTopOfAllAppsTiles(current_page) +
+                     kExtraPagePdding);
       }
     }
     tile_slot.Offset(offset.x(), offset.y());
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 6cbddf10..c8a5c68 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -325,7 +325,7 @@
       NOTREACHED();
   }
 
-  SetSelected(focused_view_ == FOCUS_SEARCH_BOX);
+  SetSelected(search_box_->text().empty() && focused_view_ == FOCUS_SEARCH_BOX);
   return (focused_view_ < FOCUS_CONTENTS_VIEW);
 }
 
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index d3c9f35..444c32a4 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/task_scheduler/post_task.h"
+#include "build/build_config.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -108,14 +109,24 @@
 
 HeadlessSurfaceFactory::HeadlessSurfaceFactory(
     HeadlessWindowManager* window_manager)
-    : window_manager_(window_manager),
-      osmesa_implementation_(base::MakeUnique<GLOzoneOSMesa>()) {}
+    : window_manager_(window_manager) {
+#if !defined(OS_FUCHSIA)
+  osmesa_implementation_ = base::MakeUnique<GLOzoneOSMesa>();
+#endif
+}
 
 HeadlessSurfaceFactory::~HeadlessSurfaceFactory() {}
 
 std::vector<gl::GLImplementation>
 HeadlessSurfaceFactory::GetAllowedGLImplementations() {
+#if defined(OS_FUCHSIA)
+  // TODO(fuchsia): Enable this or a variant with EGL support when GPU/UI is
+  // available. (crbug.com/750943)
+  NOTIMPLEMENTED();
+  return std::vector<gl::GLImplementation>{};
+#else
   return std::vector<gl::GLImplementation>{gl::kGLImplementationOSMesaGL};
+#endif
 }
 
 GLOzone* HeadlessSurfaceFactory::GetGLOzone(
diff --git a/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html b/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
index 20d15055..ad9d19f 100644
--- a/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
+++ b/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
@@ -64,14 +64,14 @@
         outline: none;
       }
 
-      :host ::content .drawer-content {
+      :host ::slotted(.drawer-content) {
         height: calc(100% - 56px);
         overflow: auto;
       }
     </style>
     <div id="container" on-tap="onContainerTap_">
       <div class="drawer-header" tabindex="-1">[[heading]]</div>
-      <content></content>
+      <slot></slot>
     </div>
   </template>
 </dom-module>