diff --git a/AUTHORS b/AUTHORS
index 19822d3a1..f13a007 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -74,6 +74,7 @@
 Andrei Parvu <parvu@adobe.com>
 Andrew Boyarshin <andrew.boyarshin@gmail.com>
 Andrew Brampton <me@bramp.net>
+Andrew Brindamour <abrindamour@bluejeans.com>
 Andrew Hung <andrhung@amazon.com>
 Andrew Jorgensen <ajorgens@amazon.com>
 Andrew MacPherson <andrew.macpherson@soundtrap.com>
@@ -421,6 +422,7 @@
 Jianneng Zhong <muzuiget@gmail.com>
 Jiawei Shao <jiawei.shao@intel.com>
 Jie Chen <jie.a.chen@intel.com>
+Jihan Chao <jihan@bluejeans.com>
 Jihoon Chung <j.c@navercorp.com>
 Jihoon Chung <jihoon@gmail.com>
 Jihun Brent Kim <devgrapher@gmail.com>
diff --git a/DEPS b/DEPS
index b804e8b2..b96fbfe5 100644
--- a/DEPS
+++ b/DEPS
@@ -162,11 +162,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '6be3ea7a7d72a6a76efcbedf67dbfde465b1a9d9',
+  'skia_revision': '86c39c71262de1147983e53625be1cb11c0650c3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6b93116584d01dc06c27975d3968739f2961b91d',
+  'v8_revision': 'b132e5cc433a3ebc085adf14f07c03db046ffdf2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -174,11 +174,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'c3f7873b9a3af998ec6e9132f07f331f3f14d306',
+  'angle_revision': '1f6f69209ec2d5190df405f1ad275a692e005b68',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'fbc146e97f30e49db4b228fb625707dfd52525e5',
+  'swiftshader_revision': 'cdb4549b571ba053d78623518e0d8a9ad16a62bd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -225,7 +225,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'e7c719c3e85f76938bf4fef0ba37c27f89246f71',
+  'catapult_revision': '2e1d9ff85e0a54a39f55d656086ff00a830cb7a9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -281,7 +281,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '2c5ed16ba97d84797190a9637e956cf21d9795e1',
+  'spv_tools_revision': '9b3cc3e05337358d0bd9fec1b7a51e3cbf55312b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -293,11 +293,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '4c187a619111f99ed4f3795374a96ede49ceb601',
+  'shaderc_revision': 'febf7e9ef53660247442dccb1fcf608bf734dead',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'ce2adba679a3b2511f153a75c0f9ebff44d41bdb',
+  'dawn_revision': 'f5c44772a6999a37760f6b67ee73b33876e8f7a9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -842,7 +842,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ac9e322afcdccc237f4dcb0136420a0adeb3965f',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7a63ee7f8a8b750b8d228d6b55f9e57e74a4e68c',
       'condition': 'checkout_linux',
   },
 
@@ -1246,7 +1246,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '042f99bcb1d4e2b4d2bbc0710ef96187d79a9545',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b1de0c8d6a36893d4b441b47429c9096945df0d6',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1455,7 +1455,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f4e32bb255038d6ca3969595daad3797292aeb4b',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@154adeb6c99862c349d309ca164be02da1b18706',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index d9dcdaa..0c96c75 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -2233,7 +2233,9 @@
 
 // Tests that the shelf animates to the auto hidden bounds after a swipe down
 // on the visible shelf.
-TEST_F(ShelfLayoutManagerTest, ShelfAnimatesToHiddenWhenGestureOutComplete) {
+// TODO(https://crbug.com/1000463): Flaky.
+TEST_F(ShelfLayoutManagerTest,
+       DISABLED_ShelfAnimatesToHiddenWhenGestureOutComplete) {
   Shelf* shelf = GetPrimaryShelf();
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc
index 991576c..f4950ad 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer.cc
@@ -13,22 +13,6 @@
 
 namespace base {
 
-namespace internal {
-
-// TODO(crbug.com/942512): Remove the feature after the M77 branch.
-const Feature kPartitionAllocPeriodicDecommit{"PartitionAllocPeriodicDecommit",
-                                              FEATURE_ENABLED_BY_DEFAULT};
-
-}  // namespace internal
-
-namespace {
-
-bool IsDeprecatedDecommitEnabled() {
-  return !FeatureList::IsEnabled(internal::kPartitionAllocPeriodicDecommit);
-}
-
-}  // namespace
-
 constexpr TimeDelta PartitionAllocMemoryReclaimer::kStatsRecordingTimeDelta;
 
 // static
@@ -63,9 +47,6 @@
     DCHECK(!partitions_.empty());
   }
 
-  if (!FeatureList::IsEnabled(internal::kPartitionAllocPeriodicDecommit))
-    return;
-
   // This does not need to run on the main thread, however there are a few
   // reasons to do it there:
   // - Most of PartitionAlloc's usage is on the main thread, hence PA's metadata
@@ -122,13 +103,6 @@
     total_reclaim_thread_time_ += timer.Elapsed();
 }
 
-void PartitionAllocMemoryReclaimer::DeprecatedReclaim() {
-  if (!IsDeprecatedDecommitEnabled())
-    return;
-
-  Reclaim();
-}
-
 void PartitionAllocMemoryReclaimer::RecordStatistics() {
   if (!ElapsedThreadTimer().is_supported())
     return;
diff --git a/base/allocator/partition_allocator/memory_reclaimer.h b/base/allocator/partition_allocator/memory_reclaimer.h
index eca30a7..8d520db1 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.h
+++ b/base/allocator/partition_allocator/memory_reclaimer.h
@@ -10,7 +10,6 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/no_destructor.h"
 #include "base/single_thread_task_runner.h"
@@ -25,8 +24,6 @@
 
 struct PartitionRootBase;
 
-BASE_EXPORT extern const Feature kPartitionAllocPeriodicDecommit;
-
 }  // namespace internal
 
 // Posts and handles memory reclaim tasks for PartitionAlloc.
@@ -52,8 +49,6 @@
   void Start(scoped_refptr<SequencedTaskRunner> task_runner);
   // Triggers an explicit reclaim now.
   void Reclaim();
-  // Triggers a reclaim. Do not add new callers.
-  void DeprecatedReclaim();
 
   static constexpr TimeDelta kStatsRecordingTimeDelta =
       TimeDelta::FromMinutes(5);
diff --git a/base/allocator/partition_allocator/memory_reclaimer_unittest.cc b/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
index b68dc38..72c72011 100644
--- a/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
@@ -9,7 +9,6 @@
 
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -62,10 +61,6 @@
 };
 
 TEST_F(PartitionAllocMemoryReclaimerTest, Simple) {
-  test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      internal::kPartitionAllocPeriodicDecommit);
-
   StartReclaimer();
 
   EXPECT_EQ(GetExpectedTasksCount(),
@@ -78,14 +73,6 @@
   EXPECT_EQ(2u, task_environment_.GetPendingMainThreadTaskCount());
 }
 
-TEST_F(PartitionAllocMemoryReclaimerTest, CanBeDisabled) {
-  test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      internal::kPartitionAllocPeriodicDecommit);
-  StartReclaimer();
-  EXPECT_EQ(0u, task_environment_.GetPendingMainThreadTaskCount());
-}
-
 TEST_F(PartitionAllocMemoryReclaimerTest, FreesMemory) {
   PartitionRootGeneric* root = allocator_->root();
 
@@ -120,33 +107,6 @@
   }
 }
 
-TEST_F(PartitionAllocMemoryReclaimerTest, DeprecatedReclaim) {
-  PartitionRootGeneric* root = allocator_->root();
-
-  // Deprecated reclaim is disabled by default.
-  {
-    AllocateAndFree();
-    size_t committed_before = root->total_size_of_committed_pages;
-    PartitionAllocMemoryReclaimer::Instance()->DeprecatedReclaim();
-    size_t committed_after = root->total_size_of_committed_pages;
-    EXPECT_EQ(committed_after, committed_before);
-
-    PartitionAllocMemoryReclaimer::Instance()->Reclaim();
-  }
-
-  // Deprecated reclaim works when periodic reclaim is disabled.
-  {
-    test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitAndDisableFeature(
-        internal::kPartitionAllocPeriodicDecommit);
-    AllocateAndFree();
-    size_t committed_before = root->total_size_of_committed_pages;
-    PartitionAllocMemoryReclaimer::Instance()->DeprecatedReclaim();
-    size_t committed_after = root->total_size_of_committed_pages;
-    EXPECT_LT(committed_after, committed_before);
-  }
-}
-
 TEST_F(PartitionAllocMemoryReclaimerTest, StatsRecording) {
   // No stats reported if the timer is not.
   if (!ElapsedThreadTimer().is_supported())
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java b/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java
index 04b5adf8..28c5ec94 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java
@@ -4,15 +4,10 @@
 
 package org.chromium.base.library_loader;
 
-import android.annotation.SuppressLint;
-import android.content.Context;
-
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.Log;
 import org.chromium.base.SysUtils;
 import org.chromium.base.TraceEvent;
-import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.annotations.NativeMethods;
@@ -20,8 +15,6 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -33,27 +26,6 @@
 @MainDex
 @JNINamespace("base::android")
 public class LibraryPrefetcher {
-    /**
-     * Used to pass ordered code info back from native.
-     */
-    final static class OrderedCodeInfo {
-        public final String filename;
-        public final long startOffset;
-        public final long length;
-
-        @CalledByNative("OrderedCodeInfo")
-        public OrderedCodeInfo(String filename, long startOffset, long length) {
-            this.filename = filename;
-            this.startOffset = startOffset;
-            this.length = length;
-        }
-
-        @Override
-        public String toString() {
-            return "filename = " + filename + " startOffset = " + startOffset
-                    + " length = " + length;
-        }
-    }
 
     private static final String TAG = "LibraryPrefetcher";
     // One-way switch that becomes true once
@@ -104,40 +76,6 @@
         });
     }
 
-    // May pin Chrome's code to memory, on platforms that support it.
-    @SuppressLint("WrongConstant")
-    public static void maybePinOrderedCodeInMemory() {
-        try (TraceEvent e = TraceEvent.scoped("LibraryPrefetcher::maybePinOrderedCodeInMemory")) {
-            OrderedCodeInfo info = LibraryPrefetcherJni.get().getOrderedCodeInfo();
-            if (info == null) return;
-            TraceEvent.instant("pinOrderedCodeInMemory", info.toString());
-
-            Context context = ContextUtils.getApplicationContext();
-            Object pinner = context.getSystemService("pinner");
-            if (pinner == null) {
-                Log.w(TAG, "Cannot get PinnerService.");
-                return;
-            }
-
-            // Reflection is required because the method is neither visible in the platform, nor
-            // available everywhere.
-            try {
-                Method pinRangeFromFile = pinner.getClass().getMethod(
-                        "pinRangeFromFile", String.class, int.class, int.class);
-                boolean ok = (Boolean) pinRangeFromFile.invoke(
-                        pinner, info.filename, (int) info.startOffset, (int) info.length);
-                if (!ok) {
-                    Log.e(TAG, "Not allowed to call the method, should not happen");
-                } else {
-                    Log.i(TAG, "Successfully pinned ordered code");
-                }
-            } catch (
-                    NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
-                Log.w(TAG, "Error invoking the method. " + ex.getMessage());
-            }
-        }
-    }
-
     @NativeMethods
     interface Natives {
         // Finds the ranges corresponding to the native library pages, forks a new
@@ -151,9 +89,5 @@
 
         // Periodically logs native library residency from this thread.
         void periodicallyCollectResidency();
-
-        // Returns the range within a file of the ordered code section, or null if this is not
-        // available.
-        OrderedCodeInfo getOrderedCodeInfo();
     }
 }
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index ae08d77..bab0171 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -19,7 +19,6 @@
 #include "base/android/library_loader/anchor_functions.h"
 #include "base/android/orderfile/orderfile_buildflags.h"
 #include "base/bits.h"
-#include "base/debug/proc_maps_linux.h"
 #include "base/files/file.h"
 #include "base/format_macros.h"
 #include "base/logging.h"
@@ -346,54 +345,6 @@
   MadviseOnRange(GetTextRange(), MADV_RANDOM);
 }
 
-// static
-bool NativeLibraryPrefetcher::GetOrderedCodeInfo(std::string* filename,
-                                                 size_t* start_offset,
-                                                 size_t* size) {
-  // Need all the anchors to identify the range.
-  if (!IsOrderingSane()) {
-    LOG(WARNING) << "Incorrect code ordering";
-    return false;
-  }
-
-  std::vector<base::debug::MappedMemoryRegion> regions;
-  {
-    std::string proc_maps;
-    bool ok = base::debug::ReadProcMaps(&proc_maps);
-    if (!ok)
-      return false;
-    ok = base::debug::ParseProcMaps(proc_maps, &regions);
-    if (!ok)
-      return false;
-  }
-
-  for (const auto& region : regions) {
-    if (region.start <= kStartOfOrderedText &&
-        region.end >= kEndOfOrderedText) {
-      size_t page_size = GetPageSize();
-      size_t page_mask = ~(page_size - 1);
-
-      DCHECK_EQ(0u, region.start % page_size);
-      DCHECK_EQ(0u, region.offset % page_size);  // mmap() enforces this.
-
-      size_t start_offset_in_range =
-          (kStartOfOrderedText & page_mask) - region.start;
-      DCHECK_EQ(0u, start_offset_in_range % page_size);
-      size_t start_offset_in_file = start_offset_in_range + region.offset;
-      DCHECK_EQ(0u, start_offset_in_file % page_size);
-
-      *filename = region.path;
-      *start_offset = start_offset_in_file;
-      *size =
-          base::bits::Align(kEndOfOrderedText - kStartOfOrderedText, page_size);
-      return true;
-    }
-  }
-
-  LOG(WARNING) << "Didn't find the ordered code, yet code is ordered.";
-  return false;
-}
-
 }  // namespace android
 }  // namespace base
 #endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
index 1b0fc6a3..2f302a8 100644
--- a/base/android/library_loader/library_prefetcher.h
+++ b/base/android/library_loader/library_prefetcher.h
@@ -52,11 +52,6 @@
   // collection is accurate.
   static void MadviseForResidencyCollection();
 
-  // Returns true for success.
-  static bool GetOrderedCodeInfo(std::string* filename,
-                                 size_t* start_offset,
-                                 size_t* size);
-
  private:
   // Returns the percentage of [start, end] currently resident in
   // memory, or -1 in case of error.
diff --git a/base/android/library_loader/library_prefetcher_hooks.cc b/base/android/library_loader/library_prefetcher_hooks.cc
index 450797d..579bb54e 100644
--- a/base/android/library_loader/library_prefetcher_hooks.cc
+++ b/base/android/library_loader/library_prefetcher_hooks.cc
@@ -11,21 +11,11 @@
 #include "base/android/library_loader/library_prefetcher.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/base_jni_headers/LibraryPrefetcher_jni.h"
-#include "base/feature_list.h"
 #include "base/logging.h"
 
 namespace base {
 namespace android {
 
-namespace {
-
-// Whether to pin code in memory. Pinning happens in Java, but is controlled
-// from here, to obtain the range.
-const Feature kPinOrderedCodeInMemory{"PinOrderedCodeInMemory",
-                                      FEATURE_ENABLED_BY_DEFAULT};
-
-}  // namespace
-
 static void JNI_LibraryPrefetcher_ForkAndPrefetchNativeLibrary(JNIEnv* env) {
 #if BUILDFLAG(SUPPORTS_CODE_ORDERING)
   return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(
@@ -50,27 +40,5 @@
 #endif
 }
 
-static ScopedJavaLocalRef<jobject> JNI_LibraryPrefetcher_GetOrderedCodeInfo(
-    JNIEnv* env) {
-#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
-  if (!FeatureList::IsEnabled(kPinOrderedCodeInMemory))
-    return {};
-
-  std::string filename;
-  size_t start_offset, size;
-  bool ok = NativeLibraryPrefetcher::GetOrderedCodeInfo(&filename,
-                                                        &start_offset, &size);
-  if (!ok)
-    return {};
-
-  auto java_filename = ConvertUTF8ToJavaString(env, filename);
-  return Java_OrderedCodeInfo_Constructor(env, java_filename,
-                                          static_cast<jlong>(start_offset),
-                                          static_cast<jlong>(size));
-#else
-  return {};
-#endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
-}
-
 }  // namespace android
 }  // namespace base
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index c2ccdad1..cc760ff 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -85,18 +85,6 @@
 // for tests. TODO(https://crbug.com/891670/) remove this class.
 class BASE_EXPORT MessageLoop {
  public:
-  // DEPRECATED: Use MessagePumpType instead
-  using Type = MessagePumpType;
-
-  // DEPRECATED: Use MessagePumpType::* instead
-  static constexpr Type TYPE_DEFAULT = Type::DEFAULT;
-  static constexpr Type TYPE_UI = Type::UI;
-  static constexpr Type TYPE_CUSTOM = Type::CUSTOM;
-  static constexpr Type TYPE_IO = Type::IO;
-#if defined(OS_ANDROID)
-  static constexpr Type TYPE_JAVA = Type::JAVA;
-#endif  // defined(OS_ANDROID)
-
   // Normally, it is not necessary to instantiate a MessageLoop.  Instead, it
   // is typical to make use of the current thread's MessageLoop instance.
   explicit MessageLoop(MessagePumpType type = MessagePumpType::DEFAULT);
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
index 1cb1a21..b8dc052a 100644
--- a/base/message_loop/message_pump.h
+++ b/base/message_loop/message_pump.h
@@ -21,7 +21,7 @@
  public:
   using MessagePumpFactory = std::unique_ptr<MessagePump>();
   // Uses the given base::MessagePumpFactory to override the default MessagePump
-  // implementation for 'Type::UI'. May only be called once.
+  // implementation for 'MessagePumpType::UI'. May only be called once.
   static void OverrideMessagePumpForUIFactory(MessagePumpFactory* factory);
 
   // Returns true if the MessagePumpForUI has been overidden.
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.cc b/base/test/launcher/test_launcher_nacl_nonsfi.cc
index 7423dac4..699a0622 100644
--- a/base/test/launcher/test_launcher_nacl_nonsfi.cc
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.cc
@@ -10,13 +10,14 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_type.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
+#include "base/task/single_thread_task_executor.h"
 #include "base/test/launcher/test_launcher.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_switches.h"
@@ -144,9 +145,9 @@
 
   TestTimeouts::Initialize();
 
-  base::MessageLoopForIO message_loop;
+  base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO);
 #if defined(OS_POSIX)
-  FileDescriptorWatcher file_descriptor_watcher(message_loop.task_runner());
+  FileDescriptorWatcher file_descriptor_watcher(executor.task_runner());
 #endif
 
   NonSfiUnitTestPlatformDelegate platform_delegate;
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index c9c0860..e0a21fc 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -18,7 +18,7 @@
 #include "base/format_macros.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_type.h"
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
@@ -26,6 +26,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
+#include "base/task/single_thread_task_executor.h"
 #include "base/test/launcher/test_launcher.h"
 #include "base/test/test_switches.h"
 #include "base/test/test_timeouts.h"
@@ -182,9 +183,9 @@
           "--single-process-tests.\n");
   fflush(stdout);
 
-  MessageLoopForIO message_loop;
+  base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO);
 #if defined(OS_POSIX)
-  FileDescriptorWatcher file_descriptor_watcher(message_loop.task_runner());
+  FileDescriptorWatcher file_descriptor_watcher(executor.task_runner());
 #endif
   use_job_objects =
       use_job_objects &&
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index fe78ec3..3a104fee 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8903293567242691744
\ No newline at end of file
+8903266443942383680
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index a83a27c..c92bb2d 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8903295702729103200
\ No newline at end of file
+8903268928406149760
\ No newline at end of file
diff --git a/cc/resources/shared_bitmap_id_registrar.cc b/cc/resources/shared_bitmap_id_registrar.cc
index 8ab3886..89a3b190 100644
--- a/cc/resources/shared_bitmap_id_registrar.cc
+++ b/cc/resources/shared_bitmap_id_registrar.cc
@@ -21,10 +21,10 @@
 }
 
 SharedBitmapIdRegistration::SharedBitmapIdRegistration(
-    SharedBitmapIdRegistration&&) = default;
+    SharedBitmapIdRegistration&&) noexcept = default;
 
 SharedBitmapIdRegistration& SharedBitmapIdRegistration::operator=(
-    SharedBitmapIdRegistration&& other) {
+    SharedBitmapIdRegistration&& other) noexcept {
   if (layer_ptr_)
     layer_ptr_->UnregisterSharedBitmapId(id_);
   layer_ptr_ = std::move(other.layer_ptr_);
diff --git a/cc/resources/shared_bitmap_id_registrar.h b/cc/resources/shared_bitmap_id_registrar.h
index 6abb30e..8fa9a8cb 100644
--- a/cc/resources/shared_bitmap_id_registrar.h
+++ b/cc/resources/shared_bitmap_id_registrar.h
@@ -50,12 +50,12 @@
  public:
   SharedBitmapIdRegistration();
   SharedBitmapIdRegistration(const SharedBitmapIdRegistration&) = delete;
-  SharedBitmapIdRegistration(SharedBitmapIdRegistration&&);
+  SharedBitmapIdRegistration(SharedBitmapIdRegistration&&) noexcept;
   ~SharedBitmapIdRegistration();
 
   SharedBitmapIdRegistration& operator=(const SharedBitmapIdRegistration&) =
       delete;
-  SharedBitmapIdRegistration& operator=(SharedBitmapIdRegistration&&);
+  SharedBitmapIdRegistration& operator=(SharedBitmapIdRegistration&&) noexcept;
 
  private:
   // Constructed by TextureLayer only, then held by the client as long
diff --git a/chrome/android/features/start_surface/internal/java/res/color/ss_normal_bottom_button_tint.xml b/chrome/android/features/start_surface/internal/java/res/color/ss_normal_bottom_button_tint.xml
deleted file mode 100644
index 48d75983..0000000
--- a/chrome/android/features/start_surface/internal/java/res/color/ss_normal_bottom_button_tint.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2014 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="@color/default_icon_color_disabled" />
-    <item android:state_selected="true" android:color="@color/light_active_color" />
-    <item android:state_focused="true" android:color="@color/light_active_color" />
-    <item android:state_pressed="true" android:color="@color/light_active_color" />
-    <item android:state_activated="true" android:color="@color/default_icon_color" />
-    <item android:color="@color/default_icon_color"/>
-</selector>
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarView.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarView.java
index 3e77d6fb..01080276 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarView.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarView.java
@@ -5,25 +5,18 @@
 package org.chromium.chrome.features.start_surface;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.support.design.widget.TabLayout;
-import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.start_surface.R;
 import org.chromium.ui.widget.ChromeImageView;
 
 /** The bottom bar view. */
+// TODO(crbug.com/982018): Support dark mode.
 class BottomBarView extends FrameLayout {
-    private final ColorStateList mNormalButtonTintColor;
-    private final ColorStateList mNormalIndicatorColor;
-    private final ColorStateList mIncognitoButtonTintColor;
-    private final ColorStateList mIncognitoIndicatorColor;
 
     private TabLayout mTabLayout;
     private TabLayout.Tab mHomeTab;
@@ -36,15 +29,6 @@
 
     public BottomBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        mNormalIndicatorColor =
-                AppCompatResources.getColorStateList(context, R.color.light_active_color);
-        mNormalButtonTintColor =
-                AppCompatResources.getColorStateList(context, R.color.ss_normal_bottom_button_tint);
-        mIncognitoButtonTintColor =
-                AppCompatResources.getColorStateList(context, R.color.white_alpha_70);
-        mIncognitoIndicatorColor =
-                AppCompatResources.getColorStateList(context, R.color.white_mode_tint);
     }
 
     @Override
@@ -54,10 +38,6 @@
         mTabLayout = (TabLayout) findViewById(R.id.bottom_tab_layout);
         mHomeTab = mTabLayout.getTabAt(0);
         mExploreTab = mTabLayout.getTabAt(1);
-        mHomeButton = (ChromeImageView) mTabLayout.findViewById(R.id.ss_home_button);
-        mHomeButtonLabel = (TextView) mTabLayout.findViewById(R.id.ss_home_button_label);
-        mExploreButton = (ChromeImageView) mTabLayout.findViewById(R.id.ss_explore_button);
-        mExploreButtonLabel = (TextView) mTabLayout.findViewById(R.id.ss_explore_button_label);
 
         mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
             @Override
@@ -83,30 +63,6 @@
     }
 
     /**
-     * Set the incognito state.
-     * @param isIncognito Whether is in incognito mode.
-     */
-    public void setIncognito(boolean isIncognito) {
-        // TODO(crbug.com/982018): Support dark mode.
-        setBackgroundColor(
-                ColorUtils.getPrimaryBackgroundColor(getContext().getResources(), isIncognito));
-        if (isIncognito) {
-            // TODO(crbug.com/982018): Distinguish selected and unselected state in incognito mode.
-            mTabLayout.setSelectedTabIndicatorColor(mIncognitoIndicatorColor.getDefaultColor());
-            ApiCompatibilityUtils.setImageTintList(mHomeButton, mIncognitoButtonTintColor);
-            mHomeButtonLabel.setTextColor(mIncognitoButtonTintColor);
-            ApiCompatibilityUtils.setImageTintList(mExploreButton, mIncognitoButtonTintColor);
-            mExploreButtonLabel.setTextColor(mIncognitoButtonTintColor);
-        } else {
-            mTabLayout.setSelectedTabIndicatorColor(mNormalIndicatorColor.getDefaultColor());
-            ApiCompatibilityUtils.setImageTintList(mHomeButton, mNormalButtonTintColor);
-            mHomeButtonLabel.setTextColor(mNormalButtonTintColor);
-            ApiCompatibilityUtils.setImageTintList(mExploreButton, mNormalButtonTintColor);
-            mExploreButtonLabel.setTextColor(mNormalButtonTintColor);
-        }
-    }
-
-    /**
      * Set the visibility of this bottom bar.
      * @param shown Whether set the visibility to visible or not.
      */
@@ -132,4 +88,4 @@
         if (index == mTabLayout.getSelectedTabPosition()) return;
         mTabLayout.getTabAt(index).select();
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarViewBinder.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarViewBinder.java
index 7b68306..5fc77f9 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarViewBinder.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/BottomBarViewBinder.java
@@ -6,7 +6,7 @@
 
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_CLICKLISTENER;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_SELECTED_TAB_POSITION;
-import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_INCOGNITO;
+import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_BOTTOM_BAR_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
 
 import org.chromium.ui.modelutil.PropertyKey;
@@ -19,10 +19,10 @@
             view.setOnClickListener(model.get(BOTTOM_BAR_CLICKLISTENER));
         } else if (BOTTOM_BAR_SELECTED_TAB_POSITION == propertyKey) {
             view.selectTabAt(model.get(BOTTOM_BAR_SELECTED_TAB_POSITION));
-        } else if (IS_INCOGNITO == propertyKey) {
-            view.setIncognito(model.get(IS_INCOGNITO));
+        } else if (IS_BOTTOM_BAR_VISIBLE == propertyKey) {
+            view.setVisibility(model.get(IS_SHOWING_OVERVIEW) && model.get(IS_BOTTOM_BAR_VISIBLE));
         } else if (IS_SHOWING_OVERVIEW == propertyKey) {
-            view.setVisibility(model.get(IS_SHOWING_OVERVIEW));
+            view.setVisibility(model.get(IS_SHOWING_OVERVIEW) && model.get(IS_BOTTOM_BAR_VISIBLE));
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
index 061c27c4..1b4b790 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
@@ -37,10 +37,9 @@
     interface FeedSurfaceCreator {
         /**
          * Creates the {@link FeedSurfaceCoordinator} for the specified mode.
-         * @param isIncognito Whether it is in incognito mode.
          * @return The {@link FeedSurfaceCoordinator}.
          */
-        FeedSurfaceCoordinator createFeedSurfaceCoordinator(boolean isIncognito);
+        FeedSurfaceCoordinator createFeedSurfaceCoordinator();
     }
 
     ExploreSurfaceCoordinator(ChromeActivity activity, ViewGroup parentView,
@@ -57,8 +56,8 @@
                 ExploreSurfaceViewBinder::bind);
         mFeedSurfaceCreator = new FeedSurfaceCreator() {
             @Override
-            public FeedSurfaceCoordinator createFeedSurfaceCoordinator(boolean isIncognito) {
-                return internalCreateFeedSurfaceCoordinator(isIncognito);
+            public FeedSurfaceCoordinator createFeedSurfaceCoordinator() {
+                return internalCreateFeedSurfaceCoordinator();
             }
         };
     }
@@ -82,22 +81,19 @@
         return false;
     }
 
-    private FeedSurfaceCoordinator internalCreateFeedSurfaceCoordinator(boolean isIncognito) {
+    private FeedSurfaceCoordinator internalCreateFeedSurfaceCoordinator() {
         if (mExploreSurfaceNavigationDelegate == null)
             mExploreSurfaceNavigationDelegate = new ExploreSurfaceNavigationDelegate(mActivity);
-        mExploreSurfaceNavigationDelegate.setIncognito(isIncognito);
 
         ExploreSurfaceActionHandler exploreSurfaceActionHandler =
                 new ExploreSurfaceActionHandler(mExploreSurfaceNavigationDelegate,
                         FeedProcessScopeFactory.getFeedConsumptionObserver(),
                         FeedProcessScopeFactory.getFeedOfflineIndicator(),
-                        OfflinePageBridge.getForProfile(isIncognito
-                                        ? Profile.getLastUsedProfile().getOffTheRecordProfile()
-                                        : Profile.getLastUsedProfile()),
+                        OfflinePageBridge.getForProfile(Profile.getLastUsedProfile()),
                         FeedProcessScopeFactory.getFeedLoggingBridge());
         return new FeedSurfaceCoordinator(
-                mActivity, null, null, null, exploreSurfaceActionHandler, isIncognito, this);
+                mActivity, null, null, null, exploreSurfaceActionHandler, false, this);
         // TODO(crbug.com/982018): Customize surface background for incognito and dark mode.
         // TODO(crbug.com/982018): Hide signin promo UI in incognito mode.
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceNavigationDelegate.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceNavigationDelegate.java
index 8de5396b..55ad511d 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceNavigationDelegate.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceNavigationDelegate.java
@@ -21,7 +21,6 @@
 /** Implementation of the {@link NativePageNavigationDelegate} for the explore surface. */
 class ExploreSurfaceNavigationDelegate implements NativePageNavigationDelegate {
     private final Context mContext;
-    private boolean mIsInCognito;
 
     ExploreSurfaceNavigationDelegate(Context context) {
         mContext = context;
@@ -43,9 +42,7 @@
         CustomTabsIntent customTabsIntent = builder.build();
         customTabsIntent.intent.setPackage(mContext.getPackageName());
         customTabsIntent.intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB,
-                (windowOpenDisposition == WindowOpenDisposition.OFF_THE_RECORD || mIsInCognito)
-                        ? true
-                        : false);
+                (windowOpenDisposition == WindowOpenDisposition.OFF_THE_RECORD) ? true : false);
         customTabsIntent.intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
         customTabsIntent.launchUrl(mContext, Uri.parse(loadUrlParams.getUrl()));
 
@@ -53,8 +50,4 @@
         // mode accordingly (note that payment window supports incognito mode).
         return null;
     }
-
-    public void setIncognito(boolean isIncognito) {
-        mIsInCognito = isIncognito;
-    }
 }
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java
index 08c5dd6..af43eacf 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java
@@ -45,16 +45,11 @@
 
     public static void bind(PropertyModel model, ViewHolder view, PropertyKey propertyKey) {
         if (propertyKey == IS_EXPLORE_SURFACE_VISIBLE) {
-            setVisibility(view, model, model.get(IS_EXPLORE_SURFACE_VISIBLE));
+            setVisibility(view, model,
+                    model.get(IS_EXPLORE_SURFACE_VISIBLE) && model.get(IS_SHOWING_OVERVIEW));
         } else if (propertyKey == IS_SHOWING_OVERVIEW) {
-            if (!model.get(IS_EXPLORE_SURFACE_VISIBLE)) return;
-
-            if (model.get(IS_SHOWING_OVERVIEW)) {
-                // Set the initial state if the explore surface is selected previously.
-                setVisibility(view, model, true);
-            } else {
-                setVisibility(view, model, false);
-            }
+            setVisibility(view, model,
+                    model.get(IS_EXPLORE_SURFACE_VISIBLE) && model.get(IS_SHOWING_OVERVIEW));
         }
     }
 
@@ -103,4 +98,4 @@
             UiUtils.removeViewFromParent(feedSurfaceView);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index d1d42c4..0181bbfd 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -5,14 +5,12 @@
 package org.chromium.chrome.features.start_surface;
 
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MORE_TABS_CLICK_LISTENER;
-import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_HEIGHT;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_BAR_HEIGHT;
 
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import android.view.ViewGroup;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
@@ -193,7 +191,11 @@
         }
 
         mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
-        if (mSurfaceMode == SurfaceMode.TWO_PANES) createAndSetBottomBar();
+
+        if (mSurfaceMode == SurfaceMode.TWO_PANES) {
+            mBottomBarCoordinator = new BottomBarCoordinator(
+                    mActivity, mActivity.getCompositorViewHolder(), mPropertyModel);
+        }
 
         int toolbarHeight =
                 mActivity.getResources().getDimensionPixelSize(R.dimen.toolbar_height_no_shadow);
@@ -217,19 +219,6 @@
                 mPropertyModel);
     }
 
-    private void createAndSetBottomBar() {
-        // Margin the bottom of the Tab grid to save space for the bottom bar.
-        int bottomBarHeight =
-                ContextUtils.getApplicationContext().getResources().getDimensionPixelSize(
-                        R.dimen.ss_bottom_bar_height);
-        mTasksSurface.getTabListDelegate().setBottomControlsHeight(bottomBarHeight);
-        mPropertyModel.set(BOTTOM_BAR_HEIGHT, bottomBarHeight);
-
-        // Create the bottom bar.
-        mBottomBarCoordinator = new BottomBarCoordinator(
-                mActivity, mActivity.getCompositorViewHolder(), mPropertyModel);
-    }
-
     private TabSwitcher.Controller initializeSecondaryTasksSurface() {
         assert mSurfaceMode == SurfaceMode.SINGLE_PANE;
         assert mSecondaryTasksSurface == null;
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 3c4c7f2c..52f1a54 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -5,15 +5,17 @@
 package org.chromium.chrome.features.start_surface;
 
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_CLICKLISTENER;
+import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_HEIGHT;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_SELECTED_TAB_POSITION;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.FEED_SURFACE_COORDINATOR;
+import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_BOTTOM_BAR_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_EXPLORE_SURFACE_VISIBLE;
-import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_INCOGNITO;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
 
 import android.support.annotation.Nullable;
 import android.view.View;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.ObserverList;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
@@ -21,6 +23,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
+import org.chromium.chrome.start_surface.R;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** The mediator implements the logic to interact with the surfaces and caller. */
@@ -57,6 +60,7 @@
     private final boolean mOnlyShowExploreSurface;
     @Nullable
     private TabSwitcher.Controller mSecondaryTasksSurfaceController;
+    private boolean mIsIncognito;
 
     StartSurfaceMediator(TabSwitcher.Controller controller, TabModelSelector tabModelSelector,
             OverlayVisibilityHandler overlayVisibilityHandler,
@@ -92,6 +96,7 @@
                         }
                     });
 
+            mIsIncognito = tabModelSelector.isIncognitoSelected();
             tabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
                 @Override
                 public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
@@ -100,18 +105,24 @@
             });
 
             // Set the initial state.
-            updateIncognitoMode(tabModelSelector.isIncognitoSelected());
 
-            // Show explore surface if in TWO PANES mode and last visible pane was explore.
+            // Show explore surface if not in incognito and either in SINGLE PANES mode
+            // or in TWO PANES mode with last visible pane explore.
+            boolean shouldShowExploreSurface =
+                    (onlyShowExploreSurface || ReturnToStartSurfaceUtil.shouldShowExploreSurface())
+                    && !mIsIncognito;
+            setExploreSurfaceVisibility(shouldShowExploreSurface);
             if (!onlyShowExploreSurface) {
-                boolean shouldShowExploreSurface =
-                        ReturnToStartSurfaceUtil.shouldShowExploreSurface();
-                mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, shouldShowExploreSurface);
-                mPropertyModel.set(
-                        BOTTOM_BAR_SELECTED_TAB_POSITION, (shouldShowExploreSurface ? 1 : 0));
+                mPropertyModel.set(BOTTOM_BAR_HEIGHT,
+                        ContextUtils.getApplicationContext().getResources().getDimensionPixelSize(
+                                R.dimen.ss_bottom_bar_height));
+                mPropertyModel.set(IS_BOTTOM_BAR_VISIBLE, !mIsIncognito);
+
+                // Margin the bottom of the Tab grid to save space for the bottom bar when visible.
+                mController.setBottomControlsHeight(
+                        mIsIncognito ? 0 : mPropertyModel.get(BOTTOM_BAR_HEIGHT));
             }
         }
-
         mController.addOverviewModeObserver(this);
     }
 
@@ -137,7 +148,7 @@
                 && mSecondaryTasksSurfaceController.overviewVisible()) {
             assert mOnlyShowExploreSurface;
 
-            mSecondaryTasksSurfaceController.hideOverview(false);
+            setSecondaryTasksSurfaceVisibility(false);
         }
         mController.hideOverview(animate);
     }
@@ -150,7 +161,11 @@
             // panes) available when mPropertyModel != null.
             if (mOnlyShowExploreSurface) {
                 RecordUserAction.record("StartSurface.SinglePane");
-                mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, true);
+                if (mIsIncognito) {
+                    setSecondaryTasksSurfaceVisibility(true);
+                } else {
+                    setExploreSurfaceVisibility(true);
+                }
             } else {
                 RecordUserAction.record("StartSurface.TwoPanes");
                 String defaultOnUserActionString = mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE)
@@ -165,8 +180,7 @@
             if (mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE)
                     && mPropertyModel.get(FEED_SURFACE_COORDINATOR) == null) {
                 mPropertyModel.set(FEED_SURFACE_COORDINATOR,
-                        mFeedSurfaceCreator.createFeedSurfaceCoordinator(
-                                mPropertyModel.get(IS_INCOGNITO)));
+                        mFeedSurfaceCreator.createFeedSurfaceCoordinator());
             }
             mPropertyModel.set(IS_SHOWING_OVERVIEW, true);
         }
@@ -177,10 +191,12 @@
     @Override
     public boolean onBackPressed() {
         if (mSecondaryTasksSurfaceController != null
-                && mSecondaryTasksSurfaceController.overviewVisible()) {
+                && mSecondaryTasksSurfaceController.overviewVisible()
+                // Secondary tasks surface is used as the main surface in incognito mode.
+                && !mIsIncognito) {
             assert mOnlyShowExploreSurface;
 
-            mSecondaryTasksSurfaceController.hideOverview(false);
+            setSecondaryTasksSurfaceVisibility(false);
             setExploreSurfaceVisibility(true);
             return true;
         }
@@ -239,7 +255,7 @@
         }
 
         setExploreSurfaceVisibility(false);
-        mSecondaryTasksSurfaceController.showOverview(false);
+        setSecondaryTasksSurfaceVisibility(true);
         RecordUserAction.record("StartSurface.SinglePane.MoreTabs");
     }
 
@@ -247,35 +263,41 @@
     private void setExploreSurfaceVisibility(boolean isVisible) {
         if (isVisible == mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE)) return;
 
-        if (isVisible && mPropertyModel.get(FEED_SURFACE_COORDINATOR) == null) {
-            mPropertyModel.set(FEED_SURFACE_COORDINATOR,
-                    mFeedSurfaceCreator.createFeedSurfaceCoordinator(
-                            mPropertyModel.get(IS_INCOGNITO)));
+        if (isVisible && mPropertyModel.get(IS_SHOWING_OVERVIEW)
+                && mPropertyModel.get(FEED_SURFACE_COORDINATOR) == null) {
+            mPropertyModel.set(
+                    FEED_SURFACE_COORDINATOR, mFeedSurfaceCreator.createFeedSurfaceCoordinator());
         }
 
         mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, isVisible);
 
-        // Update the 'BOTTOM_BAR_SELECTED_TAB_POSITION' property to reflect the change. This is
-        // needed when clicking back button on the explore surface.
-        mPropertyModel.set(BOTTOM_BAR_SELECTED_TAB_POSITION, isVisible ? 1 : 0);
-        ReturnToStartSurfaceUtil.setExploreSurfaceVisibleLast(isVisible);
+        if (!mOnlyShowExploreSurface) {
+            // Update the 'BOTTOM_BAR_SELECTED_TAB_POSITION' property to reflect the change. This is
+            // needed when clicking back button on the explore surface.
+            mPropertyModel.set(BOTTOM_BAR_SELECTED_TAB_POSITION, isVisible ? 1 : 0);
+            ReturnToStartSurfaceUtil.setExploreSurfaceVisibleLast(isVisible);
+        }
     }
 
     private void updateIncognitoMode(boolean isIncognito) {
-        if (isIncognito == mPropertyModel.get(IS_INCOGNITO)) return;
+        if (isIncognito == mIsIncognito) return;
+        mIsIncognito = isIncognito;
 
-        mPropertyModel.set(IS_INCOGNITO, isIncognito);
+        if (mOnlyShowExploreSurface) {
+            setExploreSurfaceVisibility(!mIsIncognito);
+            setSecondaryTasksSurfaceVisibility(
+                    mIsIncognito && mPropertyModel.get(IS_SHOWING_OVERVIEW));
+        } else {
+            mPropertyModel.set(IS_BOTTOM_BAR_VISIBLE, !mIsIncognito);
 
-        // Set invisible to remove the view from it's parent if it was showing and destroy the feed
-        // surface coordinator (no matter it was shown or not).
-        boolean wasShown = mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE)
-                && mPropertyModel.get(FEED_SURFACE_COORDINATOR) != null;
-        if (wasShown) setExploreSurfaceVisibility(false);
-        destroyFeedSurfaceCoordinator();
+            // Set bottom controls height to 0 when bottom bar is hidden in incogito mode
+            mController.setBottomControlsHeight(
+                    mIsIncognito ? 0 : mPropertyModel.get(BOTTOM_BAR_HEIGHT));
 
-        // Set visible if it was shown, which will build the new feed surface coordinator according
-        // to the new incognito state.
-        if (wasShown) setExploreSurfaceVisibility(true);
+            // Hide explore surface if going incognito. When returning to normal mode, we
+            // always show the Home Pane, so the Explore Pane stays hidden.
+            if (mIsIncognito) setExploreSurfaceVisibility(false);
+        }
     }
 
     private void destroyFeedSurfaceCoordinator() {
@@ -284,4 +306,17 @@
         if (feedSurfaceCoordinator != null) feedSurfaceCoordinator.destroy();
         mPropertyModel.set(FEED_SURFACE_COORDINATOR, null);
     }
+
+    private void setSecondaryTasksSurfaceVisibility(boolean isVisible) {
+        assert mOnlyShowExploreSurface;
+        if (isVisible) {
+            if (mSecondaryTasksSurfaceController == null) {
+                mSecondaryTasksSurfaceController = mSecondaryTasksSurfaceInitializer.initialize();
+            }
+            mSecondaryTasksSurfaceController.showOverview(false);
+        } else {
+            if (mSecondaryTasksSurfaceController == null) return;
+            mSecondaryTasksSurfaceController.hideOverview(false);
+        }
+    }
 }
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java
index 3a675dd..2b07872e 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java
@@ -28,9 +28,9 @@
             new PropertyModel.WritableIntPropertyKey();
     public static final PropertyModel.WritableIntPropertyKey BOTTOM_BAR_SELECTED_TAB_POSITION =
             new PropertyModel.WritableIntPropertyKey();
-    public static final PropertyModel.WritableBooleanPropertyKey IS_EXPLORE_SURFACE_VISIBLE =
+    public static final PropertyModel.WritableBooleanPropertyKey IS_BOTTOM_BAR_VISIBLE =
             new PropertyModel.WritableBooleanPropertyKey();
-    public static final PropertyModel.WritableBooleanPropertyKey IS_INCOGNITO =
+    public static final PropertyModel.WritableBooleanPropertyKey IS_EXPLORE_SURFACE_VISIBLE =
             new PropertyModel.WritableBooleanPropertyKey();
     public static final PropertyModel.WritableBooleanPropertyKey IS_SHOWING_OVERVIEW =
             new PropertyModel.WritableBooleanPropertyKey();
@@ -40,6 +40,7 @@
     public static final PropertyModel.WritableIntPropertyKey TOP_BAR_HEIGHT =
             new PropertyModel.WritableIntPropertyKey();
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {BOTTOM_BAR_CLICKLISTENER,
-            BOTTOM_BAR_HEIGHT, BOTTOM_BAR_SELECTED_TAB_POSITION, IS_EXPLORE_SURFACE_VISIBLE,
-            IS_INCOGNITO, IS_SHOWING_OVERVIEW, FEED_SURFACE_COORDINATOR, TOP_BAR_HEIGHT};
-}
\ No newline at end of file
+            BOTTOM_BAR_HEIGHT, BOTTOM_BAR_SELECTED_TAB_POSITION, IS_BOTTOM_BAR_VISIBLE,
+            IS_EXPLORE_SURFACE_VISIBLE, IS_SHOWING_OVERVIEW, FEED_SURFACE_COORDINATOR,
+            TOP_BAR_HEIGHT};
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java
index 435d609..7f1aa3e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java
@@ -99,6 +99,12 @@
          * @return Whether or not the TabSwitcher consumed the event.
          */
         boolean onBackPressed();
+
+        /**
+         * Set the bottom control height to margin the bottom of the TabListRecyclerView.
+         * @param bottomControlsHeight The bottom control height in pixel.
+         */
+        void setBottomControlsHeight(int bottomControlsHeight);
     }
 
     /**
@@ -123,12 +129,6 @@
         long getLastDirtyTimeForTesting();
 
         /**
-         * Set the bottom control height to margin the bottom of the TabListRecyclerView.
-         * @param bottomControlsHeight The bottom control height in pixel.
-         */
-        void setBottomControlsHeight(int bottomControlsHeight);
-
-        /**
          * Before calling {@link Controller#showOverview} to start showing the
          * TabSwitcher {@link TabListRecyclerView}, call this to populate it without making it
          * visible.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index c7570c5..5b5d903 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -150,11 +150,6 @@
     }
 
     @Override
-    public void setBottomControlsHeight(int bottomControlsHeight) {
-        mMediator.setBottomControlsHeight(bottomControlsHeight);
-    }
-
-    @Override
     public boolean prepareOverview() {
         boolean quick = mMediator.prepareOverview();
         mTabListCoordinator.prepareOverview();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
index 197d5cc..afd2197 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -262,10 +262,6 @@
         mShowTabsInMruOrder = feature.equals("twopanes") || feature.equals("single");
     }
 
-    void setBottomControlsHeight(int bottomControlsHeight) {
-        mContainerViewModel.set(BOTTOM_CONTROLS_HEIGHT, bottomControlsHeight);
-    }
-
     /**
      * Set the handler of the Grid Dialog so that it can be directly controlled.
      * @param tabGridDialogResetHandler The handler of the Grid Dialog
@@ -482,6 +478,11 @@
         return true;
     }
 
+    @Override
+    public void setBottomControlsHeight(int bottomControlsHeight) {
+        mContainerViewModel.set(BOTTOM_CONTROLS_HEIGHT, bottomControlsHeight);
+    }
+
     /**
      * Do clean-up work after the overview hiding animation is finished.
      * @see TabSwitcher#postHiding
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
index 58aa1716..a45d29cc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -60,6 +60,16 @@
     }
 
     @Override
+    public boolean closeAllTabsRequest(boolean incognito) {
+        if (getActiveLayout() == mStaticLayout && !incognito) {
+            startShowing(DeviceClassManager.enableAccessibilityLayout() ? mOverviewListLayout
+                                                                        : mOverviewLayout,
+                    /* animate= */ false);
+        }
+        return super.closeAllTabsRequest(incognito);
+    }
+
+    @Override
     protected LayoutManagerTabModelObserver createTabModelObserver() {
         return new LayoutManagerTabModelObserver() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationBubble.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationBubble.java
index d00d222b..c48f7c32 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationBubble.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationBubble.java
@@ -28,6 +28,10 @@
 public class NavigationBubble extends LinearLayout {
     private static final int COLOR_TRANSITION_DURATION_MS = 250;
 
+    private static final float FADE_ALPHA = 0.5f;
+
+    private static final int FADE_DURATION_MS = 400;
+
     private final ValueAnimator mColorAnimator;
     private final int mBlue;
     private final int mBlack;
@@ -55,6 +59,9 @@
     private ImageView mIcon;
     private AnimationListener mListener;
 
+    // True if arrow bubble is faded out.
+    private boolean mArrowFaded;
+
     /**
      * Constructor for inflating from XML.
      */
@@ -162,4 +169,16 @@
     public TextView getTextView() {
         return mText;
     }
+
+    /**
+     * Fade out the arrow bubble.
+     * @param faded {@code true} if the bubble should be faded.
+     * @param animate {@code true} if animation is needed.
+     */
+    public void setFaded(boolean faded, boolean animate) {
+        if (faded == mArrowFaded) return;
+        assert mIcon != null;
+        animate().alpha(faded ? FADE_ALPHA : 1.f).setDuration(animate ? FADE_DURATION_MS : 0);
+        mArrowFaded = faded;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
index 8d6499e..5f114e1d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
@@ -130,7 +130,7 @@
     public void onTouchEvent(int action) {
         if (action == MotionEvent.ACTION_UP) {
             if (mState == GestureState.DRAGGED && mSideSlideLayout != null) {
-                mSideSlideLayout.release(!mNavigationSheet.isPeeked());
+                mSideSlideLayout.release(mNavigationSheet.isHidden());
                 mNavigationSheet.release();
             } else if (mState == GestureState.GLOW && mGlowEffect != null) {
                 mGlowEffect.release();
@@ -226,6 +226,12 @@
         if (mState == GestureState.DRAGGED && mSideSlideLayout != null) {
             mSideSlideLayout.pull(delta);
             mNavigationSheet.onScroll(delta, mSideSlideLayout.getOverscroll());
+
+            mSideSlideLayout.fadeArrow(!mNavigationSheet.isHidden(), /* animate= */ true);
+            if (mNavigationSheet.isExpanded()) {
+                mSideSlideLayout.hideArrow();
+                mState = GestureState.NONE;
+            }
         } else if (mState == GestureState.GLOW && mGlowEffect != null) {
             mGlowEffect.onScroll(-delta);
         }
@@ -255,7 +261,7 @@
     public void release(boolean allowNav) {
         if (mState == GestureState.DRAGGED && mSideSlideLayout != null) {
             cancelStopNavigatingRunnable();
-            mSideSlideLayout.release(allowNav && !mNavigationSheet.isPeeked());
+            mSideSlideLayout.release(allowNav && mNavigationSheet.isHidden());
             mNavigationSheet.release();
         } else if (mState == GestureState.GLOW && mGlowEffect != null) {
             mGlowEffect.release();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
index 578345e..1a83f9be 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
@@ -53,7 +53,12 @@
         public void release() {}
 
         @Override
-        public boolean isPeeked() {
+        public boolean isHidden() {
+            return true;
+        }
+
+        @Override
+        public boolean isExpanded() {
             return false;
         }
     };
@@ -79,7 +84,12 @@
     void release();
 
     /**
-     * {@code true} if navigation sheet is in peeked state.
+     * @param {@code true} if navigation sheet is in hidden state.
      */
-    boolean isPeeked();
+    boolean isHidden();
+
+    /**
+     * @param {@code true} if navigation sheet is in expanded (half/full) state.
+     */
+    boolean isExpanded();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
index 0677146..1e510f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
@@ -24,6 +24,7 @@
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver;
 import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
+import org.chromium.content_public.browser.NavigationHistory;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.modelutil.ModelListAdapter;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -45,6 +46,10 @@
     // Actual amount is capped so it is at most half the screen width.
     private static final int PEEK_THRESHOLD_DP = 224;
 
+    // The history item count in the navigation sheet. If the count is equal or smaller,
+    // the sheet skips peek state and fully expands right away.
+    private static final int SKIP_PEEK_COUNT = 3;
+
     private final NavigationSheetView mContentView;
     private final View mToolbarView;
     private final LayoutInflater mLayoutInflater;
@@ -59,7 +64,7 @@
     };
 
     private final Handler mHandler = new Handler();
-    private final Runnable mSheetPeekRunnable;
+    private final Runnable mOpenSheetRunnable;
     private final float mPeekSheetThreshold;
 
     private final ModelList mModelList = new ModelList();
@@ -79,10 +84,6 @@
         }
     }
 
-    // Whether the navigation sheet is visible. Deemed true if it was requested to show even though
-    // it is not immediately visible. This is to avoid making repeated show/hide requests.
-    private boolean mSheetVisible;
-
     private boolean mForward;
 
     private boolean mShowCloseIndicator;
@@ -117,16 +118,29 @@
         }, NavigationItemViewBinder::bind);
         ListView listview = (ListView) mContentView.findViewById(R.id.navigation_entries);
         listview.setAdapter(mModelAdapter);
-
-        mSheetPeekRunnable = () -> {
-            if (!isVisible()) peek(mForward);
+        mOpenSheetRunnable = () -> {
+            if (isHidden()) openSheet();
         };
-
         mPeekSheetThreshold =
                 Math.min(context.getResources().getDisplayMetrics().density * PEEK_THRESHOLD_DP,
                         parent.getWidth() / 2);
     }
 
+    // Transition to either peeked or expanded state.
+    private void openSheet() {
+        NavigationHistory history = mDelegate.getHistory(mForward);
+        mMediator.populateEntries(history);
+        mBottomSheetController.get().requestShowContent(this, true);
+        mBottomSheetController.get().getBottomSheet().addObserver(mSheetObserver);
+        mSheetTriggered = true;
+        if (history.getEntryCount() <= SKIP_PEEK_COUNT) expandSheet();
+    }
+
+    private void expandSheet() {
+        mBottomSheetController.get().expandSheet();
+        GestureNavMetrics.recordHistogram("GestureNavigation.Sheet.Viewed", mForward);
+    }
+
     // NavigationSheet
 
     @Override
@@ -134,7 +148,6 @@
         if (mBottomSheetController.get() == null) return;
         mForward = forward;
         mShowCloseIndicator = showCloseIndicator;
-        setVisible(false);
         mSheetTriggered = false;
     }
 
@@ -144,8 +157,8 @@
         if (mShowCloseIndicator) return;
         if (overscroll > mPeekSheetThreshold) {
             if (isHidden() && Math.abs(delta) > 2.f) {
-                mHandler.removeCallbacks(mSheetPeekRunnable);
-                mHandler.postDelayed(mSheetPeekRunnable, PEEK_HOLD_DELAY_MS);
+                mHandler.removeCallbacks(mOpenSheetRunnable);
+                mHandler.postDelayed(mOpenSheetRunnable, PEEK_HOLD_DELAY_MS);
             }
         } else if (isPeeked()) {
             close(true);
@@ -155,27 +168,13 @@
     @Override
     public void release() {
         if (mBottomSheetController.get() == null) return;
-        mHandler.removeCallbacks(mSheetPeekRunnable);
-        // Show navigation sheet if released at peek state.
+        mHandler.removeCallbacks(mOpenSheetRunnable);
         if (mSheetTriggered) {
             GestureNavMetrics.recordHistogram("GestureNavigation.Sheet.Peeked", mForward);
         }
-        if (isPeeked()) {
-            mBottomSheetController.get().expandSheet();
-            GestureNavMetrics.recordHistogram("GestureNavigation.Sheet.Viewed", mForward);
-        }
-    }
 
-    /**
-     * Move the navigation sheet to peek state.
-     * @param forward {@code true} if the gesture is for navigating forward.
-     */
-    private void peek(boolean forward) {
-        mMediator.populateEntries(mDelegate.getHistory(forward));
-        mBottomSheetController.get().getBottomSheet().addObserver(mSheetObserver);
-        mBottomSheetController.get().requestShowContent(this, true);
-        setVisible(true);
-        mSheetTriggered = true;
+        // Show navigation sheet if released at peek state.
+        if (isPeeked()) expandSheet();
     }
 
     /**
@@ -184,22 +183,21 @@
      */
     private void close(boolean animate) {
         if (!isHidden()) mBottomSheetController.get().hideContent(this, animate);
-        setVisible(false);
         mBottomSheetController.get().getBottomSheet().removeObserver(mSheetObserver);
         mMediator.clear();
     }
 
-    /**
-     * @return {@code true} if the sheet is in hidden state.
-     */
-    private boolean isHidden() {
-        return !isVisible() && getTargetOrCurrentState() == SheetState.HIDDEN;
+    @Override
+    public boolean isHidden() {
+        return getTargetOrCurrentState() == SheetState.HIDDEN;
     }
 
-    @Override
-    public boolean isPeeked() {
+    /**
+     * @return {@code true} if the sheet is in peeked state.
+     */
+    private boolean isPeeked() {
         if (mBottomSheetController.get() == null) return false;
-        return isVisible() && getTargetOrCurrentState() == SheetState.PEEK;
+        return getTargetOrCurrentState() == SheetState.PEEK;
     }
 
     private @SheetState int getTargetOrCurrentState() {
@@ -210,26 +208,11 @@
         return state != SheetState.NONE ? state : sheet.getSheetState();
     }
 
-    /**
-     * @return {@code true} if the sheet is in fully expanded state.
-     */
-    private boolean isExpanded() {
-        return isVisible() && getTargetOrCurrentState() == SheetState.FULL;
-    }
-
-    /**
-     * Set the visibility flag of the navigation sheet.
-     * @param visible {@code true} if the sheet becomes visible.
-     */
-    private void setVisible(boolean visible) {
-        mSheetVisible = visible;
-    }
-
-    /**
-     * @return {@code true} if the sheet is visible.
-     */
-    private boolean isVisible() {
-        return mSheetVisible;
+    @Override
+    public boolean isExpanded() {
+        if (mBottomSheetController.get() == null) return false;
+        int state = getTargetOrCurrentState();
+        return state == SheetState.HALF || state == SheetState.FULL;
     }
 
     // BottomSheetContent
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java
index 0c0da8d..fdbe04c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java
@@ -113,6 +113,7 @@
 
         @Override
         public void onAnimationEnd(Animation animation) {
+            mArrowView.setFaded(false, false);
             mArrowView.setVisibility(View.INVISIBLE);
             if (mNavigating) {
                 if (mListener != null) mListener.onNavigate(mIsForward);
@@ -266,6 +267,7 @@
         mIsBeingDragged = true;
         mWillNavigate = false;
         initializeOffset();
+        mArrowView.setFaded(false, false);
         return true;
     }
 
@@ -318,6 +320,23 @@
         setTargetOffsetLeftAndRight(targetX - mCurrentTargetOffset);
     }
 
+    /**
+     * Update arrow bubble transparency as navigation sheet state changes.
+     * @param faded {@code true} if arrow bubble should fade out.
+     * @param animate {@code true} if animation is needed.
+     */
+    void fadeArrow(boolean faded, boolean animate) {
+        mArrowView.setFaded(faded, animate);
+    }
+
+    /**
+     * Hide arrow bubble by making it fade away at the current position.
+     */
+    void hideArrow() {
+        mNavigating = false;
+        startHidingAnimation(mNavigateListener);
+    }
+
     private boolean willNavigate() {
         return getOverscroll() > mTotalDragDistance * THRESHOLD_MULTIPLIER;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 38682bf..24a2371 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -447,9 +447,6 @@
         FeatureUtilities.cacheNativeFlagsForServiceManagerOnlyMode();
 
         ModuleInstaller.getInstance().recordStartupTime();
-
-        PostTask.postTask(
-                TaskTraits.BEST_EFFORT_MAY_BLOCK, LibraryPrefetcher::maybePinOrderedCodeInMemory);
     }
 
     private ActivityStateListener createActivityStateListener() {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 07d825c..f16b5bf 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6564,6 +6564,12 @@
         <message name="IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE" desc="The label of item for shared clipboard in context menu for showing device name when one device is available.">
           Send text to <ph name="DEVICE_NAME">$1<ex>Jimmy's Pixel</ex></ph>
         </message>
+        <message name="IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_NOTIFICATION_TITLE" desc="The title of the notification shown when a clipboard was shared.">
+          Text shared from <ph name="DEVICE_NAME">$1<ex>Jimmy's Pixel</ex></ph>
+        </message>
+        <message name="IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_NOTIFICATION_DESCRIPTION" desc="The description of the notification shown when a clipboard was shared.">
+          Copied to your clipboard
+        </message>
       </if>
 
       <if expr="use_titlecase">
@@ -6579,6 +6585,12 @@
         <message name="IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE" desc="In Title Case: The label of item for shared clipboard in context menu when single device is available.">
           Send text to <ph name="DEVICE_NAME">$1<ex>Jimmy's Pixel</ex></ph>
         </message>
+        <message name="IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_NOTIFICATION_TITLE" desc="In Title Case: The title of the notification shown when a clipboard was shared.">
+          Text shared from <ph name="DEVICE_NAME">$1<ex>Jimmy's Pixel</ex></ph>
+        </message>
+        <message name="IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_NOTIFICATION_DESCRIPTION" desc="In Title Case: The description of the notification shown when a clipboard was shared.">
+          Copied to Your Clipboard
+        </message>
       </if>
 
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index bfb4cfc..4b860be 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1589,8 +1589,8 @@
     "sharing/ping_message_handler.h",
     "sharing/shared_clipboard/feature_flags.cc",
     "sharing/shared_clipboard/feature_flags.h",
-    "sharing/shared_clipboard/shared_clipboard_message_handler_android.cc",
-    "sharing/shared_clipboard/shared_clipboard_message_handler_android.h",
+    "sharing/shared_clipboard/shared_clipboard_message_handler.cc",
+    "sharing/shared_clipboard/shared_clipboard_message_handler.h",
     "sharing/sharing_constants.cc",
     "sharing/sharing_constants.h",
     "sharing/sharing_device_capability.h",
@@ -2872,6 +2872,8 @@
       "search/contextual_search_policy_handler_android.h",
       "search_engines/template_url_service_factory_android.cc",
       "search_engines/template_url_service_factory_android.h",
+      "sharing/shared_clipboard/shared_clipboard_message_handler_android.cc",
+      "sharing/shared_clipboard/shared_clipboard_message_handler_android.h",
       "signin/identity_services_provider_android.cc",
       "signin/signin_manager_android_factory.cc",
       "signin/signin_manager_android_factory.h",
@@ -3425,11 +3427,15 @@
       "sharing/click_to_call/click_to_call_utils.h",
       "sharing/shared_clipboard/shared_clipboard_context_menu_observer.cc",
       "sharing/shared_clipboard/shared_clipboard_context_menu_observer.h",
+      "sharing/shared_clipboard/shared_clipboard_message_handler_desktop.cc",
+      "sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h",
       "sharing/shared_clipboard/shared_clipboard_ui_controller.cc",
       "sharing/shared_clipboard/shared_clipboard_ui_controller.h",
       "sharing/shared_clipboard/shared_clipboard_utils.cc",
       "sharing/shared_clipboard/shared_clipboard_utils.h",
       "sharing/sharing_dialog.h",
+      "sharing/sharing_notification_handler.cc",
+      "sharing/sharing_notification_handler.h",
       "sharing/sharing_ui_controller.cc",
       "sharing/sharing_ui_controller.h",
       "signin/signin_promo.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0c68024..a2be80d9 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1736,9 +1736,6 @@
     {"enable-request-tablet-site", flag_descriptions::kRequestTabletSiteName,
      flag_descriptions::kRequestTabletSiteDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(chromeos::switches::kEnableRequestTabletSite)},
-    {"force-use-chrome-camera", flag_descriptions::kForceUseChromeCameraName,
-     flag_descriptions::kForceUseChromeCameraDescription, kOsCrOS,
-     SINGLE_VALUE_TYPE(chromeos::switches::kForceUseChromeCamera)},
 #endif  // OS_CHROMEOS
     {"debug-packed-apps", flag_descriptions::kDebugPackedAppName,
      flag_descriptions::kDebugPackedAppDescription, kOsDesktop,
@@ -2936,9 +2933,9 @@
      flag_descriptions::kResourceLoadSchedulerDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kResourceLoadScheduler)},
 
-    {"prefetch-redirect-error", flag_descriptions::kPrefetchRedirectErrorName,
-     flag_descriptions::kPrefetchRedirectErrorDescription, kOsAll,
-     FEATURE_VALUE_TYPE(blink::features::kPrefetchRedirectError)},
+    {"prefetch-privacy-changes", flag_descriptions::kPrefetchPrivacyChangesName,
+     flag_descriptions::kPrefetchPrivacyChangesDescription, kOsAll,
+     FEATURE_VALUE_TYPE(blink::features::kPrefetchPrivacyChanges)},
 
     {"prefetch-main-resource-network-isolation-key",
      flag_descriptions::kPrefetchMainResourceNetworkIsolationKeyName,
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_config.cc b/chrome/browser/android/oom_intervention/oom_intervention_config.cc
index e41ceaa8..2390fe9 100644
--- a/chrome/browser/android/oom_intervention/oom_intervention_config.cc
+++ b/chrome/browser/android/oom_intervention/oom_intervention_config.cc
@@ -125,7 +125,7 @@
   is_navigate_ads_enabled_ = base::GetFieldTrialParamByFeatureAsBool(
       features::kOomIntervention, kNavigateAdsParamName, true);
   is_purge_v8_memory_enabled_ = base::GetFieldTrialParamByFeatureAsBool(
-      features::kOomIntervention, kPurgeV8MemoryParamName, false);
+      features::kOomIntervention, kPurgeV8MemoryParamName, true);
   should_detect_in_renderer_ = base::GetFieldTrialParamByFeatureAsBool(
       features::kOomIntervention, kShouldDetectInRenderer, true);
 
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
index bee8b7e..4b0d328 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -36,11 +36,13 @@
 #include "chromeos/network/proxy/proxy_config_service_impl.h"
 #include "chromeos/settings/timezone_settings.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_features.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/intent_helper/font_size_util.h"
 #include "components/arc/mojom/backup_settings.mojom.h"
+#include "components/arc/mojom/pip.mojom.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/onc/onc_pref_names.h"
@@ -171,6 +173,7 @@
   void SyncLocationServiceEnabled() const;
   void SyncProxySettings() const;
   void SyncReportingConsent(bool initial_sync) const;
+  void SyncPictureInPictureEnabled() const;
   void SyncSelectToSpeakEnabled() const;
   void SyncSpokenFeedbackEnabled() const;
   void SyncSwitchAccessEnabled() const;
@@ -383,6 +386,7 @@
   SyncFocusHighlightEnabled();
   SyncProxySettings();
   SyncReportingConsent(/*initial_sync=*/false);
+  SyncPictureInPictureEnabled();
   SyncSelectToSpeakEnabled();
   SyncSpokenFeedbackEnabled();
   SyncSwitchAccessEnabled();
@@ -595,6 +599,18 @@
                         extras);
 }
 
+void ArcSettingsServiceImpl::SyncPictureInPictureEnabled() const {
+  bool isPipEnabled =
+      base::FeatureList::IsEnabled(arc::kPictureInPictureFeature);
+
+  auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->pip(),
+                                               SetPipSuppressionStatus);
+  if (!instance)
+    return;
+
+  instance->SetPipSuppressionStatus(!isPipEnabled);
+}
+
 void ArcSettingsServiceImpl::SyncSelectToSpeakEnabled() const {
   SendBoolPrefSettingsBroadcast(
       ash::prefs::kAccessibilitySelectToSpeakEnabled,
diff --git a/chrome/browser/chromeos/arc/pip/arc_pip_bridge.cc b/chrome/browser/chromeos/arc/pip/arc_pip_bridge.cc
index 4534aa6..720d17a 100644
--- a/chrome/browser/chromeos/arc/pip/arc_pip_bridge.cc
+++ b/chrome/browser/chromeos/arc/pip/arc_pip_bridge.cc
@@ -6,18 +6,15 @@
 
 #include <utility>
 
-#include "ash/public/cpp/ash_pref_names.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h"
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
-#include "chrome/browser/profiles/profile.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_features.h"
 #include "components/arc/session/arc_bridge_service.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_service.h"
 #include "content/public/browser/picture_in_picture_window_controller.h"
 
 namespace arc {
@@ -54,20 +51,10 @@
 
 ArcPipBridge::ArcPipBridge(content::BrowserContext* context,
                            ArcBridgeService* bridge_service)
-    : arc_bridge_service_(bridge_service),
-      profile_(Profile::FromBrowserContext(context)) {
-  DCHECK(context);
-  DCHECK(profile_);
-
+    : arc_bridge_service_(bridge_service) {
   DVLOG(2) << "ArcPipBridge::ArcPipBridge";
   arc_bridge_service_->pip()->SetHost(this);
   arc_bridge_service_->pip()->AddObserver(this);
-
-  pref_change_registrar_.Init(profile_->GetPrefs());
-  pref_change_registrar_.Add(
-      ash::prefs::kAccessibilitySpokenFeedbackEnabled,
-      base::BindRepeating(&ArcPipBridge::OnSpokenFeedbackChanged,
-                          base::Unretained(this)));
 }
 
 ArcPipBridge::~ArcPipBridge() {
@@ -78,8 +65,6 @@
 
 void ArcPipBridge::OnConnectionReady() {
   DVLOG(1) << "ArcPipBridge::OnConnectionReady";
-  // Send the initial status.
-  OnSpokenFeedbackChanged();
 }
 
 void ArcPipBridge::OnConnectionClosed() {
@@ -116,26 +101,4 @@
     instance->ClosePip();
 }
 
-bool ArcPipBridge::ShouldSuppressPip() const {
-  return profile_->GetPrefs()->GetBoolean(
-      ash::prefs::kAccessibilitySpokenFeedbackEnabled);
-}
-
-void ArcPipBridge::OnSpokenFeedbackChanged() {
-  const bool should_suppress = ShouldSuppressPip();
-
-  DVLOG(1) << "ArcPipBridge::OnSpokenFeedbackChanged (status: "
-           << should_suppress << ")";
-
-  auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->pip(),
-                                               SetPipSuppressionStatus);
-  if (!instance)
-    return;
-
-  instance->SetPipSuppressionStatus(should_suppress);
-
-  // TODO(yoshiki): Add the code to suppress Chrome PIP window when the spoken
-  // feedback gets enabled.
-}
-
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/pip/arc_pip_bridge.h b/chrome/browser/chromeos/arc/pip/arc_pip_bridge.h
index 94f5505..164b073e 100644
--- a/chrome/browser/chromeos/arc/pip/arc_pip_bridge.h
+++ b/chrome/browser/chromeos/arc/pip/arc_pip_bridge.h
@@ -10,9 +10,6 @@
 #include "components/arc/mojom/pip.mojom.h"
 #include "components/arc/session/connection_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/prefs/pref_change_registrar.h"
-
-class Profile;
 
 namespace content {
 
@@ -47,17 +44,11 @@
   // PipInstance methods:
   void ClosePip();
 
-  void OnSpokenFeedbackChanged();
-
  private:
-  bool ShouldSuppressPip() const;
-
   ArcBridgeService* const arc_bridge_service_;
-  Profile* const profile_;
 
   std::unique_ptr<ArcPictureInPictureWindowControllerImpl>
       pip_window_controller_;
-  PrefChangeRegistrar pref_change_registrar_;
 
   bool prevent_closing_pip_ = false;
 
diff --git a/chrome/browser/chromeos/arc/pip/arc_pip_bridge_unittest.cc b/chrome/browser/chromeos/arc/pip/arc_pip_bridge_unittest.cc
index 6f498250..c4ada07 100644
--- a/chrome/browser/chromeos/arc/pip/arc_pip_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/pip/arc_pip_bridge_unittest.cc
@@ -4,13 +4,11 @@
 
 #include "chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h"
 
-#include "ash/public/cpp/ash_pref_names.h"
 #include "chrome/browser/chromeos/arc/pip/arc_pip_bridge.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/test/connection_holder_util.h"
 #include "components/arc/test/fake_pip_instance.h"
-#include "components/prefs/pref_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,12 +38,6 @@
   ArcPipBridge* bridge() { return bridge_.get(); }
   FakePipInstance* pip_instance() { return pip_instance_.get(); }
 
- protected:
-  void SetSpokenFeedbackEnabled(bool enabled) {
-    return testing_profile_.GetPrefs()->SetBoolean(
-        ash::prefs::kAccessibilitySpokenFeedbackEnabled, enabled);
-  }
-
  private:
   content::BrowserTaskEnvironment task_environment_;
   TestingProfile testing_profile_;
@@ -70,18 +62,4 @@
   EXPECT_EQ(0, pip_instance()->num_closed());
 }
 
-TEST_F(ArcPipBridgeTest, ChromeVoxSuppressesPip) {
-  // Initialized as "false" on connection ready.
-  EXPECT_TRUE(pip_instance()->suppressed().has_value());
-  EXPECT_FALSE(pip_instance()->suppressed().value());
-
-  // Enabling spoken-feedback suppresses pip.
-  SetSpokenFeedbackEnabled(true);
-  EXPECT_TRUE(pip_instance()->suppressed().value());
-
-  // Disabling spoken-feedback unsuppresses pip.
-  SetSpokenFeedbackEnabled(false);
-  EXPECT_FALSE(pip_instance()->suppressed().value());
-}
-
 }  // namespace arc
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 98a246c4..53d79bf 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -209,8 +209,11 @@
   }
 
   void FinishRestart(CrostiniResult result) {
-    crostini_manager_->FinishRestart(this, result);
     ReportRestarterResult(result);
+
+    // FinishRestart will delete this, so it's not safe to call any methods
+    // after this point.
+    crostini_manager_->FinishRestart(this, result);
   }
 
   void LoadComponentFinished(CrostiniResult result) {
@@ -463,7 +466,7 @@
     }
 
     crostini_manager_->SetContainerSshfsMounted(vm_name_, container_name_,
-                                                  true);
+                                                true);
 
     // Register filesystem and add volume to VolumeManager.
     base::FilePath mount_path = base::FilePath(mount_info.mount_path);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc
index 9559c85..53587f12 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc
@@ -12,5 +12,5 @@
 };
 
 IN_PROC_BROWSER_TEST_F(FileManagerBaseJsTest, VolumeManagerTypesTest) {
-  RunGeneratedTest("/volume_manager_types_unittest.html");
+  RunTestURL("volume_manager_types_unittest_gen.html");
 }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index f7b4a33..2da8fc2 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -524,6 +524,12 @@
         TestCase("openQuickViewFromDirectoryTree")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
+    DirectoryTree, /* directory_tree.js */
+    FilesAppBrowserTest,
+    ::testing::Values(TestCase("directoryTreeHorizontalScroll"),
+                      TestCase("directoryTreeVerticalScroll")));
+
+WRAPPED_INSTANTIATE_TEST_SUITE_P(
     DirectoryTreeContextMenu, /* directory_tree_context_menu.js */
     FilesAppBrowserTest,
     ::testing::Values(
@@ -945,12 +951,6 @@
         TestCase("metadataLargeDrive").EnableDriveFs()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
-    NavigationList, /* navigation_list.js */
-    FilesAppBrowserTest,
-    ::testing::Values(TestCase("navigationListHorizontalScroll"),
-                      TestCase("navigationListVerticalScroll")));
-
-WRAPPED_INSTANTIATE_TEST_SUITE_P(
     Search, /* search.js */
     FilesAppBrowserTest,
     ::testing::Values(TestCase("searchDownloadsWithResults"),
diff --git a/chrome/browser/chromeos/file_manager/gallery_jstest.cc b/chrome/browser/chromeos/file_manager/gallery_jstest.cc
index 562cc758..eb1fe84 100644
--- a/chrome/browser/chromeos/file_manager/gallery_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_jstest.cc
@@ -12,7 +12,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, ImageEncoderTest) {
-  RunGeneratedTest("/image_editor/image_encoder_unittest.html");
+  RunTestURL("image_editor/image_encoder_unittest_gen.html");
 }
 
 // Disabled on ASan builds due to a consistent failure. https://crbug.com/762831
@@ -22,37 +22,37 @@
 #define MAYBE_ExifEncoderTest ExifEncoderTest
 #endif
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, MAYBE_ExifEncoderTest) {
-  RunGeneratedTest("/image_editor/exif_encoder_unittest.html");
+  RunTestURL("image_editor/exif_encoder_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, ImageViewTest) {
-  RunGeneratedTest("/image_editor/image_view_unittest.html");
+  RunTestURL("image_editor/image_view_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, EntryListWatcherTest) {
-  RunGeneratedTest("/entry_list_watcher_unittest.html");
+  RunTestURL("entry_list_watcher_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, GalleryUtilTest) {
-  RunGeneratedTest("/gallery_util_unittest.html");
+  RunTestURL("gallery_util_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, GalleryItemTest) {
-  RunGeneratedTest("/gallery_item_unittest.html");
+  RunTestURL("gallery_item_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, GalleryDataModelTest) {
-  RunGeneratedTest("/gallery_data_model_unittest.html");
+  RunTestURL("gallery_data_model_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, RibbonTest) {
-  RunGeneratedTest("/ribbon_unittest.html");
+  RunTestURL("ribbon_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, SlideModeTest) {
-  RunGeneratedTest("/slide_mode_unittest.html");
+  RunTestURL("slide_mode_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, DimmableUIControllerTest) {
-  RunGeneratedTest("/dimmable_ui_controller_unittest.html");
+  RunTestURL("dimmable_ui_controller_unittest_gen.html");
 }
diff --git a/chrome/browser/chromeos/file_manager/image_loader_jstest.cc b/chrome/browser/chromeos/file_manager/image_loader_jstest.cc
index a2ef3b55..0acd3fa 100644
--- a/chrome/browser/chromeos/file_manager/image_loader_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/image_loader_jstest.cc
@@ -11,17 +11,17 @@
 };
 
 IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderClientTest) {
-  RunGeneratedTest("/image_loader_client_unittest.html");
+  RunTestURL("image_loader_client_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, CacheTest) {
-  RunGeneratedTest("/cache_unittest.html");
+  RunTestURL("cache_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderTest) {
-  RunGeneratedTest("/image_loader_unittest.html");
+  RunTestURL("image_loader_unittest_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, PiexLoaderTest) {
-  RunGeneratedTest("/piex_loader_unittest.html");
+  RunTestURL("piex_loader_unittest_gen.html");
 }
diff --git a/chrome/browser/chromeos/file_manager/video_player_jstest.cc b/chrome/browser/chromeos/file_manager/video_player_jstest.cc
index 4ab2218..16e4721 100644
--- a/chrome/browser/chromeos/file_manager/video_player_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/video_player_jstest.cc
@@ -12,5 +12,5 @@
 };
 
 IN_PROC_BROWSER_TEST_F(VideoPlayerJsTest, SaveResumePlaybackTest) {
-  RunGeneratedTest("/video_player_native_controls_unittest.html");
+  RunTestURL("video_player_native_controls_unittest_gen.html");
 }
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index 8bf90fd..e4865f9 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -1091,7 +1091,8 @@
   EXPECT_TRUE(fake_google_.IsPageRequested());
 }
 
-IN_PROC_BROWSER_TEST_P(MergeSessionTest, XHRNotThrottled) {
+// TODO(https://crbug.com/990844): Re-enable once flakiness is fixed.
+IN_PROC_BROWSER_TEST_P(MergeSessionTest, DISABLED_XHRNotThrottled) {
   StartNewUserSession(/*wait_for_merge=*/false,
                       /*is_under_advanced_protection=*/false);
 
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.cc b/chrome/browser/chromeos/usb/cros_usb_detector.cc
index 4fd8a31..3db8953 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.cc
@@ -38,29 +38,6 @@
 
 const char kNotifierUsb[] = "crosusb.connected";
 
-// ARCVM (Android VM) is considered as the "default" VM here, when it's enabled,
-// in the sense that the Android runtime is enabled by default on Chrome OS and
-// is always running. Android also has its own mechanisms/permissions ultimately
-// relying on Chrome OS for granting access to the USB devices attached in
-// ARCVM/ARC++. This means that unclaimed devices get auto-attached to ARCVM on
-// connect until the user decides otherwise by e.g. disconnecting them or
-// explicitly sharing them with another VM such as Crostini.
-// Note that attaching a device to a VM makes it visible by the guest kernel in
-// that VM but doesn't actually claim/open the device by itself, i.e. a device
-// attached in a VM (and not open there) can still be opened outside that VM.
-const char* const kDefaultVmName = arc::kArcVmName;
-
-// Returns whether the default VM is enabled. See declaration of
-// |kDefaultVmName|.
-bool IsDefaultVmEnabled() {
-  return arc::IsArcVmEnabled();
-}
-
-// Helper free function used with BindOnce() below for convenience.
-void IgnoreBool(base::OnceClosure closure, bool) {
-  std::move(closure).Run();
-}
-
 void RecordNotificationClosure(CrosUsbNotificationClosed disposition) {
   UMA_HISTOGRAM_ENUMERATION("CrosUsb.NotificationClosed", disposition);
 }
@@ -358,15 +335,6 @@
   available_device_info_.emplace(device_info->guid, device_info.Clone());
   SignalUsbDeviceObservers();
 
-  if (IsDefaultVmEnabled()) {
-    if (has_supported_interface || !has_blocked_interface) {
-      // USB devices not claimed by Chrome OS get automatically attached to the
-      // default VM. Note that this relies on the underlying VM (ARCVM) having
-      // its own permission model to restrict access to the device.
-      AttachUsbDeviceToVm(kDefaultVmName, new_device.guid, base::DoNothing());
-    }
-  }
-
   // Some devices should not trigger the notification.
   if (!new_device.sharable_with_crostini || hide_notification ||
       !ShouldShowNotification(*device_info)) {
@@ -397,8 +365,7 @@
   for (const auto& device : usb_devices_) {
     if (device.guid == guid) {
       for (const auto& sharing_info_pair : device.vm_sharing_info) {
-        DetachUsbDeviceFromVmInternal(sharing_info_pair.first, guid,
-                                      base::DoNothing());
+        DetachUsbDeviceFromVm(sharing_info_pair.first, guid, base::DoNothing());
       }
     }
   }
@@ -422,20 +389,11 @@
     const std::string& vm_name) {
   // Reattach shared devices when the VM becomes available.
   for (auto& device : usb_devices_) {
-    bool is_shared = false;
-    bool is_shared_with_this_vm = false;
     for (const auto& sharing_pair : device.vm_sharing_info) {
-      if (sharing_pair.second.shared) {
-        is_shared = true;
-        if (sharing_pair.first == vm_name) {
-          is_shared_with_this_vm = true;
-          break;
-        }
+      if (sharing_pair.second.shared && sharing_pair.first == vm_name) {
+        AttachUsbDeviceToVm(vm_name, device.guid, base::DoNothing());
       }
     }
-    if (is_shared_with_this_vm || (vm_name == kDefaultVmName && !is_shared)) {
-      AttachUsbDeviceToVm(vm_name, device.guid, base::DoNothing());
-    }
   }
 }
 
@@ -454,22 +412,6 @@
       break;
     }
   }
-  if (!IsDefaultVmEnabled() || vm_name == kDefaultVmName) {
-    AttachUsbDeviceToVmInternal(vm_name, guid, std::move(callback));
-    return;
-  }
-  auto attach_internal = base::BindOnce(
-      &CrosUsbDetector::AttachUsbDeviceToVmInternal,
-      weak_ptr_factory_.GetWeakPtr(), vm_name, guid, std::move(callback));
-  DetachUsbDeviceFromVm(
-      kDefaultVmName, guid,
-      base::BindOnce(&IgnoreBool, std::move(attach_internal)));
-}
-
-void CrosUsbDetector::AttachUsbDeviceToVmInternal(
-    const std::string& vm_name,
-    const std::string& guid,
-    base::OnceCallback<void(bool success)> callback) {
   auto it = available_device_info_.find(guid);
   if (it == available_device_info_.end()) {
     return;
@@ -490,23 +432,6 @@
     const std::string& vm_name,
     const std::string& guid,
     base::OnceCallback<void(bool success)> callback) {
-  if (!IsDefaultVmEnabled() || vm_name == kDefaultVmName) {
-    DetachUsbDeviceFromVmInternal(vm_name, guid, std::move(callback));
-    return;
-  }
-  auto attach_to_default_vm =
-      base::BindOnce(&CrosUsbDetector::AttachUsbDeviceToVmInternal,
-                     weak_ptr_factory_.GetWeakPtr(), kDefaultVmName, guid,
-                     std::move(callback));
-  DetachUsbDeviceFromVmInternal(
-      vm_name, guid,
-      base::BindOnce(&IgnoreBool, std::move(attach_to_default_vm)));
-}
-
-void CrosUsbDetector::DetachUsbDeviceFromVmInternal(
-    const std::string& vm_name,
-    const std::string& guid,
-    base::OnceCallback<void(bool success)> callback) {
   const auto& it = available_device_info_.find(guid);
   if (it == available_device_info_.end()) {
     // If there wasn't an existing attachment, then removal is a no-op and
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.h b/chrome/browser/chromeos/usb/cros_usb_detector.h
index 47c906c9..1c49128 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.h
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.h
@@ -106,15 +106,13 @@
   void OnDeviceRemoved(device::mojom::UsbDeviceInfoPtr device) override;
 
   // Attaches the device identified by |guid| into the VM identified by
-  // |vm_name|. Note that this may detach the device from the default VM
-  // (=ARCVM) beforehand.
+  // |vm_name|.
   void AttachUsbDeviceToVm(const std::string& vm_name,
                            const std::string& guid,
                            base::OnceCallback<void(bool success)> callback);
 
   // Detaches the device identified by |guid| from the VM identified by
-  // |vm_name|. Note that this may attach the device (back) into the default VM
-  // (=ARCVM) as a result.
+  // |vm_name|.
   void DetachUsbDeviceFromVm(const std::string& vm_name,
                              const std::string& guid,
                              base::OnceCallback<void(bool success)> callback);
@@ -133,16 +131,6 @@
   std::vector<CrosUsbDeviceInfo> GetDevicesSharableWithCrostini() const;
 
  private:
-  void AttachUsbDeviceToVmInternal(
-      const std::string& vm_name,
-      const std::string& guid,
-      base::OnceCallback<void(bool success)> callback);
-
-  void DetachUsbDeviceFromVmInternal(
-      const std::string& vm_name,
-      const std::string& guid,
-      base::OnceCallback<void(bool success)> callback);
-
   // Called after USB device access has been checked.
   void OnDeviceChecked(device::mojom::UsbDeviceInfoPtr device,
                        bool hide_notification,
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
index 77fbe26..c14309c2 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
@@ -138,7 +138,6 @@
         {chromeos::features::kCrostiniUsbSupport,
          chromeos::features::kCrostiniUsbAllowUnsupported},
         {});
-    arc::EnableArcVmForTesting();
 
     TestingBrowserProcess::GetGlobal()->SetSystemNotificationHelper(
         std::make_unique<SystemNotificationHelper>());
@@ -157,7 +156,6 @@
   }
 
   void TearDown() override {
-    arc::DisableArcVmForTesting();
     scoped_feature_list_.Reset();
     crostini_test_helper_.reset();
     BrowserWithTestWindowTest::TearDown();
@@ -196,6 +194,13 @@
     return devices.front();
   }
 
+  static bool IsSharedWithCrostini(
+      const chromeos::CrosUsbDeviceInfo& device_info) {
+    const auto it = device_info.vm_sharing_info.find(
+        crostini::kCrostiniDefaultVmName);
+    return it != device_info.vm_sharing_info.end() && it->second.shared;
+  }
+
  protected:
   base::string16 connection_message(const char* product_name) {
     return base::ASCIIToUTF16(base::StringPrintf(
@@ -699,62 +704,6 @@
   EXPECT_EQ(0U, *crostini_info.guest_port);
 }
 
-TEST_F(CrosUsbDetectorTest, DeviceGetsAutoAttachedToArcVmOnConnect) {
-  cros_usb_detector_->AddUsbDeviceObserver(&usb_device_observer_);
-  ConnectToDeviceManager();
-  base::RunLoop().RunUntilIdle();
-
-  auto device_1 = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
-      0, 1, kManufacturerName, kProductName_1, "002");
-  device_manager_.AddDevice(device_1);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(2, usb_device_observer_.notify_count());
-  EXPECT_TRUE(GetSingleDeviceInfo().vm_sharing_info[arc::kArcVmName].shared);
-}
-
-TEST_F(CrosUsbDetectorTest, AttachingDeviceToCrostiniDetachesItFromArcVm) {
-  ConnectToDeviceManager();
-  base::RunLoop().RunUntilIdle();
-
-  auto device_1 = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
-      0, 1, kManufacturerName, kProductName_1, "002");
-  device_manager_.AddDevice(device_1);
-  base::RunLoop().RunUntilIdle();
-
-  auto device_info = GetSingleDeviceInfo();
-  EXPECT_TRUE(device_info.vm_sharing_info[arc::kArcVmName].shared);
-
-  cros_usb_detector_->AddUsbDeviceObserver(&usb_device_observer_);
-  AttachDeviceToVm(crostini::kCrostiniDefaultVmName, device_info.guid);
-  EXPECT_EQ(2, usb_device_observer_.notify_count());
-
-  device_info = GetSingleDeviceInfo();
-  EXPECT_EQ(1U, device_info.vm_sharing_info.size());
-  EXPECT_TRUE(
-      device_info.vm_sharing_info[crostini::kCrostiniDefaultVmName].shared);
-}
-
-TEST_F(CrosUsbDetectorTest, DetachingDeviceFromCrostiniAttachesItToArcVm) {
-  ConnectToDeviceManager();
-  base::RunLoop().RunUntilIdle();
-
-  auto device_1 = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
-      0, 1, kManufacturerName, kProductName_1, "002");
-  device_manager_.AddDevice(device_1);
-  base::RunLoop().RunUntilIdle();
-
-  auto device_info = GetSingleDeviceInfo();
-  AttachDeviceToVm(crostini::kCrostiniDefaultVmName, device_info.guid);
-  cros_usb_detector_->AddUsbDeviceObserver(&usb_device_observer_);
-  DetachDeviceFromVm(crostini::kCrostiniDefaultVmName, device_info.guid);
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(2, usb_device_observer_.notify_count());
-  device_info = GetSingleDeviceInfo();
-  EXPECT_EQ(1U, device_info.vm_sharing_info.size());
-  EXPECT_TRUE(device_info.vm_sharing_info[arc::kArcVmName].shared);
-}
-
 TEST_F(CrosUsbDetectorTest, AttachingAlreadyAttachedDeviceIsANoOp) {
   ConnectToDeviceManager();
   base::RunLoop().RunUntilIdle();
@@ -765,7 +714,7 @@
   base::RunLoop().RunUntilIdle();
 
   auto device_info = GetSingleDeviceInfo();
-  EXPECT_TRUE(device_info.vm_sharing_info[arc::kArcVmName].shared);
+  EXPECT_EQ(0U, device_info.vm_sharing_info.size());
 
   AttachDeviceToVm(crostini::kCrostiniDefaultVmName, device_info.guid);
   cros_usb_detector_->AddUsbDeviceObserver(&usb_device_observer_);
@@ -773,8 +722,7 @@
   EXPECT_EQ(0, usb_device_observer_.notify_count());
   device_info = GetSingleDeviceInfo();
   EXPECT_EQ(1U, device_info.vm_sharing_info.size());
-  EXPECT_TRUE(
-      device_info.vm_sharing_info[crostini::kCrostiniDefaultVmName].shared);
+  EXPECT_TRUE(IsSharedWithCrostini(device_info));
 }
 
 TEST_F(CrosUsbDetectorTest, DeviceCanBeAttachedToArcVmWhenCrostiniIsDisabled) {
@@ -787,6 +735,7 @@
   device_manager_.AddDevice(device_1);
   base::RunLoop().RunUntilIdle();
 
+  AttachDeviceToVm(arc::kArcVmName, GetSingleDeviceInfo().guid);
   EXPECT_TRUE(GetSingleDeviceInfo().vm_sharing_info[arc::kArcVmName].shared);
 }
 
@@ -799,48 +748,24 @@
   device_manager_.AddDevice(device_1);
   base::RunLoop().RunUntilIdle();
 
-  const auto device = GetSingleDeviceInfo();
-  AttachDeviceToVm(crostini::kCrostiniDefaultVmName, device.guid);
-  base::RunLoop().RunUntilIdle();
-
-  cros_usb_detector_->AddUsbDeviceObserver(&usb_device_observer_);
-  cros_usb_detector_->ConnectSharedDevicesOnVmStartup(arc::kArcVmName);
-  base::RunLoop().RunUntilIdle();
-  // Starting ARCVM should be a no-op here as the device was already shared with
-  // Crostini.
-  EXPECT_EQ(0, usb_device_observer_.notify_count());
-
   cros_usb_detector_->ConnectSharedDevicesOnVmStartup(
       crostini::kCrostiniDefaultVmName);
   base::RunLoop().RunUntilIdle();
-  // The device was already attached to Crostini.
+  // No device is shared with Crostini, yet.
   EXPECT_EQ(0, usb_device_observer_.notify_count());
+  auto device = GetSingleDeviceInfo();
+  EXPECT_EQ(0U, device.vm_sharing_info.size());
 
-  DetachDeviceFromVm(crostini::kCrostiniDefaultVmName, device.guid);
-  cros_usb_detector_->ConnectSharedDevicesOnVmStartup(arc::kArcVmName);
-  EXPECT_EQ(2, usb_device_observer_.notify_count());
-  EXPECT_TRUE(GetSingleDeviceInfo().vm_sharing_info[arc::kArcVmName].shared);
-}
-
-TEST_F(CrosUsbDetectorTest, DevicesDontGetAutoAttachedToArcVmWhenDisabled) {
-  arc::DisableArcVmForTesting();
-  ConnectToDeviceManager();
+  device = GetSingleDeviceInfo();
+  AttachDeviceToVm(crostini::kCrostiniDefaultVmName, device.guid);
   base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(IsSharedWithCrostini(GetSingleDeviceInfo()));
 
-  auto device_1 = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
-      0, 1, kManufacturerName, kProductName_1, "002");
-  device_manager_.AddDevice(device_1);
+  cros_usb_detector_->AddUsbDeviceObserver(&usb_device_observer_);
+  cros_usb_detector_->ConnectSharedDevicesOnVmStartup(
+      crostini::kCrostiniDefaultVmName);
   base::RunLoop().RunUntilIdle();
-
-  auto device_info = GetSingleDeviceInfo();
-  EXPECT_TRUE(device_info.vm_sharing_info.empty());
-
-  AttachDeviceToVm(crostini::kCrostiniDefaultVmName, device_info.guid);
-  device_info = GetSingleDeviceInfo();
-  EXPECT_TRUE(
-      device_info.vm_sharing_info[crostini::kCrostiniDefaultVmName].shared);
-
-  // Detaching shouldn't auto-attach to ARCVM either when ARCVM is disabled.
-  DetachDeviceFromVm(crostini::kCrostiniDefaultVmName, device_info.guid);
-  EXPECT_TRUE(GetSingleDeviceInfo().vm_sharing_info.empty());
+  // Attaching an already attached device is a no-op currently.
+  EXPECT_EQ(0, usb_device_observer_.notify_count());
+  EXPECT_TRUE(IsSharedWithCrostini(GetSingleDeviceInfo()));
 }
diff --git a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
index 7b80e96..563dfc1 100644
--- a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
@@ -165,6 +165,7 @@
 
   void ViewSingleDistilledPage(const GURL& url,
                                const std::string& expected_mime_type);
+  void ViewSingleDistilledPageAndExpectErrorPage(const GURL& url);
   void PrefTest(bool is_error_page);
   // Database entries.
   static FakeDB<ArticleEntry>::EntryMap* database_model_;
@@ -219,10 +220,10 @@
   // We should expect distillation for any valid URL.
   expect_distillation_ = true;
   expect_distiller_page_ = true;
-  GURL view_url("http://www.example.com/1");
-  const GURL url =
-      url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme, view_url);
-  ViewSingleDistilledPage(url, "text/html");
+  GURL original_url("http://www.example.com/1");
+  const GURL view_url =
+      url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme, original_url);
+  ViewSingleDistilledPage(view_url, "text/html");
 }
 
 void DomDistillerViewerSourceBrowserTest::ViewSingleDistilledPage(
@@ -256,9 +257,13 @@
 IN_PROC_BROWSER_TEST_F(DomDistillerViewerSourceBrowserTest,
                        MAYBE_TestBadUrlErrorPage) {
   GURL url("chrome-distiller://bad");
+  ViewSingleDistilledPageAndExpectErrorPage(url);
+}
 
+void DomDistillerViewerSourceBrowserTest::
+    ViewSingleDistilledPageAndExpectErrorPage(const GURL& url) {
   // Navigate to a distiller URL.
-  ui_test_utils::NavigateToURL(browser(), url);
+  ViewSingleDistilledPage(url, "text/html");
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
@@ -319,6 +324,19 @@
   ViewSingleDistilledPage(url, "text/html");
 }
 
+IN_PROC_BROWSER_TEST_F(DomDistillerViewerSourceBrowserTest,
+                       InvalidURLShouldGetErrorPage) {
+  const GURL original_url("http://www.example.com/1");
+  const GURL different_url("http://www.example.com/2");
+  const GURL view_url =
+      url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme, original_url);
+  // This is a bogus URL, so no distillation will happen.
+  const GURL bad_view_url = net::AppendOrReplaceQueryParameter(
+      view_url, kUrlKey, different_url.spec());
+
+  ViewSingleDistilledPageAndExpectErrorPage(bad_view_url);
+}
+
 IN_PROC_BROWSER_TEST_F(DomDistillerViewerSourceBrowserTest, EarlyTemplateLoad) {
   dom_distiller::DomDistillerServiceFactory::GetInstance()
       ->SetTestingFactoryAndUse(browser()->profile(),
@@ -553,20 +571,21 @@
 }
 
 void DomDistillerViewerSourceBrowserTest::PrefTest(bool is_error_page) {
-  GURL url;
+  GURL view_url;
   if (is_error_page) {
     expect_distillation_ = false;
     expect_distiller_page_ = false;
-    url = GURL("chrome-distiller://bad");
+    view_url = GURL("chrome-distiller://bad");
   } else {
     expect_distillation_ = true;
     expect_distiller_page_ = true;
-    GURL view_url("http://www.example.com/1");
-    url = url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme, view_url);
+    GURL original_url("http://www.example.com/1");
+    view_url = url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme,
+                                                     original_url);
   }
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ViewSingleDistilledPage(url, "text/html");
+  ViewSingleDistilledPage(view_url, "text/html");
   content::WaitForLoadStop(contents);
   ExpectBodyHasThemeAndFont(contents, "light", "sans-serif");
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index c5730518..14d735f 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2154,11 +2154,6 @@
     "expiry_milestone": -1
   },
   {
-    "name": "force-use-chrome-camera",
-    "owners": [ "shik", "chromeos-camera-app-eng@google.com" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "foreground-notification-manager",
     "owners": [ "//components/download/OWNERS" ],
     "expiry_milestone": 76
@@ -2836,7 +2831,7 @@
     "expiry_milestone": 85
   },
   {
-    "name": "prefetch-redirect-error",
+    "name": "prefetch-privacy-changes",
     "owners": [ "dom", "yhirano" ],
     "expiry_milestone": 85
   },
@@ -3236,7 +3231,7 @@
   {
     "name": "unified-consent",
     "owners": [ "msarda", "tangltom" ],
-    "expiry_milestone": 76
+    "expiry_milestone": 79
   },
   {
     "name": "unsafely-treat-insecure-origin-as-secure",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 24a51bf..982da961 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1647,11 +1647,12 @@
     "Uses the resource load scheduler in blink to throttle resource load "
     "requests.";
 
-const char kPrefetchRedirectErrorName[] =
-    "Prefetch requests use \"error\" redirect mode";
-const char kPrefetchRedirectErrorDescription[] =
-    "Prefetch requests will not follow redirect responses, and instead be "
-    "logged as errors. Redirect responses are still stored in the cache.";
+const char kPrefetchPrivacyChangesName[] =
+    "Prefetch request properties are updated to be privacy-preserving";
+const char kPrefetchPrivacyChangesDescription[] =
+    "Prefetch requests will not follow redirects, not send a Referer header, "
+    "not send credentials for cross-origin requests, and do not pass through "
+    "service workers.";
 
 const char kPrefetchMainResourceNetworkIsolationKeyName[] =
     "Prefetch requests for cross-origin main resources are fetched with a "
@@ -3422,12 +3423,6 @@
 const char kFirstRunUiTransitionsDescription[] =
     "Transitions during first-run tutorial are animated.";
 
-const char kForceUseChromeCameraName[] =
-    "Open Chrome camera app when clicking on camera icon";
-const char kForceUseChromeCameraDescription[] =
-    "Open Chrome camera app when clicking on camera icon instead of "
-    "GoogleCamera app, regardless of whether Android runtime is enabled.";
-
 const char kFsNosymfollowName[] =
     "Prevent symlink traversal on user-supplied filesystems.";
 const char kFsNosymfollowDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 185e392d..6155c8fd 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -992,8 +992,8 @@
 extern const char kResourceLoadSchedulerName[];
 extern const char kResourceLoadSchedulerDescription[];
 
-extern const char kPrefetchRedirectErrorName[];
-extern const char kPrefetchRedirectErrorDescription[];
+extern const char kPrefetchPrivacyChangesName[];
+extern const char kPrefetchPrivacyChangesDescription[];
 
 extern const char kPrefetchMainResourceNetworkIsolationKeyName[];
 extern const char kPrefetchMainResourceNetworkIsolationKeyDescription[];
@@ -2048,9 +2048,6 @@
 extern const char kFirstRunUiTransitionsName[];
 extern const char kFirstRunUiTransitionsDescription[];
 
-extern const char kForceUseChromeCameraName[];
-extern const char kForceUseChromeCameraDescription[];
-
 extern const char kFsNosymfollowName[];
 extern const char kFsNosymfollowDescription[];
 
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
index 6b9128f..c18e6eeb 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
@@ -55,6 +55,10 @@
 #include "ui/base/ui_base_features.h"
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_MACOSX)
+#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
+#endif  // defined(OS_MACOSX)
+
 using content::BrowserThread;
 
 namespace {
@@ -308,6 +312,16 @@
   // If the device id wasn't specified then this is a screen capture request
   // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
   if (request.requested_video_device_id.empty()) {
+#if defined(OS_MACOSX)
+    if (system_media_permissions::CheckSystemScreenCapturePermission() !=
+        system_media_permissions::SystemPermission::kAllowed) {
+      std::move(callback).Run(
+          blink::MediaStreamDevices(),
+          blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+          nullptr);
+      return;
+    }
+#endif
     ProcessScreenCaptureAccessRequest(web_contents, request,
                                       std::move(callback), extension);
     return;
@@ -340,6 +354,17 @@
         std::move(ui));
     return;
   }
+#if defined(OS_MACOSX)
+  if (media_id.type != content::DesktopMediaID::TYPE_WEB_CONTENTS &&
+      system_media_permissions::CheckSystemScreenCapturePermission() !=
+          system_media_permissions::SystemPermission::kAllowed) {
+    std::move(callback).Run(
+        blink::MediaStreamDevices(),
+        blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+        nullptr);
+    return;
+  }
+#endif
 
   bool loopback_audio_supported = false;
 #if defined(USE_CRAS) || defined(OS_WIN)
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.cc b/chrome/browser/media/webrtc/display_media_access_handler.cc
index 46e317e..006b9d6 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler.cc
@@ -25,6 +25,10 @@
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
 
+#if defined(OS_MACOSX)
+#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
+#endif
+
 // Holds pending request information so that we display one picker UI at a time
 // for each content::WebContents.
 struct DisplayMediaAccessHandler::PendingAccessRequest {
@@ -198,15 +202,27 @@
     request_result = blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
   } else {
     request_result = blink::mojom::MediaStreamRequestResult::OK;
-    const auto& visible_url = url_formatter::FormatUrlForSecurityDisplay(
-        web_contents->GetLastCommittedURL(),
-        url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
-    ui = GetDevicesForDesktopCapture(
-        web_contents, &devices, media_id,
-        blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
-        blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE,
-        media_id.audio_share, false /* disable_local_echo */,
-        display_notification_, visible_url, visible_url);
+#if defined(OS_MACOSX)
+    // Check screen capture permissions on Mac if necessary.
+    if ((media_id.type == content::DesktopMediaID::TYPE_SCREEN ||
+         media_id.type == content::DesktopMediaID::TYPE_WINDOW) &&
+        system_media_permissions::CheckSystemScreenCapturePermission() !=
+            system_media_permissions::SystemPermission::kAllowed) {
+      request_result =
+          blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
+    }
+#endif
+    if (request_result == blink::mojom::MediaStreamRequestResult::OK) {
+      const auto& visible_url = url_formatter::FormatUrlForSecurityDisplay(
+          web_contents->GetLastCommittedURL(),
+          url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
+      ui = GetDevicesForDesktopCapture(
+          web_contents, &devices, media_id,
+          blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
+          blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE,
+          media_id.audio_share, false /* disable_local_echo */,
+          display_notification_, visible_url, visible_url);
+    }
   }
 
   std::move(pending_request.callback)
diff --git a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h
index bd9aec5..73b0453 100644
--- a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h
+++ b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h
@@ -31,6 +31,11 @@
 SystemPermission CheckSystemAudioCapturePermission();
 SystemPermission CheckSystemVideoCapturePermission();
 
+// On 10.15 and above: returns the system permission.
+// On 10.14 and below: returns |SystemPermission::kAllowed|, since there are no
+// system screen capture permissions.
+SystemPermission CheckSystemScreenCapturePermission();
+
 // On 10.14 and above: requests system permission and returns. When requesting
 // permission, the OS will show a user dialog and respond asynchronously. At the
 // response, |callback| is posted with |traits|.
diff --git a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm
index ebffca78..11aa31cb 100644
--- a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm
+++ b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm
@@ -23,6 +23,8 @@
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "base/task/post_task.h"
@@ -161,6 +163,27 @@
   }
 }
 
+// Heuristic to check screen capture permission on macOS 10.15.
+// See https://crbug.com/993692#c3.
+bool IsScreenCaptureAllowed() {
+  if (@available(macOS 10.15, *)) {
+    base::ScopedCFTypeRef<CFArrayRef> window_list(CGWindowListCopyWindowInfo(
+        kCGWindowListOptionOnScreenOnly, kCGNullWindowID));
+    NSUInteger num_windows = CFArrayGetCount(window_list);
+    NSUInteger num_windows_with_name = 0;
+    for (NSDictionary* dict in base::mac::CFToNSCast(window_list.get())) {
+      if ([dict objectForKey:base::mac::CFToNSCast(kCGWindowName)]) {
+        num_windows_with_name++;
+      } else {
+        // No kCGWindowName detected implies no permission.
+        break;
+      }
+    }
+    return num_windows == num_windows_with_name;
+  }
+  return true;
+}
+
 }  // namespace
 
 SystemPermission CheckSystemAudioCapturePermission() {
@@ -171,6 +194,11 @@
   return CheckSystemMediaCapturePermission(AVMediaTypeVideo);
 }
 
+SystemPermission CheckSystemScreenCapturePermission() {
+  return IsScreenCaptureAllowed() ? SystemPermission::kAllowed
+                                  : SystemPermission::kDenied;
+}
+
 void RequestSystemAudioCapturePermisson(base::OnceClosure callback,
                                         const base::TaskTraits& traits) {
   RequestSystemMediaCapturePermission(
diff --git a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
index 0c80ba6..b0fa8a8 100644
--- a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
@@ -71,7 +71,8 @@
   bool LaunchApprtcInstanceOnLocalhost(const std::string& port) {
     base::FilePath appengine_dev_appserver =
         GetSourceDir().Append(FILE_PATH_LITERAL(
-            "out/apprtc/temp/google-cloud-sdk/bin/dev_appserver.py"));
+            "third_party/webrtc/rtc_tools/testing/webrtc_apprtc_browsertest/"
+            "apprtc/temp/google-cloud-sdk/bin/dev_appserver.py"));
     if (!base::PathExists(appengine_dev_appserver)) {
       LOG(ERROR) << "Missing appengine sdk at " <<
           appengine_dev_appserver.value() << ".\n" <<
@@ -79,8 +80,9 @@
       return false;
     }
 
-    base::FilePath apprtc_dir =
-        GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc/out/app_engine"));
+    base::FilePath apprtc_dir = GetSourceDir().Append(
+        FILE_PATH_LITERAL("third_party/webrtc/rtc_tools/testing/"
+                          "webrtc_apprtc_browsertest/apprtc/out/app_engine"));
     if (!base::PathExists(apprtc_dir)) {
       LOG(ERROR) << "Missing AppRTC AppEngine app at " <<
           apprtc_dir.value() << ".\n" << test::kAdviseOnGclientSolution;
@@ -113,11 +115,13 @@
     // The go workspace should be created, and collidermain built, at the
     // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs.
 #if defined(OS_WIN)
-    base::FilePath collider_server = GetSourceDir().Append(
-        FILE_PATH_LITERAL("out/collider/collidermain.exe"));
+    base::FilePath collider_server = GetSourceDir().Append(FILE_PATH_LITERAL(
+        "third_party/webrtc/rtc_tools/testing/"
+        "webrtc_apprtc_browsertest/collider/collidermain.exe"));
 #else
-    base::FilePath collider_server =
-        GetSourceDir().Append(FILE_PATH_LITERAL("out/collider/collidermain"));
+    base::FilePath collider_server = GetSourceDir().Append(
+        FILE_PATH_LITERAL("third_party/webrtc/rtc_tools/testing/"
+                          "webrtc_apprtc_browsertest/collider/collidermain"));
 #endif
     if (!base::PathExists(collider_server)) {
       LOG(ERROR) << "Missing Collider server binary at " <<
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 1668725..7f8536a 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -56,8 +56,8 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/user_agent.h"
 #include "crypto/sha2.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/net_buildflags.h"
 #include "net/third_party/uri_template/uri_template.h"
 #include "services/network/network_service.h"
@@ -601,11 +601,11 @@
       MakeRequest(&network_service_network_context_),
       CreateNetworkContextParams());
 
-  network::mojom::NetworkContextClientPtr client_ptr;
-  auto client_request = mojo::MakeRequest(&client_ptr);
-  mojo::MakeStrongBinding(std::make_unique<content::NetworkContextClientBase>(),
-                          std::move(client_request));
-  network_service_network_context_->SetClient(std::move(client_ptr));
+  mojo::PendingRemote<network::mojom::NetworkContextClient> client_remote;
+  mojo::MakeSelfOwnedReceiver(
+      std::make_unique<content::NetworkContextClientBase>(),
+      client_remote.InitWithNewPipeAndPassReceiver());
+  network_service_network_context_->SetClient(std::move(client_remote));
 
   // Configure the stub resolver. This must be done after the system
   // NetworkContext is created, but before anything has the chance to use it.
diff --git a/chrome/browser/notifications/notification_display_service_impl.cc b/chrome/browser/notifications/notification_display_service_impl.cc
index 44fb2fd2..46f516b 100644
--- a/chrome/browser/notifications/notification_display_service_impl.cc
+++ b/chrome/browser/notifications/notification_display_service_impl.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/notifications/persistent_notification_handler.h"
 #include "chrome/browser/permissions/permission_request_notification_handler.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sharing/sharing_notification_handler.h"
 #include "chrome/common/chrome_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/ui_base_features.h"
@@ -139,6 +140,10 @@
         NotificationHandler::Type::PERMISSION_REQUEST,
         std::make_unique<PermissionRequestNotificationHandler>());
 #endif
+#if !defined(OS_ANDROID)
+    AddNotificationHandler(NotificationHandler::Type::SHARING,
+                           std::make_unique<SharingNotificationHandler>());
+#endif
   }
 
   // Initialize the bridge if native notifications are available, otherwise
diff --git a/chrome/browser/notifications/notification_handler.h b/chrome/browser/notifications/notification_handler.h
index 417961a8..f7cec6e3a 100644
--- a/chrome/browser/notifications/notification_handler.h
+++ b/chrome/browser/notifications/notification_handler.h
@@ -34,7 +34,8 @@
                     // NotificationDelegate.
     PERMISSION_REQUEST = 5,  // A permission request that is presented to the
                              // user via a notification.
-    MAX = PERMISSION_REQUEST,
+    SHARING = 6,
+    MAX = SHARING,
   };
 
   virtual ~NotificationHandler();
diff --git a/chrome/browser/notifications/popups_only_ui_controller.cc b/chrome/browser/notifications/popups_only_ui_controller.cc
index d9fcdaf5..5c1b1eb 100644
--- a/chrome/browser/notifications/popups_only_ui_controller.cc
+++ b/chrome/browser/notifications/popups_only_ui_controller.cc
@@ -6,6 +6,8 @@
 
 #include "ui/display/screen.h"
 #include "ui/message_center/message_center.h"
+#include "ui/message_center/views/desktop_popup_alignment_delegate.h"
+#include "ui/message_center/views/message_popup_collection.h"
 
 PopupsOnlyUiController::PopupsOnlyUiController()
     : message_center_(message_center::MessageCenter::Get()) {
@@ -15,7 +17,10 @@
   // Initialize delegate after calling message_center_->AddObserver to ensure
   // the correct order of observers. (PopupsOnlyUiController has to be called
   // before MessagePopupCollection, see crbug.com/901350)
-  delegate_ = CreateDelegate();
+  alignment_delegate_ =
+      std::make_unique<message_center::DesktopPopupAlignmentDelegate>();
+  popup_collection_ = std::make_unique<message_center::MessagePopupCollection>(
+      alignment_delegate_.get());
 }
 
 PopupsOnlyUiController::~PopupsOnlyUiController() {
@@ -53,12 +58,9 @@
 
 void PopupsOnlyUiController::ShowOrHidePopupBubbles() {
   if (popups_visible_ && !message_center_->HasPopupNotifications()) {
-    if (delegate_)
-      delegate_->HidePopups();
     popups_visible_ = false;
   } else if (!popups_visible_ && message_center_->HasPopupNotifications()) {
-    if (delegate_)
-      delegate_->ShowPopups();
+    alignment_delegate_->StartObserving(display::Screen::GetScreen());
     popups_visible_ = true;
   }
 }
diff --git a/chrome/browser/notifications/popups_only_ui_controller.h b/chrome/browser/notifications/popups_only_ui_controller.h
index eef747d..e433b03 100644
--- a/chrome/browser/notifications/popups_only_ui_controller.h
+++ b/chrome/browser/notifications/popups_only_ui_controller.h
@@ -11,22 +11,17 @@
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_observer.h"
 
+namespace message_center {
+class DesktopPopupAlignmentDelegate;
+class MessagePopupCollection;
+}  // namespace message_center
+
 // A message center view implementation that shows notification popups (toasts)
 // in the corner of the screen, but has no dedicated message center (widget with
 // multiple notifications inside). This is used on Windows and Linux for
 // non-native notifications.
 class PopupsOnlyUiController : public message_center::MessageCenterObserver {
  public:
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-    virtual void ShowPopups() = 0;
-    virtual void HidePopups() = 0;
-  };
-
-  // Implementations are platform specific.
-  static std::unique_ptr<Delegate> CreateDelegate();
-
   PopupsOnlyUiController();
   ~PopupsOnlyUiController() override;
 
@@ -42,12 +37,13 @@
   void OnBlockingStateChanged(
       message_center::NotificationBlocker* blocker) override;
 
-  Delegate* delegate() { return delegate_.get(); }
   bool popups_visible() const { return popups_visible_; }
 
  private:
   message_center::MessageCenter* const message_center_;
-  std::unique_ptr<Delegate> delegate_;
+  std::unique_ptr<message_center::MessagePopupCollection> popup_collection_;
+  std::unique_ptr<message_center::DesktopPopupAlignmentDelegate>
+      alignment_delegate_;
 
   // Update the visibility of the popup bubbles. Shows or hides them if
   // necessary.
diff --git a/chrome/browser/ui/views/message_center/popups_only_ui_delegate_unittest.cc b/chrome/browser/notifications/popups_only_ui_controller_unittest.cc
similarity index 90%
rename from chrome/browser/ui/views/message_center/popups_only_ui_delegate_unittest.cc
rename to chrome/browser/notifications/popups_only_ui_controller_unittest.cc
index 60393db..9b3e91f 100644
--- a/chrome/browser/ui/views/message_center/popups_only_ui_delegate_unittest.cc
+++ b/chrome/browser/notifications/popups_only_ui_controller_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/message_center/popups_only_ui_delegate.h"
+#include "chrome/browser/notifications/popups_only_ui_controller.h"
 
 #include <stddef.h>
 
@@ -10,7 +10,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/browser/notifications/popups_only_ui_controller.h"
 #include "content/public/test/test_utils.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification_list.h"
@@ -31,10 +30,10 @@
 
 namespace {
 
-class PopupsOnlyUiDelegateTest : public views::test::WidgetTest {
+class PopupsOnlyUiControllerTest : public views::test::WidgetTest {
  public:
-  PopupsOnlyUiDelegateTest() = default;
-  ~PopupsOnlyUiDelegateTest() override = default;
+  PopupsOnlyUiControllerTest() = default;
+  ~PopupsOnlyUiControllerTest() override = default;
 
   void SetUp() override {
     set_native_widget_type(NativeWidgetType::kDesktop);
@@ -88,10 +87,10 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(PopupsOnlyUiDelegateTest);
+  DISALLOW_COPY_AND_ASSIGN(PopupsOnlyUiControllerTest);
 };
 
-TEST_F(PopupsOnlyUiDelegateTest, WebNotificationPopupBubble) {
+TEST_F(PopupsOnlyUiControllerTest, WebNotificationPopupBubble) {
   auto ui_controller = std::make_unique<PopupsOnlyUiController>();
 
   // Adding a notification should show the popup bubble.
@@ -110,11 +109,9 @@
   // Removing the visible notification should hide the popup bubble.
   RemoveNotification("id2");
   EXPECT_FALSE(ui_controller->popups_visible());
-
-  ui_controller->delegate()->HidePopups();
 }
 
-TEST_F(PopupsOnlyUiDelegateTest, ManyPopupNotifications) {
+TEST_F(PopupsOnlyUiControllerTest, ManyPopupNotifications) {
   auto ui_controller = std::make_unique<PopupsOnlyUiController>();
 
   // Add the max visible popup notifications +1, ensure the correct num visible.
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 241c0ed1..eb303775 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -122,14 +122,14 @@
   // Add existing credential into loginDB. It should be the only thing that's
   // available in the store.
   auto login_db = std::make_unique<password_manager::LoginDatabase>(
-      test_login_db_file_path(), /*is_account_store=*/false);
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   ASSERT_TRUE(login_db->Init());
   ignore_result(login_db->AddLogin(MakePasswordForm()));
   login_db.reset();
 
   // Create the store.
   login_db = std::make_unique<password_manager::LoginDatabase>(
-      test_login_db_file_path(), /*is_account_store=*/false);
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   scoped_refptr<PasswordStoreX> store =
       new PasswordStoreX(std::move(login_db), fake_pref_service());
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
@@ -146,8 +146,8 @@
   WaitForPasswordStore();
 
   // Check if the database is encrypted.
-  password_manager::LoginDatabase login_db2(test_login_db_file_path(),
-                                            /*is_account_store=*/false);
+  password_manager::LoginDatabase login_db2(
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   // Disable encryption.
   login_db2.disable_encryption();
   EXPECT_TRUE(login_db2.Init());
@@ -173,7 +173,7 @@
 
   // Create the store with an empty database.
   auto login_db = std::make_unique<password_manager::LoginDatabase>(
-      test_login_db_file_path(), /*is_account_store=*/false);
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   password_manager::LoginDatabase* login_db_ptr = login_db.get();
 
   scoped_refptr<PasswordStoreX> store =
@@ -190,8 +190,8 @@
   WaitForPasswordStore();
 
   // Check if the database is encrypted.
-  password_manager::LoginDatabase login_db2(test_login_db_file_path(),
-                                            /*is_account_store=*/false);
+  password_manager::LoginDatabase login_db2(
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   login_db2.disable_encryption();
   EXPECT_TRUE(login_db2.Init());
   // Read the password again.
@@ -220,7 +220,7 @@
   // Add existing credential into loginDB.
   auto existing_login = MakePasswordForm();
   auto login_db = std::make_unique<password_manager::LoginDatabase>(
-      test_login_db_file_path(), /*is_account_store=*/false);
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   login_db->disable_encryption();
   ASSERT_TRUE(login_db->Init());
   ignore_result(login_db->AddLogin(existing_login));
@@ -228,7 +228,7 @@
 
   // Create the store with a non-empty database.
   login_db = std::make_unique<password_manager::LoginDatabase>(
-      test_login_db_file_path(), /*is_account_store=*/false);
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   password_manager::LoginDatabase* login_db_ptr = login_db.get();
 
   scoped_refptr<PasswordStoreX> store =
@@ -247,8 +247,8 @@
   WaitForPasswordStore();
 
   // Check that the database is encrypted.
-  password_manager::LoginDatabase login_db2(test_login_db_file_path(),
-                                            /*is_account_store=*/false);
+  password_manager::LoginDatabase login_db2(
+      test_login_db_file_path(), password_manager::IsAccountStore(false));
   // Disable encryption and get the raw values. An encrypted database would have
   // read both encrypted and unencrypted entries.
   login_db2.disable_encryption();
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 9a779317..2262e66 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -866,7 +866,10 @@
   // Add shared clipboard menu item and copy items.
   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
     DCHECK(!editable);
-    AppendSharedClipboardItems();
+    // If this is a link, shared clipboard will be shown along with link items
+    // (AppendLinkItems), otherwise show it here along with copy items.
+    if (params_.link_url.is_empty())
+      AppendSharedClipboardItems();
     AppendCopyItem();
   }
 
@@ -1262,11 +1265,14 @@
       }
     }
 #endif  // !defined(OS_CHROMEOS)
+    AppendSharedClipboardItems();
     if (browser && send_tab_to_self::ShouldOfferFeatureForLink(
                        active_web_contents, params_.link_url)) {
       send_tab_to_self::RecordSendTabToSelfClickResult(
           send_tab_to_self::kLinkMenu, SendTabToSelfClickResult::kShowItem);
-      menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
+      // If Shared Clipboard is available don't add the separator.
+      if (!ShouldOfferSharedClipboard(browser_context_, params_.selection_text))
+        menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
       if (send_tab_to_self::GetValidDeviceCount(GetBrowser()->profile()) == 1) {
 #if defined(OS_MACOSX)
         menu_model_.AddItem(IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET,
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css
index b463267..e25333c 100644
--- a/chrome/browser/resources/chromeos/camera/src/css/main.css
+++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -229,6 +229,11 @@
   pointer-events: auto;
 }
 
+body:not(.streaming) #modes-group,
+body.taking #modes-group {
+  opacity: 0.38;
+}
+
 .mode-item {
   flex: 0 0 var(--mode-item-height);
   position: relative;
diff --git a/chrome/browser/resources/chromeos/camera/src/js/background.js b/chrome/browser/resources/chromeos/camera/src/js/background.js
index 977c0bd..ce7c134 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/background.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/background.js
@@ -36,15 +36,6 @@
 cca.bg.TOPBAR_COLOR = '#000000';
 
 /**
- * Whether the main AppWindow is created. It's used in test to ensure that we
- * won't connect to the main.html target before the window is created, otherwise
- * the window might disappear.
- * @type {boolean}
- * @deprecated This flag would be removed after we migrate CCA Tast tests.
- */
-cca.bg.appWindowCreated = false;
-
-/**
  * It's used in test to ensure that we won't connect to the main.html target
  * before the window is created, otherwise the window might disappear.
  * @type {?function(): undefined}
@@ -89,7 +80,6 @@
         chrome.storage.local.set({maximized: inAppWindow.isMaximized()});
         chrome.storage.local.set({fullscreen: inAppWindow.isFullscreen()});
       });
-      cca.bg.appWindowCreated = true;
       if (cca.bg.onAppWindowCreatedForTesting !== null) {
         cca.bg.onAppWindowCreatedForTesting();
       }
@@ -97,4 +87,28 @@
   });
 };
 
+/**
+ * Handles messages from the test extension used in Tast.
+ * @param {*} message The message sent by the calling script.
+ * @param {!MessageSender} sender
+ * @param {function(*): void} sendResponse
+ * @return {boolean|undefined} True to indicate the response is sent
+ *     asynchronously.
+ */
+cca.bg.handleExternalMessageFromTest = function(message, sender, sendResponse) {
+  if (sender.id !== 'behllobkkfkfnphdnhnkndlbkcpglgmj') {
+    console.warn(`Unknown sender id: ${sender.id}`);
+    return;
+  }
+  switch (message.action) {
+    case 'SET_WINDOW_CREATED_CALLBACK':
+      cca.bg.onAppWindowCreatedForTesting = sendResponse;
+      return true;
+    default:
+      console.warn(`Unknown action: ${message.action}`);
+  }
+};
+
 chrome.app.runtime.onLaunched.addListener(cca.bg.create);
+chrome.runtime.onMessageExternal.addListener(
+    cca.bg.handleExternalMessageFromTest);
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_permission_view.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_permission_view.html
index 7fc3dc8..6b2284f8 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_permission_view.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_permission_view.html
@@ -13,7 +13,6 @@
   <template>
     <style include="app-management-shared-css">
     </style>
-
     <div class="permission-list">
       <app-management-pin-to-shelf-item
         id="pin-to-shelf-setting"
@@ -33,7 +32,7 @@
           hidden$="[[!isArcSupported_]]">
           <div class="header-text">$i18n{permissions}</div>
         </div>
-        <div class="indented-permission-block">
+        <div class="permission-list indented-permission-block">
           <app-management-permission-item class="subpermission-row"
             icon="app-management:location"
             permission-label="$i18n{location}"
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_permission_view.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_permission_view.html
index 260da0d..dff2a290 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_permission_view.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_permission_view.html
@@ -28,7 +28,7 @@
         <div class="permission-section-header">
           <div class="header-text">$i18n{permissions}</div>
         </div>
-        <div class="indented-permission-block">
+        <div class="permission-list indented-permission-block">
           <app-management-permission-item id="location"
             class="subpermission-row" icon="app-management:location"
             permission-label="$i18n{location}"
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.html
index 0b0a5f99..2b12a42 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.html
@@ -17,12 +17,12 @@
     --header-text-color: #5A5A5A;
     --permission-icon-color: #757575;
     --permission-icon-padding: 20px;
-    --permission-list-item-height: 64px;
-    --text-permission-list-row-height: 40px;
+    --permission-list-item-height: 48px;
     --primary-text-color: rgba(0, 0, 0, 0.87);
     --row-item-icon-padding: 12px;
     --secondary-font-weight: 400;
     --secondary-text-color: rgba(0, 0, 0, 0.54);
+    --text-permission-list-row-height: 40px;
   }
 </style>
 </custom-style>
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
index 5905bdc0..7a5e5143 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
@@ -178,10 +179,13 @@
           </settings-parental-controls-page>
         </template>
 
-        <template is="dom-if" if="[[isKerberosEnabled_]]">
+        <template is="dom-if" if="[[pageVisibility.people.kerberosAccounts]]">
           <cr-link-row id="kerberos-accounts-subpage-trigger" class="hr"
               on-click="onKerberosAccountsTap_"
-              label="$i18n{kerberosAccountsSubMenuLabel}"></cr-link-row>
+              label="$i18n{kerberosAccountsSubMenuLabel}">
+            <cr-policy-indicator indicator-type="userPolicy">
+            </cr-policy-indicator>
+          </cr-link-row>
         </template>
 
       </div>
@@ -246,7 +250,7 @@
           <settings-account-manager></settings-account-manager>
         </settings-subpage>
       </template>
-      <template is="dom-if" if="[[isKerberosEnabled_]]">
+      <template is="dom-if" if="[[pageVisibility.people.kerberosAccounts]]">
         <template is="dom-if" route-path="/kerberosAccounts">
           <settings-subpage
               associated-control="[[$$('#kerberos-accounts-subpage-trigger')]]"
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js
index b678d52..05d4251 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js
@@ -103,18 +103,6 @@
       readOnly: true,
     },
 
-    /**
-     * True if Chrome OS Kerberos support is enabled.
-     * @private
-     */
-    isKerberosEnabled_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('isKerberosEnabled');
-      },
-      readOnly: true,
-    },
-
     /** @private */
     showParentalControls_: {
       type: Boolean,
diff --git a/chrome/browser/resources/settings/page_visibility.js b/chrome/browser/resources/settings/page_visibility.js
index 88823614..6096033fa 100644
--- a/chrome/browser/resources/settings/page_visibility.js
+++ b/chrome/browser/resources/settings/page_visibility.js
@@ -99,6 +99,11 @@
   let pageVisibility;
 
   const showOSSettings = loadTimeData.getBoolean('showOSSettings');
+  const isAccountManagerEnabled =
+      loadTimeData.valueExists('isAccountManagerEnabled') &&
+      loadTimeData.getBoolean('isAccountManagerEnabled');
+  const isKerberosEnabled = loadTimeData.valueExists('isKerberosEnabled') &&
+      loadTimeData.getBoolean('isKerberosEnabled');
 
   if (loadTimeData.getBoolean('isGuest')) {
     // "if not chromeos" and "if chromeos" in two completely separate blocks
@@ -168,8 +173,8 @@
       autofill: true,
       people: {
         lockScreen: showOSSettings,
-        kerberosAccounts: showOSSettings,
-        googleAccounts: showOSSettings,
+        kerberosAccounts: showOSSettings && isKerberosEnabled,
+        googleAccounts: showOSSettings && isAccountManagerEnabled,
         manageUsers: showOSSettings,
       },
       onStartup: true,
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 409e5662..327da536 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -272,8 +272,7 @@
                 prefs.settings.enable_screen_lock.value)]]"
             hidden="[[!pageVisibility.people.lockScreen]]"></cr-link-row>
 
-        <template is="dom-if" if="[[shouldShowAccountManager_(
-            isAccountManagerEnabled_, pageVisibility.people.googleAccounts)]]">
+        <template is="dom-if" if="[[pageVisibility.people.googleAccounts]]">
           <cr-link-row id="account-manager-subpage-trigger" class="hr"
               on-click="onAccountManagerTap_"
               label="$i18n{accountManagerSubMenuLabel}"></cr-link-row>
@@ -287,8 +286,7 @@
             hidden="[[!pageVisibility.people.manageUsers]]">
         </cr-link-row>
 
-        <template is="dom-if" if="[[shouldShowKerberos_(
-            isKerberosEnabled_, pageVisibility.people.kerberosAccounts)]]">
+        <template is="dom-if" if="[[pageVisibility.people.kerberosAccounts]]">
           <cr-link-row id="kerberos-accounts-subpage-trigger" class="hr"
               on-click="onKerberosAccountsTap_"
               label="$i18n{kerberosAccountsSubMenuLabel}">
@@ -375,8 +373,7 @@
           <settings-change-picture></settings-change-picture>
         </settings-subpage>
       </template>
-      <template is="dom-if" if="[[shouldShowAccountManager_(
-          isAccountManagerEnabled_, pageVisibility.people.googleAccounts)]]">
+      <template is="dom-if" if="[[pageVisibility.people.googleAccounts]]">
         <template is="dom-if" route-path="/accountManager">
           <settings-subpage
               associated-control="[[$$('#account-manager-subpage-trigger')]]"
@@ -385,8 +382,7 @@
           </settings-subpage>
         </template>
       </template>
-      <template is="dom-if" if="[[shouldShowKerberos_(
-          isKerberosEnabled_, pageVisibility.people.kerberosAccounts)]]">
+      <template is="dom-if" if="[[pageVisibility.people.kerberosAccounts]]">
         <template is="dom-if" route-path="/kerberosAccounts">
           <settings-subpage
               associated-control="[[$$('#kerberos-accounts-subpage-trigger')]]"
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index ab465b3..988352af 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -142,30 +142,6 @@
       readOnly: true,
     },
 
-    /**
-     * True if Chrome OS Account Manager is enabled.
-     * @private
-     */
-    isAccountManagerEnabled_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('isAccountManagerEnabled');
-      },
-      readOnly: true,
-    },
-
-    /**
-     * True if Chrome OS Kerberos support is enabled.
-     * @private
-     */
-    isKerberosEnabled_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('isKerberosEnabled');
-      },
-      readOnly: true,
-    },
-
     /** @private */
     showParentalControls_: {
       type: Boolean,
@@ -236,7 +212,7 @@
     let useProfileNameAndIcon = true;
     // <if expr="chromeos">
     if (!loadTimeData.getBoolean('showOSSettings') &&
-        this.isAccountManagerEnabled_) {
+        loadTimeData.getBoolean('isAccountManagerEnabled')) {
       // If this is SplitSettings and we have the Google Account manager,
       // prefer the GAIA name and icon.
       useProfileNameAndIcon = false;
@@ -524,18 +500,6 @@
   onManageOtherPeople_: function() {
     settings.navigateTo(settings.routes.ACCOUNTS);
   },
-
-  /** @private */
-  shouldShowAccountManager_: function() {
-    return this.isAccountManagerEnabled_ &&
-        this.pageVisibility.people.googleAccounts;
-  },
-
-  /** @private */
-  shouldShowKerberos_: function() {
-    return this.isKerberosEnabled_ &&
-        this.pageVisibility.people.kerberosAccounts;
-  },
   // </if>
 
   // <if expr="not chromeos">
diff --git a/chrome/browser/safe_browsing/download_protection/two_phase_uploader_unittest.cc b/chrome/browser/safe_browsing/download_protection/two_phase_uploader_unittest.cc
index b060db9..e285f4fb 100644
--- a/chrome/browser/safe_browsing/download_protection/two_phase_uploader_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/two_phase_uploader_unittest.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/net_errors.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/network_context.h"
@@ -81,12 +82,13 @@
             network::NetworkService::GetNetworkServiceForTesting());
 
     // A NetworkContextClient is needed for uploads to work.
-    network::mojom::NetworkContextClientPtr network_context_client_ptr;
+    mojo::PendingRemote<network::mojom::NetworkContextClient>
+        network_context_client_remote;
     network_context_client_ =
         std::make_unique<network::TestNetworkContextClient>(
-            mojo::MakeRequest(&network_context_client_ptr));
+            network_context_client_remote.InitWithNewPipeAndPassReceiver());
     shared_url_loader_factory_->network_context()->SetClient(
-        std::move(network_context_client_ptr));
+        std::move(network_context_client_remote));
   }
 
  protected:
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc
index c5419ac9..757d06c 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc
@@ -58,7 +58,8 @@
                        /* gcm_driver= */ nullptr,
                        /* device_info_tracker= */ nullptr,
                        /* local_device_info_provider= */ nullptr,
-                       /* sync_service */ nullptr) {}
+                       /* sync_service */ nullptr,
+                       /* notification_display_service= */ nullptr) {}
 
   ~MockSharingService() override = default;
 
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
index b3702f7..07aa04f 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
@@ -52,7 +52,8 @@
                        /* gcm_driver= */ nullptr,
                        /* device_info_tracker= */ nullptr,
                        /* local_device_info_provider= */ nullptr,
-                       /* sync_service */ nullptr) {}
+                       /* sync_service= */ nullptr,
+                       /* notification_display_service= */ nullptr) {}
 
   ~MockSharingService() override = default;
 
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc
index 1f22d46d..c643179c 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc
@@ -49,7 +49,8 @@
                        /* gcm_driver= */ nullptr,
                        /* device_info_tracker= */ nullptr,
                        /* local_device_info_provider= */ nullptr,
-                       /* sync_service */ nullptr) {}
+                       /* sync_service */ nullptr,
+                       /* notification_display_service= */ nullptr) {}
 
   ~MockSharingService() override = default;
 
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc
index 307482d..99bac5d 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc
@@ -54,7 +54,8 @@
                        /* gcm_driver= */ nullptr,
                        /* device_info_tracker= */ nullptr,
                        /* local_device_info_provider= */ nullptr,
-                       /* sync_service */ nullptr) {}
+                       /* sync_service */ nullptr,
+                       /* notification_display_service= */ nullptr) {}
 
   ~MockSharingService() override = default;
 
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.cc
new file mode 100644
index 0000000..b0022f3
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.cc
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/sharing/proto/shared_clipboard_message.pb.h"
+#include "chrome/browser/sharing/proto/sharing_message.pb.h"
+#include "chrome/browser/sharing/sharing_service.h"
+#include "components/sync_device_info/device_info.h"
+#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+
+SharedClipboardMessageHandler::SharedClipboardMessageHandler(
+    SharingService* sharing_service)
+    : sharing_service_(sharing_service) {}
+
+SharedClipboardMessageHandler::~SharedClipboardMessageHandler() = default;
+
+void SharedClipboardMessageHandler::OnMessage(
+    const chrome_browser_sharing::SharingMessage& message) {
+  DCHECK(message.has_shared_clipboard_message());
+
+  ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
+      .WriteText(base::UTF8ToUTF16(message.shared_clipboard_message().text()));
+
+  std::unique_ptr<syncer::DeviceInfo> device =
+      sharing_service_->GetDeviceByGuid(message.sender_guid());
+  if (device)
+    ShowNotification(std::move(device));
+}
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.h b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.h
new file mode 100644
index 0000000..994aa69
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.h
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_H_
+#define CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/sharing/sharing_message_handler.h"
+
+namespace syncer {
+class DeviceInfo;
+}  // namespace syncer
+
+class SharingService;
+
+// Handles incoming messages for the shared clipboard feature.
+class SharedClipboardMessageHandler : public SharingMessageHandler {
+ public:
+  explicit SharedClipboardMessageHandler(SharingService* sharing_service);
+  ~SharedClipboardMessageHandler() override;
+
+  // SharingMessageHandler implementation:
+  void OnMessage(
+      const chrome_browser_sharing::SharingMessage& message) override;
+
+ protected:
+  // Called after the message has been copied to the clipboard. Implementers
+  // should display a notification using information from |device_info|.
+  virtual void ShowNotification(
+      std::unique_ptr<syncer::DeviceInfo> device_info) = 0;
+
+ private:
+  SharingService* sharing_service_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedClipboardMessageHandler);
+};
+
+#endif  // CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_H_
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.cc
index 95a4d2d..6d16e431 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.cc
@@ -4,41 +4,23 @@
 
 #include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h"
 
-#include <memory>
-#include <string>
-
 #include "base/android/jni_string.h"
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
 #include "chrome/android/chrome_jni_headers/SharedClipboardMessageHandler_jni.h"
-#include "chrome/browser/sharing/proto/shared_clipboard_message.pb.h"
-#include "chrome/browser/sharing/proto/sharing_message.pb.h"
-#include "chrome/browser/sharing/sharing_service.h"
 #include "components/sync_device_info/device_info.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 
-SharedClipboardMessageHandler::SharedClipboardMessageHandler(
+SharedClipboardMessageHandlerAndroid::SharedClipboardMessageHandlerAndroid(
     SharingService* sharing_service)
-    : sharing_service_(sharing_service) {}
+    : SharedClipboardMessageHandler(sharing_service) {}
 
-SharedClipboardMessageHandler::~SharedClipboardMessageHandler() = default;
+SharedClipboardMessageHandlerAndroid::~SharedClipboardMessageHandlerAndroid() =
+    default;
 
-void SharedClipboardMessageHandler::OnMessage(
-    const chrome_browser_sharing::SharingMessage& message) {
-  DCHECK(message.has_shared_clipboard_message());
-
-  ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
-      .WriteText(base::UTF8ToUTF16(message.shared_clipboard_message().text()));
-
-  std::string device_name;
-  std::unique_ptr<syncer::DeviceInfo> device =
-      sharing_service_->GetDeviceByGuid(message.sender_guid());
-  if (device)
-    device_name = device->client_name();
-
+void SharedClipboardMessageHandlerAndroid::ShowNotification(
+    std::unique_ptr<syncer::DeviceInfo> device_info) {
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SharedClipboardMessageHandler_showNotification(
-      env, base::android::ConvertUTF8ToJavaString(env, device_name));
+      env,
+      base::android::ConvertUTF8ToJavaString(env, device_info->client_name()));
 }
-
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h
index 59758363..bbdad70 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h
@@ -6,24 +6,23 @@
 #define CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_ANDROID_H_
 
 #include "base/macros.h"
-#include "chrome/browser/sharing/sharing_message_handler.h"
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.h"
 
 class SharingService;
 
-// Handles incoming messages for the shared clipboard feature.
-class SharedClipboardMessageHandler : public SharingMessageHandler {
+class SharedClipboardMessageHandlerAndroid
+    : public SharedClipboardMessageHandler {
  public:
-  explicit SharedClipboardMessageHandler(SharingService* sharing_service);
-  ~SharedClipboardMessageHandler() override;
-
-  // SharingMessageHandler implementation:
-  void OnMessage(
-      const chrome_browser_sharing::SharingMessage& message) override;
+  explicit SharedClipboardMessageHandlerAndroid(
+      SharingService* sharing_service);
+  ~SharedClipboardMessageHandlerAndroid() override;
 
  private:
-  SharingService* sharing_service_ = nullptr;
+  // SharedClipboardMessageHandler implementation.
+  void ShowNotification(
+      std::unique_ptr<syncer::DeviceInfo> device_info) override;
 
-  DISALLOW_COPY_AND_ASSIGN(SharedClipboardMessageHandler);
+  DISALLOW_COPY_AND_ASSIGN(SharedClipboardMessageHandlerAndroid);
 };
 
 #endif  // CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_ANDROID_H_
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.cc
new file mode 100644
index 0000000..1072d7b
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h"
+
+#include "base/guid.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/sync_device_info/device_info.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notifier_id.h"
+#include "url/gurl.h"
+
+SharedClipboardMessageHandlerDesktop::SharedClipboardMessageHandlerDesktop(
+    SharingService* sharing_service,
+    NotificationDisplayService* notification_display_service)
+    : SharedClipboardMessageHandler(sharing_service),
+      notification_display_service_(notification_display_service) {}
+
+SharedClipboardMessageHandlerDesktop::~SharedClipboardMessageHandlerDesktop() =
+    default;
+
+void SharedClipboardMessageHandlerDesktop::ShowNotification(
+    std::unique_ptr<syncer::DeviceInfo> device_info) {
+  DCHECK(notification_display_service_);
+  DCHECK(device_info);
+
+  std::string notification_id = base::GenerateGUID();
+  std::string device_name = device_info->client_name();
+
+  message_center::Notification notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
+      l10n_util::GetStringFUTF16(
+          IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_NOTIFICATION_TITLE,
+          base::UTF8ToUTF16(device_name)),
+      l10n_util::GetStringUTF16(
+          IDS_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_NOTIFICATION_DESCRIPTION),
+      gfx::Image(gfx::CreateVectorIcon(vector_icons::kDevicesIcon, 64,
+                                       gfx::kChromeIconGrey)),
+      /* display_source= */ base::string16(),
+      /* origin_url= */ GURL(), message_center::NotifierId(),
+      message_center::RichNotificationData(),
+      /* delegate= */ nullptr);
+
+  notification_display_service_->Display(NotificationHandler::Type::SHARING,
+                                         notification, /* metadata= */ nullptr);
+}
\ No newline at end of file
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h
new file mode 100644
index 0000000..3894c4a
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_DESKTOP_H_
+#define CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_DESKTOP_H_
+
+#include "base/macros.h"
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler.h"
+
+class NotificationDisplayService;
+class SharingService;
+
+// Handles incoming messages for the shared clipboard feature.
+class SharedClipboardMessageHandlerDesktop
+    : public SharedClipboardMessageHandler {
+ public:
+  SharedClipboardMessageHandlerDesktop(
+      SharingService* sharing_service,
+      NotificationDisplayService* notification_display_service);
+  ~SharedClipboardMessageHandlerDesktop() override;
+
+ private:
+  // SharedClipboardMessageHandler implementation.
+  void ShowNotification(
+      std::unique_ptr<syncer::DeviceInfo> device_info) override;
+
+  NotificationDisplayService* notification_display_service_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedClipboardMessageHandlerDesktop);
+};
+
+#endif  // CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_MESSAGE_HANDLER_DESKTOP_H_
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop_unittest.cc
new file mode 100644
index 0000000..be3a24c
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h"
+
+#include <memory>
+
+#include "base/guid.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/stub_notification_display_service.h"
+#include "chrome/browser/sharing/proto/shared_clipboard_message.pb.h"
+#include "chrome/browser/sharing/sharing_fcm_handler.h"
+#include "chrome/browser/sharing/sharing_service.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/sync/protocol/sync_enums.pb.h"
+#include "components/sync_device_info/device_info.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard.h"
+
+namespace {
+
+const char kText[] = "clipboard";
+const char kClientName[] = "Foo's Pixel";
+
+class MockSharingService : public SharingService {
+ public:
+  explicit MockSharingService(
+      NotificationDisplayService* notification_display_service)
+      : SharingService(
+            /* sync_prefs= */ nullptr,
+            /* vapid_key_manager= */ nullptr,
+            /* sharing_device_registration= */ nullptr,
+            /* fcm_sender= */ nullptr,
+            std::make_unique<SharingFCMHandler>(nullptr, nullptr, nullptr),
+            /* gcm_driver= */ nullptr,
+            /* device_info_tracker= */ nullptr,
+            /* local_device_info_provider= */ nullptr,
+            /* sync_service */ nullptr,
+            notification_display_service) {}
+
+  ~MockSharingService() override = default;
+
+  MOCK_CONST_METHOD1(
+      GetDeviceByGuid,
+      std::unique_ptr<syncer::DeviceInfo>(const std::string& guid));
+};
+
+class SharedClipboardMessageHandlerTest : public testing::Test {
+ public:
+  SharedClipboardMessageHandlerTest() = default;
+
+  void SetUp() override {
+    notification_display_service_ =
+        std::make_unique<StubNotificationDisplayService>(&profile_);
+    sharing_service_ = std::make_unique<MockSharingService>(
+        notification_display_service_.get());
+    message_handler_ = std::make_unique<SharedClipboardMessageHandlerDesktop>(
+        sharing_service_.get(), notification_display_service_.get());
+  }
+
+  void TearDown() override {
+    ui::Clipboard::DestroyClipboardForCurrentThread();
+  }
+
+  chrome_browser_sharing::SharingMessage CreateMessage(const std::string guid) {
+    chrome_browser_sharing::SharingMessage message;
+    message.set_sender_guid(guid);
+    message.mutable_shared_clipboard_message()->set_text(kText);
+    return message;
+  }
+
+ protected:
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<StubNotificationDisplayService> notification_display_service_;
+  std::unique_ptr<MockSharingService> sharing_service_;
+  std::unique_ptr<SharedClipboardMessageHandlerDesktop> message_handler_;
+  TestingProfile profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedClipboardMessageHandlerTest);
+};
+
+}  // namespace
+
+TEST_F(SharedClipboardMessageHandlerTest, MessageCopiedToClipboard) {
+  std::string guid = base::GenerateGUID();
+  {
+    EXPECT_CALL(*sharing_service_, GetDeviceByGuid(guid))
+        .WillOnce(
+            [](const std::string& guid) -> std::unique_ptr<syncer::DeviceInfo> {
+              return nullptr;
+            });
+    message_handler_->OnMessage(CreateMessage(guid));
+  }
+  EXPECT_TRUE(notification_display_service_
+                  ->GetDisplayedNotificationsForType(
+                      NotificationHandler::Type::TRANSIENT)
+                  .empty());
+
+  base::string16 text;
+  ui::Clipboard::GetForCurrentThread()->ReadText(
+      ui::ClipboardBuffer::kCopyPaste, &text);
+  EXPECT_EQ(base::UTF16ToUTF8(text), kText);
+}
+
+TEST_F(SharedClipboardMessageHandlerTest, NotificationDisplayed) {
+  std::string guid = base::GenerateGUID();
+  {
+    EXPECT_CALL(*sharing_service_, GetDeviceByGuid(guid))
+        .WillOnce(
+            [](const std::string& guid) -> std::unique_ptr<syncer::DeviceInfo> {
+              return std::make_unique<syncer::DeviceInfo>(
+                  base::GenerateGUID(), kClientName,
+                  /* chrome_version= */ "78.0.0.0",
+                  /* sync_user_agent= */ "Chrome",
+                  sync_pb::SyncEnums::TYPE_LINUX,
+                  /* signin_scoped_device_id= */ base::GenerateGUID(),
+                  base::Time::Now(),
+                  /* send_tab_to_self_receiving_enabled= */ true);
+            });
+    message_handler_->OnMessage(CreateMessage(guid));
+  }
+  auto notifications =
+      notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::SHARING);
+  ASSERT_EQ(notifications.size(), 1u);
+
+  const message_center::Notification& notification = notifications[0];
+  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
+  EXPECT_EQ("Text shared from " + std::string(kClientName),
+            base::UTF16ToUTF8(notification.title()));
+  EXPECT_FALSE(notification.icon().IsEmpty());
+}
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc
index 7f58493467..cd33c6a 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc
@@ -52,7 +52,8 @@
                        /* gcm_driver= */ nullptr,
                        /* device_info_tracker= */ nullptr,
                        /* local_device_info_provider= */ nullptr,
-                       /* sync_service */ nullptr) {}
+                       /* sync_service */ nullptr,
+                       /* notification_display_service= */ nullptr) {}
 
   ~MockSharingService() override = default;
 
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc
index bd7dd31a..bc7f3a5 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc
@@ -43,7 +43,8 @@
                        /* gcm_driver= */ nullptr,
                        /* device_info_tracker= */ nullptr,
                        /* local_device_info_provider= */ nullptr,
-                       /* sync_service */ nullptr) {}
+                       /* sync_service */ nullptr,
+                       /* notification_display_service= */ nullptr) {}
 
   ~MockSharingService() override = default;
 
diff --git a/chrome/browser/sharing/sharing_device_registration.cc b/chrome/browser/sharing/sharing_device_registration.cc
index a2eb8d7..5c8cfd3 100644
--- a/chrome/browser/sharing/sharing_device_registration.cc
+++ b/chrome/browser/sharing/sharing_device_registration.cc
@@ -222,11 +222,7 @@
 }
 
 bool SharingDeviceRegistration::IsSharedClipboardSupported() const {
-#if defined(OS_ANDROID)
   return base::FeatureList::IsEnabled(kSharedClipboardReceiver);
-#else
-  return false;
-#endif
 }
 
 void SharingDeviceRegistration::SetDeviceCapabilityForTesting(
diff --git a/chrome/browser/sharing/sharing_notification_handler.cc b/chrome/browser/sharing/sharing_notification_handler.cc
new file mode 100644
index 0000000..35121d0
--- /dev/null
+++ b/chrome/browser/sharing/sharing_notification_handler.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/sharing_notification_handler.h"
+
+#include <utility>
+
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
+
+SharingNotificationHandler::SharingNotificationHandler() = default;
+SharingNotificationHandler::~SharingNotificationHandler() = default;
+
+void SharingNotificationHandler::OnClick(
+    Profile* profile,
+    const GURL& origin,
+    const std::string& notification_id,
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply,
+    base::OnceClosure completed_closure) {
+  NotificationDisplayServiceFactory::GetForProfile(profile)->Close(
+      NotificationHandler::Type::SHARING, notification_id);
+  std::move(completed_closure).Run();
+}
+
+void SharingNotificationHandler::OpenSettings(Profile* profile,
+                                              const GURL& origin) {}
diff --git a/chrome/browser/sharing/sharing_notification_handler.h b/chrome/browser/sharing/sharing_notification_handler.h
new file mode 100644
index 0000000..4e82cc1
--- /dev/null
+++ b/chrome/browser/sharing/sharing_notification_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_SHARING_NOTIFICATION_HANDLER_H_
+#define CHROME_BROWSER_SHARING_SHARING_NOTIFICATION_HANDLER_H_
+
+#include <map>
+#include <string>
+
+#include "chrome/browser/notifications/notification_handler.h"
+
+// Handles SHARING nofication actions.
+class SharingNotificationHandler : public NotificationHandler {
+ public:
+  SharingNotificationHandler();
+  ~SharingNotificationHandler() override;
+
+  // NotificationHandler implementation:
+  void OnClick(Profile* profile,
+               const GURL& origin,
+               const std::string& notification_id,
+               const base::Optional<int>& action_index,
+               const base::Optional<base::string16>& reply,
+               base::OnceClosure completed_closure) override;
+  void OpenSettings(Profile* profile, const GURL& origin) override;
+
+ protected:
+  DISALLOW_COPY_AND_ASSIGN(SharingNotificationHandler);
+};
+
+#endif  // CHROME_BROWSER_SHARING_SHARING_NOTIFICATION_HANDLER_H_
\ No newline at end of file
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc
index 93a5b42..0b16a86 100644
--- a/chrome/browser/sharing/sharing_service.cc
+++ b/chrome/browser/sharing/sharing_service.cc
@@ -44,7 +44,8 @@
     gcm::GCMDriver* gcm_driver,
     syncer::DeviceInfoTracker* device_info_tracker,
     syncer::LocalDeviceInfoProvider* local_device_info_provider,
-    syncer::SyncService* sync_service)
+    syncer::SyncService* sync_service,
+    NotificationDisplayService* notification_display_service)
     : sync_prefs_(std::move(sync_prefs)),
       vapid_key_manager_(std::move(vapid_key_manager)),
       sharing_device_registration_(std::move(sharing_device_registration)),
@@ -82,12 +83,19 @@
         sharing_service_proxy_android_.click_to_call_message_handler());
   }
 
+  shared_clipboard_message_handler_ =
+      std::make_unique<SharedClipboardMessageHandlerAndroid>(this);
+#else
+  shared_clipboard_message_handler_ =
+      std::make_unique<SharedClipboardMessageHandlerDesktop>(
+          this, notification_display_service);
+#endif  // defined(OS_ANDROID)
+
   if (base::FeatureList::IsEnabled(kSharedClipboardReceiver)) {
     fcm_handler_->AddSharingHandler(
         chrome_browser_sharing::SharingMessage::kSharedClipboardMessage,
-        sharing_service_proxy_android_.shared_clipboard_message_handler());
+        shared_clipboard_message_handler_.get());
   }
-#endif  // defined(OS_ANDROID)
 
   // If device has already registered before, start listening to FCM right away
   // to avoid missing messages.
diff --git a/chrome/browser/sharing/sharing_service.h b/chrome/browser/sharing/sharing_service.h
index 401f0d4f..9f4b6a4e 100644
--- a/chrome/browser/sharing/sharing_service.h
+++ b/chrome/browser/sharing/sharing_service.h
@@ -25,7 +25,10 @@
 #include "net/base/backoff_entry.h"
 
 #if defined(OS_ANDROID)
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h"
 #include "chrome/browser/sharing/sharing_service_proxy_android.h"
+#else
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h"
 #endif  // defined(OS_ANDROID)
 
 namespace gcm {
@@ -39,6 +42,7 @@
 class SyncService;
 }  // namespace syncer
 
+class NotificationDisplayService;
 class SharingFCMHandler;
 class SharingMessageHandler;
 class SharingSyncPreference;
@@ -74,11 +78,12 @@
       gcm::GCMDriver* gcm_driver,
       syncer::DeviceInfoTracker* device_info_tracker,
       syncer::LocalDeviceInfoProvider* local_device_info_provider,
-      syncer::SyncService* sync_service);
+      syncer::SyncService* sync_service,
+      NotificationDisplayService* notification_display_service);
   ~SharingService() override;
 
   // Returns the device matching |guid|, or nullptr if no match was found.
-  std::unique_ptr<syncer::DeviceInfo> GetDeviceByGuid(
+  virtual std::unique_ptr<syncer::DeviceInfo> GetDeviceByGuid(
       const std::string& guid) const;
 
   // Returns a list of DeviceInfo that is available to receive messages.
@@ -167,6 +172,9 @@
   SharingServiceProxyAndroid sharing_service_proxy_android_{this};
 #endif  // defined(OS_ANDROID)
 
+  std::unique_ptr<SharedClipboardMessageHandler>
+      shared_clipboard_message_handler_;
+
   base::WeakPtrFactory<SharingService> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SharingService);
diff --git a/chrome/browser/sharing/sharing_service_factory.cc b/chrome/browser/sharing/sharing_service_factory.cc
index a8c24fd..1d1457b 100644
--- a/chrome/browser/sharing/sharing_service_factory.cc
+++ b/chrome/browser/sharing/sharing_service_factory.cc
@@ -9,6 +9,7 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sharing/sharing_device_registration.h"
 #include "chrome/browser/sharing/sharing_fcm_handler.h"
@@ -51,6 +52,7 @@
   DependsOn(instance_id::InstanceIDProfileServiceFactory::GetInstance());
   DependsOn(DeviceInfoSyncServiceFactory::GetInstance());
   DependsOn(ProfileSyncServiceFactory::GetInstance());
+  DependsOn(NotificationDisplayServiceFactory::GetInstance());
 }
 
 SharingServiceFactory::~SharingServiceFactory() = default;
@@ -75,6 +77,8 @@
   syncer::LocalDeviceInfoProvider* local_device_info_provider =
       DeviceInfoSyncServiceFactory::GetForProfile(profile)
           ->GetLocalDeviceInfoProvider();
+  NotificationDisplayService* notification_display_service =
+      NotificationDisplayServiceFactory::GetForProfile(profile);
 
   std::unique_ptr<SharingSyncPreference> sync_prefs =
       std::make_unique<SharingSyncPreference>(profile->GetPrefs());
@@ -92,11 +96,11 @@
       std::make_unique<SharingFCMHandler>(gcm_driver, fcm_sender.get(),
                                           sync_prefs.get());
 
-  return new SharingService(std::move(sync_prefs), std::move(vapid_key_manager),
-                            std::move(sharing_device_registration),
-                            std::move(fcm_sender), std::move(fcm_handler),
-                            gcm_driver, device_info_tracker,
-                            local_device_info_provider, sync_service);
+  return new SharingService(
+      std::move(sync_prefs), std::move(vapid_key_manager),
+      std::move(sharing_device_registration), std::move(fcm_sender),
+      std::move(fcm_handler), gcm_driver, device_info_tracker,
+      local_device_info_provider, sync_service, notification_display_service);
 }
 
 content::BrowserContext* SharingServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/sharing/sharing_service_proxy_android.cc b/chrome/browser/sharing/sharing_service_proxy_android.cc
index 5bba96af..97db7e4 100644
--- a/chrome/browser/sharing/sharing_service_proxy_android.cc
+++ b/chrome/browser/sharing/sharing_service_proxy_android.cc
@@ -25,8 +25,7 @@
 
 SharingServiceProxyAndroid::SharingServiceProxyAndroid(
     SharingService* sharing_service)
-    : sharing_service_(sharing_service),
-      shared_clipboard_message_handler_(sharing_service) {
+    : sharing_service_(sharing_service) {
   DCHECK(sharing_service_);
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SharingServiceProxy_onProxyCreated(env,
diff --git a/chrome/browser/sharing/sharing_service_proxy_android.h b/chrome/browser/sharing/sharing_service_proxy_android.h
index 2fe658f..fb7a99d 100644
--- a/chrome/browser/sharing/sharing_service_proxy_android.h
+++ b/chrome/browser/sharing/sharing_service_proxy_android.h
@@ -8,7 +8,6 @@
 #include "base/android/jni_android.h"
 #include "base/macros.h"
 #include "chrome/browser/sharing/click_to_call/click_to_call_message_handler_android.h"
-#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_android.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
 
 class SharingService;
@@ -19,10 +18,6 @@
   explicit SharingServiceProxyAndroid(SharingService* sharing_service);
   ~SharingServiceProxyAndroid();
 
-  SharedClipboardMessageHandler* shared_clipboard_message_handler() {
-    return &shared_clipboard_message_handler_;
-  }
-
   ClickToCallMessageHandler* click_to_call_message_handler() {
     return &click_to_call_message_handler_;
   }
@@ -40,7 +35,6 @@
 
  private:
   SharingService* sharing_service_ = nullptr;
-  SharedClipboardMessageHandler shared_clipboard_message_handler_;
   ClickToCallMessageHandler click_to_call_message_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(SharingServiceProxyAndroid);
diff --git a/chrome/browser/sharing/sharing_service_unittest.cc b/chrome/browser/sharing/sharing_service_unittest.cc
index ebe1789..7daa91e 100644
--- a/chrome/browser/sharing/sharing_service_unittest.cc
+++ b/chrome/browser/sharing/sharing_service_unittest.cc
@@ -211,7 +211,8 @@
           base::WrapUnique(sharing_device_registration_),
           base::WrapUnique(fcm_sender_), base::WrapUnique(fcm_handler_),
           &fake_gcm_driver_, &device_info_tracker_,
-          &fake_local_device_info_provider_, &test_sync_service_);
+          &fake_local_device_info_provider_, &test_sync_service_,
+          /* notification_display_service= */ nullptr);
     }
     return sharing_service_.get();
   }
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index e8811b7..d944446 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -32,6 +32,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/metrics/metrics_service.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/cookie_settings_util.h"
 #include "components/signin/public/base/signin_buildflags.h"
@@ -343,6 +344,10 @@
 #endif
 }
 
+bool ChromeSigninClient::IsNonEnterpriseUser(const std::string& username) {
+  return policy::BrowserPolicyConnector::IsNonEnterpriseUser(username);
+}
+
 void ChromeSigninClient::SetURLLoaderFactoryForTest(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   url_loader_factory_for_testing_ = url_loader_factory;
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index 6c6f749..2f6d7c8 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -61,6 +61,7 @@
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       gaia::GaiaSource source) override;
+  bool IsNonEnterpriseUser(const std::string& username) override;
 
   // Returns a string describing the chrome version environment. Version format:
   // <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel">
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index df82660..ef5ac4e4 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -40,8 +40,6 @@
 // The UMA histograms that logs events related to Dice responses.
 const char kDiceResponseHeaderHistogram[] = "Signin.DiceResponseHeader";
 const char kDiceTokenFetchResultHistogram[] = "Signin.DiceTokenFetchResult";
-const char kChromePrimaryAccountStateOnWebSignoutHistogram[] =
-    "Signin.ChromePrimaryAccountStateOnWebSignout";
 
 // Used for UMA. Do not reorder, append new values at the end.
 enum DiceResponseHeader {
@@ -72,21 +70,6 @@
   kDiceTokenFetchResultCount
 };
 
-// Used for UMA. Do not reorder, append new values at the end.
-enum ChromePrimaryAccountStateInGaiaCookies {
-  // The user is not authenticated in Chrome.
-  kNoChromePrimaryAccount = 0,
-  // The user is authenticated in Chrome with the first Gaia account.
-  kChromePrimaryAccountIsFirstGaiaAccount = 1,
-  // The user is authenticated in Chrome with another Gaia account.
-  kChromePrimaryAccountIsSecondaryGaiaAccount = 2,
-  // The user is authenticated in Chrome with an account that is not in Gaia
-  // cookies.
-  kChromePrimaryAccountIsNotInGaiaAccounts = 3,
-
-  kChromePrimaryAccountStateInGaiaCookiesCount
-};
-
 class DiceResponseHandlerFactory : public BrowserContextKeyedServiceFactory {
  public:
   // Returns an instance of the factory singleton.
@@ -144,12 +127,6 @@
                             kDiceTokenFetchResultCount);
 }
 
-void RecordGaiaSignoutMetrics(ChromePrimaryAccountStateInGaiaCookies state) {
-  UMA_HISTOGRAM_ENUMERATION(kChromePrimaryAccountStateOnWebSignoutHistogram,
-                            state,
-                            kChromePrimaryAccountStateInGaiaCookiesCount);
-}
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -339,10 +316,6 @@
     if (signed_out_account == primary_account) {
       primary_account_signed_out = true;
       RecordDiceResponseHeader(kSignoutPrimary);
-      RecordGaiaSignoutMetrics(
-          (account_info.session_index == 0)
-              ? kChromePrimaryAccountIsFirstGaiaAccount
-              : kChromePrimaryAccountIsSecondaryGaiaAccount);
 
       if (account_consistency_ == signin::AccountConsistencyMethod::kDice) {
         // Put the account in error state.
@@ -372,12 +345,8 @@
     }
   }
 
-  if (!primary_account_signed_out) {
+  if (!primary_account_signed_out)
     RecordDiceResponseHeader(kSignoutSecondary);
-    RecordGaiaSignoutMetrics(primary_account.empty()
-                                 ? kNoChromePrimaryAccount
-                                 : kChromePrimaryAccountIsNotInGaiaAccounts);
-  }
 }
 
 void DiceResponseHandler::DeleteTokenFetcher(DiceTokenFetcher* token_fetcher) {
diff --git a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
index 353fb04..46a4d284 100644
--- a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/callback_list.h"
+#include "base/files/file_util.h"
 #include "base/macros.h"
+#include "base/path_service.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/defaults.h"
@@ -12,6 +14,7 @@
 #include "chrome/browser/sync/test/integration/secondary_account_helper.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
+#include "chrome/common/chrome_paths.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/profile_sync_service.h"
 #include "components/sync/driver/sync_driver_switches.h"
@@ -28,7 +31,13 @@
   allowed_types.PutAll(syncer::ControlTypes());
   return allowed_types;
 }
-#endif
+
+base::FilePath GetTestFilePathForCacheGuid() {
+  base::FilePath user_data_path;
+  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path);
+  return user_data_path.AppendASCII("SyncTestTmpCacheGuid");
+}
+#endif  // !defined(OS_CHROMEOS)
 
 class SingleClientSecondaryAccountSyncTest : public SyncTest {
  public:
@@ -149,4 +158,61 @@
 }
 #endif  // !defined(OS_CHROMEOS)
 
+// Regression test for crbug.com/955989 that verifies the cache GUID is not
+// reset upon restart of the browser, in standalone transport mode with
+// secondary accounts.
+//
+// The unconsented primary account (aka secondary account) isn't supported on
+// ChromeOS, see IdentityManager::ComputeUnconsentedPrimaryAccountInfo().
+#if !defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(SingleClientSecondaryAccountSyncTest,
+                       PRE_ReusesSameCacheGuid) {
+  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  secondary_account_helper::SignInSecondaryAccount(
+      profile(), &test_url_loader_factory_, "user@email.com");
+  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+
+  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
+            GetSyncService(0)->GetTransportState());
+
+  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->IsFirstSetupComplete());
+  ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
+
+  syncer::SyncPrefs prefs(GetProfile(0)->GetPrefs());
+  const std::string cache_guid = prefs.GetCacheGuid();
+  ASSERT_FALSE(cache_guid.empty());
+
+  // Save the cache GUID to file to remember after restart, for test
+  // verification purposes only.
+  ASSERT_NE(-1, base::WriteFile(GetTestFilePathForCacheGuid(),
+                                cache_guid.c_str(), cache_guid.size()));
+}
+#endif  // !defined(OS_CHROMEOS)
+
+// The unconsented primary account (aka secondary account) isn't supported on
+// ChromeOS, see IdentityManager::ComputeUnconsentedPrimaryAccountInfo().
+#if !defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(SingleClientSecondaryAccountSyncTest,
+                       ReusesSameCacheGuid) {
+  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+
+  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
+            GetSyncService(0)->GetTransportState());
+
+  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->IsFirstSetupComplete());
+  ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
+
+  syncer::SyncPrefs prefs(GetProfile(0)->GetPrefs());
+  ASSERT_FALSE(prefs.GetCacheGuid().empty());
+
+  std::string old_cache_guid;
+  ASSERT_TRUE(
+      base::ReadFileToString(GetTestFilePathForCacheGuid(), &old_cache_guid));
+  ASSERT_FALSE(old_cache_guid.empty());
+
+  EXPECT_EQ(old_cache_guid, prefs.GetCacheGuid());
+}
+#endif  // !defined(OS_CHROMEOS)
+
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index a67ab56c..4729e710 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -864,7 +864,14 @@
   ASSERT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id);
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, OneMetricReportedOnStartup) {
+// TODO(https://crbug.com/1000455) Flaky on CrOS.
+#if defined(OS_CHROMEOS)
+#define MAYBE_OneMetricReportedOnStartup DISABLED_OneMetricReportedOnStartup
+#else
+#define MAYBE_OneMetricReportedOnStartup OneMetricReportedOnStartup
+#endif
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       MAYBE_OneMetricReportedOnStartup) {
   // Set different data so that we get a full update.
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a5bb1a9..5975930 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2027,8 +2027,6 @@
       "user_manager.h",
       "views/external_protocol_dialog.cc",
       "views/external_protocol_dialog.h",
-      "views/message_center/popups_only_ui_delegate.cc",
-      "views/message_center/popups_only_ui_delegate.h",
       "views/profiles/badged_profile_photo.cc",
       "views/profiles/badged_profile_photo.h",
       "views/profiles/profile_menu_view.cc",
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index 2a89be2..4eaced40 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -20,9 +20,11 @@
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/task_runner_util.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_command_line.h"
 #include "base/values.h"
+#include "chrome/browser/apps/app_service/arc_icon_once_loader.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
@@ -2056,6 +2058,40 @@
   EXPECT_EQ(1 + scale_factors.size(), delegate.update_image_count());
 }
 
+TEST_P(ArcAppModelBuilderTest, IconLoaderCompressed) {
+  const arc::mojom::AppInfo& app = fake_apps()[0];
+  const std::string app_id = ArcAppTest::GetAppId(app);
+  const int icon_size =
+      app_list::AppListConfig::instance().grid_icon_dimension();
+  const std::vector<ui::ScaleFactor>& scale_factors =
+      ui::GetSupportedScaleFactors();
+  size_t num_compressed_images_seen = 0;
+
+  app_instance()->SendRefreshAppList(std::vector<arc::mojom::AppInfo>(
+      fake_apps().begin(), fake_apps().begin() + 1));
+
+  apps::ArcIconOnceLoader once_loader(profile());
+  once_loader.LoadIcon(
+      app_id, icon_size, apps::mojom::IconCompression::kCompressed,
+      base::BindLambdaForTesting([&](ArcAppIcon* icon) {
+        const std::map<ui::ScaleFactor, std::string>& compressed_images =
+            icon->compressed_images();
+        for (auto& scale_factor : scale_factors) {
+          auto iter = compressed_images.find(scale_factor);
+          if (iter != compressed_images.end()) {
+            num_compressed_images_seen++;
+            const std::string& compressed = iter->second;
+            // Check that |compressed| starts with the 8-byte PNG magic string.
+            EXPECT_EQ(compressed.substr(0, 8),
+                      "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a");
+          }
+        }
+      }));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(num_compressed_images_seen, scale_factors.size());
+}
+
 TEST_P(ArcAppModelIconTest, IconInvalidation) {
   ArcAppListPrefs* const prefs = ArcAppListPrefs::Get(profile_.get());
   ASSERT_TRUE(prefs);
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc
index 20e7003..601942b6e 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc
@@ -244,10 +244,17 @@
 }
 
 std::map<unsigned int, float> FrecencyPredictor::Rank(unsigned int condition) {
-  std::map<unsigned int, float> result;
+  float total = 0.0f;
   for (auto& pair : targets_) {
     DecayScore(&pair.second);
-    result[pair.first] = pair.second.last_score;
+    total += pair.second.last_score;
+  }
+  if (total == 0.0f)
+    return {};
+
+  std::map<unsigned int, float> result;
+  for (auto& pair : targets_) {
+    result[pair.first] = pair.second.last_score / total;
   }
   return result;
 }
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h
index 058eef8..3fd1163 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h
@@ -201,10 +201,18 @@
 };
 
 // FrecencyPredictor ranks targets according to their frecency, and
-// can only be used for zero-state predictions. This predictor allows for
-// frecency-based rankings with different configuration to that of the ranker's
-// FrecencyStore. If frecency-based rankings with the same configuration as the
-// store are needed, the DefaultPredictor should be used instead.
+// can only be used for zero-state predictions. This predictor has two
+// key differences from the DefaultPredictor:
+//
+//  1. The decay coefficient for ranking can be set separately from the
+//     RecurrenceRanker's target_decay parameter used for storage.
+//
+//  2. The scores returned by FrecencyPredictor::Rank are normalized to sum to
+//     1 (if there is at least one result). This is not the case for
+//     DefaultPredictor::Rank.
+//
+// If neither of the above differences are required, it is more efficient to
+// use DefaultPredictor.
 class FrecencyPredictor : public RecurrencePredictor {
  public:
   FrecencyPredictor(const FrecencyPredictorConfig& config,
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
index 9fcde933..13c108f 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
@@ -56,10 +56,11 @@
   predictor_->Train(4u, kCondition);
   predictor_->Train(6u, kCondition);
 
-  EXPECT_THAT(
-      predictor_->Rank(kCondition),
-      UnorderedElementsAre(Pair(2u, FloatEq(0.125f)), Pair(4u, FloatEq(0.25f)),
-                           Pair(6u, FloatEq(0.5f))));
+  const float total = 0.5f + 0.25f + 0.125f;
+  EXPECT_THAT(predictor_->Rank(kCondition),
+              UnorderedElementsAre(Pair(2u, FloatEq(0.125f / total)),
+                                   Pair(4u, FloatEq(0.25f / total)),
+                                   Pair(6u, FloatEq(0.5f / total))));
 }
 
 TEST_F(FrecencyPredictorTest, RecordAndRankComplex) {
@@ -70,11 +71,12 @@
   predictor_->Train(2u, kCondition);
 
   // Ranks should be deterministic.
+  const float total = 0.53125f + 0.3125f + 0.125f;
   for (int i = 0; i < 3; ++i) {
     EXPECT_THAT(predictor_->Rank(kCondition),
-                UnorderedElementsAre(Pair(2u, FloatEq(0.53125f)),
-                                     Pair(4u, FloatEq(0.3125f)),
-                                     Pair(6u, FloatEq(0.125f))));
+                UnorderedElementsAre(Pair(2u, FloatEq(0.53125f / total)),
+                                     Pair(4u, FloatEq(0.3125f / total)),
+                                     Pair(6u, FloatEq(0.125f / total))));
   }
 }
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
index 9f024fb..b611e5ab 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
@@ -459,9 +459,12 @@
   ranker.RemoveTarget("E");
   ranker.RenameTarget("E", "A");
 
-  EXPECT_THAT(ranker.Rank(), UnorderedElementsAre(Pair("A", FloatEq(0.09375f)),
-                                                  Pair("B", FloatEq(0.125f)),
-                                                  Pair("C", FloatEq(0.25f))));
+  // E with score 0.5 not yet removed from model.
+  const float total = 0.09375f + 0.125f + 0.25f + 0.5f;
+  EXPECT_THAT(ranker.Rank(),
+              UnorderedElementsAre(Pair("A", FloatEq(0.09375f / total)),
+                                   Pair("B", FloatEq(0.125f / total)),
+                                   Pair("C", FloatEq(0.25f / total))));
   ExpectErrors(/* fresh_model_created = */ true,
                /* using_fake_predictor = */ false);
 }
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index 2acda4a3..261e897 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -36,7 +36,6 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
-#include "ui/gfx/favicon_size.h"
 #include "ui/gfx/image/image_skia.h"
 #include "url/gurl.h"
 
@@ -44,20 +43,6 @@
 
 namespace {
 
-// Gets the icon to use if the extension app icon is not available.
-gfx::ImageSkia GetFallbackAppIcon(Browser* browser) {
-  gfx::ImageSkia page_icon = browser->GetCurrentPageIcon().AsImageSkia();
-  if (!page_icon.isNull())
-    return page_icon;
-
-  // The extension icon may be loading still. Return a transparent icon rather
-  // than using a placeholder to avoid flickering.
-  SkBitmap bitmap;
-  bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize);
-  bitmap.eraseColor(SK_ColorTRANSPARENT);
-  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
-}
-
 // Returns true if |app_url| and |page_url| are the same origin. To avoid
 // breaking Hosted Apps and Bookmark Apps that might redirect to sites in the
 // same domain but with "www.", this returns true if |page_url| is secure and in
@@ -211,16 +196,16 @@
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   if (!contents)
-    return GetFallbackAppIcon(browser());
+    return GetFallbackAppIcon();
 
   extensions::TabHelper* extensions_tab_helper =
       extensions::TabHelper::FromWebContents(contents);
   if (!extensions_tab_helper)
-    return GetFallbackAppIcon(browser());
+    return GetFallbackAppIcon();
 
   const SkBitmap* icon_bitmap = extensions_tab_helper->GetExtensionAppIcon();
   if (!icon_bitmap)
-    return GetFallbackAppIcon(browser());
+    return GetFallbackAppIcon();
 
   return gfx::ImageSkia::CreateFrom1xBitmap(*icon_bitmap);
 }
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_button.cc b/chrome/browser/ui/views/extensions/extensions_menu_button.cc
index 074a158c..54d8959 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_button.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_button.cc
@@ -4,41 +4,18 @@
 
 #include "chrome/browser/ui/views/extensions/extensions_menu_button.h"
 
-#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
-#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_item_view.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_view.h"
 #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
-#include "chrome/grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/button/image_button_factory.h"
-#include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/button/menu_button_controller.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/layout_provider.h"
-#include "ui/views/vector_icons.h"
-#include "ui/views/view_class_properties.h"
 
 const char ExtensionsMenuButton::kClassName[] = "ExtensionsMenuButton";
 
-namespace {
-
-constexpr int EXTENSION_PINNING = 14;
-
-void SetSecondaryButtonHighlightPath(views::Button* button) {
-  auto highlight_path = std::make_unique<SkPath>();
-  highlight_path->addOval(gfx::RectToSkRect(gfx::Rect(button->size())));
-  button->SetProperty(views::kHighlightPathKey, highlight_path.release());
-}
-
-}  // namespace
-
 ExtensionsMenuButton::ExtensionsMenuButton(
     Browser* browser,
     ExtensionsMenuItemView* parent,
@@ -52,12 +29,7 @@
                   true),
       browser_(browser),
       parent_(parent),
-      controller_(controller),
-      model_(ToolbarActionsModel::Get(browser_->profile())) {
-  // Set so the extension button receives enter/exit on children to retain hover
-  // status when hovering child views.
-  set_notify_enter_exit_on_child(true);
-  ConfigureSecondaryView();
+      controller_(controller) {
   set_auto_compute_tooltip(false);
   controller_->SetDelegate(this);
   UpdateState();
@@ -65,53 +37,12 @@
 
 ExtensionsMenuButton::~ExtensionsMenuButton() = default;
 
-void ExtensionsMenuButton::UpdatePinButton() {
-  pin_button_->SetTooltipText(l10n_util::GetStringUTF16(
-      IsPinned() ? IDS_EXTENSIONS_MENU_UNPIN_BUTTON_TOOLTIP
-                 : IDS_EXTENSIONS_MENU_PIN_BUTTON_TOOLTIP));
-  SkColor unpinned_icon_color =
-      ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors()
-          ? gfx::kGoogleGrey500
-          : gfx::kChromeIconGrey;
-  SkColor icon_color = IsPinned()
-                           ? GetNativeTheme()->GetSystemColor(
-                                 ui::NativeTheme::kColorId_ProminentButtonColor)
-                           : unpinned_icon_color;
-  views::SetImageFromVectorIcon(
-      pin_button_, IsPinned() ? views::kUnpinIcon : views::kPinIcon,
-      ExtensionsMenuItemView::kSecondaryIconSizeDp, icon_color);
-  pin_button_->SetVisible(IsPinned() || IsMouseHovered() || IsMenuRunning());
-}
-
-void ExtensionsMenuButton::OnMouseEntered(const ui::MouseEvent& event) {
-  UpdatePinButton();
-  // The layout manager does not get notified of visibility changes and the pin
-  // buttons has not be laid out before if it was invisible.
-  pin_button_->InvalidateLayout();
-  views::Button::OnMouseEntered(event);
-}
-
-void ExtensionsMenuButton::OnMouseExited(const ui::MouseEvent& event) {
-  UpdatePinButton();
-  views::Button::OnMouseExited(event);
-}
-
-void ExtensionsMenuButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  UpdatePinButton();
-  HoverButton::OnBoundsChanged(previous_bounds);
-}
-
 const char* ExtensionsMenuButton::GetClassName() const {
   return kClassName;
 }
 
 void ExtensionsMenuButton::ButtonPressed(Button* sender,
                                          const ui::Event& event) {
-  if (sender->GetID() == EXTENSION_PINNING) {
-    model_->SetActionVisibility(controller_->GetId(), !IsPinned());
-    return;
-  }
-  DCHECK_EQ(this, sender);
   controller_->ExecuteAction(true);
 }
 
@@ -150,30 +81,3 @@
 bool ExtensionsMenuButton::IsMenuRunning() const {
   return parent_->IsContextMenuRunning();
 }
-
-void ExtensionsMenuButton::ConfigureSecondaryView() {
-  views::View* container = secondary_view();
-  DCHECK(container->children().empty());
-  container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal));
-
-  const SkColor icon_color =
-      ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
-          ui::NativeTheme::kColorId_DefaultIconColor);
-
-  auto pin_button = views::CreateVectorImageButton(this);
-  pin_button->SetID(EXTENSION_PINNING);
-  pin_button->set_ink_drop_base_color(icon_color);
-  pin_button->SizeToPreferredSize();
-
-  pin_button_ = pin_button.get();
-  SetSecondaryButtonHighlightPath(pin_button_);
-  container->AddChildView(std::move(pin_button));
-}
-
-bool ExtensionsMenuButton::IsPinned() {
-  // |model_| can be null in unit tests.
-  if (!model_)
-    return false;
-  return model_->IsActionPinned(controller_->GetId());
-}
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_button.h b/chrome/browser/ui/views/extensions/extensions_menu_button.h
index f0a7043..71e722e 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_button.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_button.h
@@ -18,7 +18,6 @@
 
 namespace views {
 class Button;
-class ImageButton;
 }  // namespace views
 
 class ExtensionsMenuButton : public HoverButton,
@@ -37,11 +36,6 @@
   static const char kClassName[];
 
  private:
-  // views::Button:
-  void OnMouseEntered(const ui::MouseEvent& event) override;
-  void OnMouseExited(const ui::MouseEvent& event) override;
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
-
   // views::ButtonListener:
   const char* GetClassName() const override;
   void ButtonPressed(Button* sender, const ui::Event& event) override;
@@ -54,11 +48,6 @@
   void UpdateState() override;
   bool IsMenuRunning() const override;
 
-  // Configures the secondary (right-hand-side) view of this HoverButton.
-  void ConfigureSecondaryView();
-
-  bool IsPinned();
-
   Browser* const browser_;
 
   // The container containing this view.
@@ -67,10 +56,6 @@
   // Responsible for executing the extension's actions.
   ToolbarActionViewController* const controller_;
 
-  ToolbarActionsModel* const model_;
-
-  views::ImageButton* pin_button_ = nullptr;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionsMenuButton);
 };
 
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
index c752760..6c7a259 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
@@ -7,20 +7,23 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
 #include "chrome/browser/ui/views/extensions/extension_context_menu_controller.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_button.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/animation/ink_drop_host_view.h"
-#include "ui/views/layout/fill_layout.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/flex_layout_types.h"
-#include "ui/views/layout/grid_layout.h"
+#include "ui/views/vector_icons.h"
 #include "ui/views/view_class_properties.h"
 
 namespace {
 constexpr int EXTENSION_CONTEXT_MENU = 13;
+constexpr int EXTENSION_PINNING = 14;
 }  // namespace
 
 ExtensionsMenuItemView::ExtensionsMenuItemView(
@@ -28,7 +31,12 @@
     std::unique_ptr<ToolbarActionViewController> controller)
     : primary_action_button_(
           new ExtensionsMenuButton(browser, this, controller.get())),
-      controller_(std::move(controller)) {
+      controller_(std::move(controller)),
+      model_(ToolbarActionsModel::Get(browser->profile())) {
+  // Set so the extension button receives enter/exit on children to retain hover
+  // status when hovering child views.
+  set_notify_enter_exit_on_child(true);
+
   context_menu_controller_ = std::make_unique<ExtensionContextMenuController>(
       nullptr, controller_.get());
 
@@ -48,6 +56,12 @@
       ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
           ui::NativeTheme::kColorId_DefaultIconColor);
 
+  auto pin_button = views::CreateVectorImageButton(this);
+  pin_button->SetID(EXTENSION_PINNING);
+  pin_button->set_ink_drop_base_color(icon_color);
+  pin_button_ = pin_button.get();
+  AddChildView(std::move(pin_button));
+
   // TODO(pbos): There's complicated configuration code in place since menus
   // can't be triggered from ImageButtons. When MenuRunner::RunMenuAt accepts
   // views::Buttons, turn this into a views::ImageButton and use
@@ -79,6 +93,15 @@
 
 ExtensionsMenuItemView::~ExtensionsMenuItemView() = default;
 
+void ExtensionsMenuItemView::ButtonPressed(views::Button* sender,
+                                           const ui::Event& event) {
+  if (sender->GetID() == EXTENSION_PINNING) {
+    model_->SetActionVisibility(controller_->GetId(), !IsPinned());
+    return;
+  }
+  NOTREACHED();
+}
+
 void ExtensionsMenuItemView::OnMenuButtonClicked(views::Button* source,
                                                  const gfx::Point& point,
                                                  const ui::Event* event) {
@@ -90,13 +113,43 @@
 }
 
 void ExtensionsMenuItemView::UpdatePinButton() {
-  primary_action_button_->UpdatePinButton();
+  pin_button_->SetTooltipText(l10n_util::GetStringUTF16(
+      IsPinned() ? IDS_EXTENSIONS_MENU_UNPIN_BUTTON_TOOLTIP
+                 : IDS_EXTENSIONS_MENU_PIN_BUTTON_TOOLTIP));
+  SkColor unpinned_icon_color =
+      ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors()
+          ? gfx::kGoogleGrey500
+          : gfx::kChromeIconGrey;
+  SkColor icon_color = IsPinned()
+                           ? GetNativeTheme()->GetSystemColor(
+                                 ui::NativeTheme::kColorId_ProminentButtonColor)
+                           : unpinned_icon_color;
+  views::SetImageFromVectorIcon(
+      pin_button_, IsPinned() ? views::kUnpinIcon : views::kPinIcon,
+      kSecondaryIconSizeDp, icon_color);
+  pin_button_->SetVisible(IsPinned() || IsMouseHovered() ||
+                          IsContextMenuRunning());
+}
+
+void ExtensionsMenuItemView::OnMouseEntered(const ui::MouseEvent& event) {
+  UpdatePinButton();
+}
+
+void ExtensionsMenuItemView::OnMouseExited(const ui::MouseEvent& event) {
+  UpdatePinButton();
 }
 
 bool ExtensionsMenuItemView::IsContextMenuRunning() {
   return context_menu_controller_->IsMenuRunning();
 }
 
+bool ExtensionsMenuItemView::IsPinned() {
+  // |model_| can be null in unit tests.
+  if (!model_)
+    return false;
+  return model_->IsActionPinned(controller_->GetId());
+}
+
 ExtensionsMenuButton*
 ExtensionsMenuItemView::primary_action_button_for_testing() {
   return primary_action_button_;
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.h b/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
index b20a913..9a296ea 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
@@ -7,16 +7,18 @@
 
 #include <memory>
 
+#include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/menu_button_listener.h"
-#include "ui/views/layout/flex_layout.h"
 #include "ui/views/view.h"
 
 class Browser;
 class ExtensionContextMenuController;
 class ExtensionsMenuButton;
 class ToolbarActionViewController;
+class ToolbarActionsModel;
 
 namespace views {
+class ImageButton;
 class MenuButton;
 }  // namespace views
 
@@ -25,6 +27,7 @@
 // a button to pin the extension to the toolbar and a button for accessing the
 // associated context menu.
 class ExtensionsMenuItemView : public views::View,
+                               public views::ButtonListener,
                                public views::MenuButtonListener {
  public:
   static constexpr int kSecondaryIconSizeDp = 16;
@@ -34,6 +37,9 @@
       std::unique_ptr<ToolbarActionViewController> controller);
   ~ExtensionsMenuItemView() override;
 
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
   // views::MenuButtonListener:
   void OnMenuButtonClicked(views::Button* source,
                            const gfx::Point& point,
@@ -43,15 +49,25 @@
 
   bool IsContextMenuRunning();
 
+  bool IsPinned();
+
   ExtensionsMenuButton* primary_action_button_for_testing();
 
  private:
+  // views::Button:
+  void OnMouseEntered(const ui::MouseEvent& event) override;
+  void OnMouseExited(const ui::MouseEvent& event) override;
+
   ExtensionsMenuButton* const primary_action_button_;
 
   std::unique_ptr<ToolbarActionViewController> controller_;
 
   views::MenuButton* context_menu_button_ = nullptr;
 
+  ToolbarActionsModel* const model_;
+
+  views::ImageButton* pin_button_ = nullptr;
+
   // This controller is responsible for showing the context menu for an
   // extension.
   std::unique_ptr<ExtensionContextMenuController> context_menu_controller_;
diff --git a/chrome/browser/ui/views/message_center/DEPS b/chrome/browser/ui/views/message_center/DEPS
deleted file mode 100644
index b21e182..0000000
--- a/chrome/browser/ui/views/message_center/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+ui/message_center",
-]
diff --git a/chrome/browser/ui/views/message_center/OWNERS b/chrome/browser/ui/views/message_center/OWNERS
deleted file mode 100644
index 577bbabd6..0000000
--- a/chrome/browser/ui/views/message_center/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://ui/message_center/OWNERS
diff --git a/chrome/browser/ui/views/message_center/popups_only_ui_delegate.cc b/chrome/browser/ui/views/message_center/popups_only_ui_delegate.cc
deleted file mode 100644
index 2b612d8d..0000000
--- a/chrome/browser/ui/views/message_center/popups_only_ui_delegate.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/message_center/popups_only_ui_delegate.h"
-
-#include "ui/display/screen.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/views/desktop_popup_alignment_delegate.h"
-#include "ui/message_center/views/message_popup_collection.h"
-
-// static
-std::unique_ptr<PopupsOnlyUiController::Delegate>
-PopupsOnlyUiController::CreateDelegate() {
-  return std::make_unique<PopupsOnlyUiDelegate>();
-}
-
-PopupsOnlyUiDelegate::PopupsOnlyUiDelegate() {
-  alignment_delegate_ =
-      std::make_unique<message_center::DesktopPopupAlignmentDelegate>();
-  popup_collection_.reset(
-      new message_center::MessagePopupCollection(alignment_delegate_.get()));
-}
-
-PopupsOnlyUiDelegate::~PopupsOnlyUiDelegate() {
-  // Reset this early so that delegated events during destruction don't cause
-  // problems.
-  popup_collection_.reset();
-}
-
-void PopupsOnlyUiDelegate::ShowPopups() {
-  alignment_delegate_->StartObserving(display::Screen::GetScreen());
-}
-
-void PopupsOnlyUiDelegate::HidePopups() {
-  DCHECK(popup_collection_.get());
-}
diff --git a/chrome/browser/ui/views/message_center/popups_only_ui_delegate.h b/chrome/browser/ui/views/message_center/popups_only_ui_delegate.h
deleted file mode 100644
index 39bdff10..0000000
--- a/chrome/browser/ui/views/message_center/popups_only_ui_delegate.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_MESSAGE_CENTER_POPUPS_ONLY_UI_DELEGATE_H_
-#define CHROME_BROWSER_UI_VIEWS_MESSAGE_CENTER_POPUPS_ONLY_UI_DELEGATE_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "chrome/browser/notifications/popups_only_ui_controller.h"
-
-namespace message_center {
-class DesktopPopupAlignmentDelegate;
-class MessagePopupCollection;
-}  // namespace message_center
-
-// A message center view implementation that shows notification popups (toasts)
-// in the corner of the screen, but has no dedicated message center (widget with
-// multiple notifications inside). This is used on Windows and Linux for
-// non-native notifications.
-class PopupsOnlyUiDelegate : public PopupsOnlyUiController::Delegate {
- public:
-  PopupsOnlyUiDelegate();
-  ~PopupsOnlyUiDelegate() override;
-
-  // UiDelegate implementation.
-  void ShowPopups() override;
-  void HidePopups() override;
-
- private:
-  std::unique_ptr<message_center::MessagePopupCollection> popup_collection_;
-  std::unique_ptr<message_center::DesktopPopupAlignmentDelegate>
-      alignment_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(PopupsOnlyUiDelegate);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_MESSAGE_CENTER_POPUPS_ONLY_UI_DELEGATE_H_
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index 7c3fcb3d..533d035 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -27,6 +27,8 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "net/base/escape.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/favicon_size.h"
 #include "url/gurl.h"
 
 namespace web_app {
@@ -233,6 +235,19 @@
 
 void AppBrowserController::OnTabRemoved(content::WebContents* contents) {}
 
+gfx::ImageSkia AppBrowserController::GetFallbackAppIcon() const {
+  gfx::ImageSkia page_icon = browser()->GetCurrentPageIcon().AsImageSkia();
+  if (!page_icon.isNull())
+    return page_icon;
+
+  // The icon may be loading still. Return a transparent icon rather
+  // than using a placeholder to avoid flickering.
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize);
+  bitmap.eraseColor(SK_ColorTRANSPARENT);
+  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+}
+
 void AppBrowserController::SetInitialURL(const GURL& initial_url) {
   DCHECK(initial_url_.is_empty());
   initial_url_ = initial_url;
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.h b/chrome/browser/ui/web_applications/app_browser_controller.h
index 6838bf6..a300747d 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.h
+++ b/chrome/browser/ui/web_applications/app_browser_controller.h
@@ -14,13 +14,10 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/image/image_skia.h"
 
 class Browser;
 
-namespace gfx {
-class ImageSkia;
-}
-
 namespace web_app {
 
 // Returns true if |app_url| and |page_url| are the same origin. To avoid
@@ -142,6 +139,9 @@
   virtual void OnTabInserted(content::WebContents* contents);
   virtual void OnTabRemoved(content::WebContents* contents);
 
+  // Gets the icon to use if the app icon is not available.
+  gfx::ImageSkia GetFallbackAppIcon() const;
+
  private:
   // Sets the url that the app browser controller was created with.
   void SetInitialURL(const GURL& initial_url);
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
index 6c53a4b..ed154a7 100644
--- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -4,19 +4,22 @@
 
 #include "chrome/browser/ui/web_applications/web_app_browser_controller.h"
 
+#include "base/strings/string_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_manager.h"
 #include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h"
+#include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
-#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/favicon_size.h"
+#include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 
 namespace web_app {
 
 WebAppBrowserController::WebAppBrowserController(Browser* browser)
     : AppBrowserController(browser),
-      registrar_(WebAppProvider::Get(browser->profile())->registrar()),
+      provider_(*WebAppProvider::Get(browser->profile())),
       app_id_(GetAppIdFromApplicationName(browser->app_name())) {}
 
 WebAppBrowserController::~WebAppBrowserController() = default;
@@ -39,13 +42,20 @@
 }
 
 gfx::ImageSkia WebAppBrowserController::GetWindowAppIcon() const {
-  // TODO(https://crbug.com/966290): Complete implementation.
-  return gfx::ImageSkia();
+  if (app_icon_)
+    return *app_icon_;
+  app_icon_ = GetFallbackAppIcon();
+
+  provider_.icon_manager().ReadSmallestIcon(
+      app_id_, gfx::kFaviconSize,
+      base::BindOnce(&WebAppBrowserController::OnReadIcon,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  return *app_icon_;
 }
 
 gfx::ImageSkia WebAppBrowserController::GetWindowIcon() const {
-  // TODO(https://crbug.com/966290): Complete implementation.
-  return gfx::ImageSkia();
+  return GetWindowAppIcon();
 }
 
 base::Optional<SkColor> WebAppBrowserController::GetThemeColor() const {
@@ -54,15 +64,15 @@
   if (web_theme_color)
     return web_theme_color;
 
-  return registrar_.GetAppThemeColor(app_id_);
+  return registrar().GetAppThemeColor(app_id_);
 }
 
 GURL WebAppBrowserController::GetAppLaunchURL() const {
-  return registrar_.GetAppLaunchURL(app_id_);
+  return registrar().GetAppLaunchURL(app_id_);
 }
 
 bool WebAppBrowserController::IsUrlInAppScope(const GURL& url) const {
-  base::Optional<GURL> app_scope = registrar_.GetAppScope(app_id_);
+  base::Optional<GURL> app_scope = registrar().GetAppScope(app_id_);
   if (!app_scope)
     return false;
 
@@ -74,12 +84,11 @@
 
   std::string scope_path = app_scope->path();
   std::string url_path = url.path();
-  return scope_path.size() <= url_path.size() &&
-         scope_path == url_path.substr(0, scope_path.size());
+  return base::StartsWith(url_path, scope_path, base::CompareCase::SENSITIVE);
 }
 
 std::string WebAppBrowserController::GetAppShortName() const {
-  return registrar_.GetAppShortName(app_id_);
+  return registrar().GetAppShortName(app_id_);
 }
 
 base::string16 WebAppBrowserController::GetFormattedUrlOrigin() const {
@@ -100,7 +109,21 @@
 }
 
 bool WebAppBrowserController::IsInstalled() const {
-  return registrar_.IsInstalled(app_id_);
+  return registrar().IsInstalled(app_id_);
+}
+
+const AppRegistrar& WebAppBrowserController::registrar() const {
+  return provider_.registrar();
+}
+
+void WebAppBrowserController::OnReadIcon(SkBitmap bitmap) {
+  if (bitmap.empty()) {
+    DLOG(ERROR) << "Failed to read icon for web app";
+    return;
+  }
+
+  app_icon_ = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+  web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h
index ae4251d..65b5d01 100644
--- a/chrome/browser/ui/web_applications/web_app_browser_controller.h
+++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -8,25 +8,26 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/image/image_skia.h"
 
 class Browser;
-
-namespace gfx {
-class ImageSkia;
-}
+class SkBitmap;
 
 namespace web_app {
 
 class AppRegistrar;
+class WebAppProvider;
 
 // Class to encapsulate logic to control the browser UI for
 // web apps.
 // App information is obtained from the AppRegistrar.
+// Icon information is obtained from the AppIconManager.
 // Note: Much of the functionality in HostedAppBrowserController
 // will move to this class.
 class WebAppBrowserController : public AppBrowserController {
@@ -51,8 +52,15 @@
   bool IsHostedApp() const override;
 
  private:
-  AppRegistrar& registrar_;
+  const AppRegistrar& registrar() const;
+
+  void OnReadIcon(SkBitmap bitmap);
+
+  WebAppProvider& provider_;
   const AppId app_id_;
+  mutable base::Optional<gfx::ImageSkia> app_icon_;
+
+  mutable base::WeakPtrFactory<WebAppBrowserController> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebAppBrowserController);
 };
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index debf598d..60361fed 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -4,6 +4,8 @@
 
 source_set("components") {
   sources = [
+    "app_icon_manager.cc",
+    "app_icon_manager.h",
     "app_registrar.cc",
     "app_registrar.h",
     "app_registrar_observer.h",
diff --git a/chrome/browser/web_applications/components/app_icon_manager.cc b/chrome/browser/web_applications/components/app_icon_manager.cc
new file mode 100644
index 0000000..5e45b50
--- /dev/null
+++ b/chrome/browser/web_applications/components/app_icon_manager.cc
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/app_icon_manager.h"
+
+namespace web_app {
+
+AppIconManager::AppIconManager() = default;
+
+AppIconManager::~AppIconManager() = default;
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/app_icon_manager.h b/chrome/browser/web_applications/components/app_icon_manager.h
new file mode 100644
index 0000000..1a0755d1
--- /dev/null
+++ b/chrome/browser/web_applications/components/app_icon_manager.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_APP_ICON_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_APP_ICON_MANAGER_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+
+class SkBitmap;
+
+namespace web_app {
+
+// Exclusively used from the UI thread.
+class AppIconManager {
+ public:
+  AppIconManager();
+  virtual ~AppIconManager();
+
+  // Reads icon's bitmap for an app. Returns false if no IconInfo for
+  // |icon_size_in_px|. Returns empty SkBitmap in |callback| if IO error.
+  using ReadIconCallback = base::OnceCallback<void(SkBitmap)>;
+  virtual bool ReadIcon(const AppId& app_id,
+                        int icon_size_in_px,
+                        ReadIconCallback callback) = 0;
+
+  // Reads smallest icon with size at least |icon_size_in_px|.
+  // Returns false if there is no such icon.
+  // Returns empty SkBitmap in |callback| if IO error.
+  virtual bool ReadSmallestIcon(const AppId& app_id,
+                                int icon_size_in_px,
+                                ReadIconCallback callback) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AppIconManager);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_APP_ICON_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/web_app_provider_base.h b/chrome/browser/web_applications/components/web_app_provider_base.h
index 24cea11..41e26de 100644
--- a/chrome/browser/web_applications/components/web_app_provider_base.h
+++ b/chrome/browser/web_applications/components/web_app_provider_base.h
@@ -18,6 +18,7 @@
 class InstallFinalizer;
 class AppRegistrar;
 class FileHandlerManager;
+class AppIconManager;
 class WebAppPolicyManager;
 class WebAppAudioFocusIdMap;
 class WebAppUiManager;
@@ -48,6 +49,9 @@
 
   virtual FileHandlerManager& file_handler_manager() = 0;
 
+  // Implements fetching of app icons.
+  virtual AppIconManager& icon_manager() = 0;
+
   DISALLOW_COPY_AND_ASSIGN(WebAppProviderBase);
 };
 
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index 120b2aa..0f7147c 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -12,6 +12,8 @@
     "bookmark_app_file_handler_manager.h",
     "bookmark_app_finalizer_utils.cc",
     "bookmark_app_finalizer_utils.h",
+    "bookmark_app_icon_manager.cc",
+    "bookmark_app_icon_manager.h",
     "bookmark_app_install_finalizer.cc",
     "bookmark_app_install_finalizer.h",
     "bookmark_app_registrar.cc",
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc
new file mode 100644
index 0000000..857c95b
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.cc
@@ -0,0 +1,69 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h"
+
+#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/image_loader.h"
+#include "extensions/common/extension_icon_set.h"
+#include "extensions/common/manifest_handlers/icons_handler.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/image/image.h"
+
+namespace extensions {
+
+namespace {
+
+void OnExtensionIconLoaded(BookmarkAppIconManager::ReadIconCallback callback,
+                           const gfx::Image& image) {
+  std::move(callback).Run(image.IsEmpty() ? SkBitmap() : *image.ToSkBitmap());
+}
+
+bool ReadExtensionIcon(Profile* profile,
+                       const web_app::AppId& app_id,
+                       int icon_size_in_px,
+                       ExtensionIconSet::MatchType match_type,
+                       BookmarkAppIconManager::ReadIconCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  const Extension* extension =
+      ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(app_id);
+  if (!extension)
+    return false;
+  DCHECK(extension->from_bookmark());
+
+  ImageLoader* loader = ImageLoader::Get(profile);
+  loader->LoadImageAsync(
+      extension,
+      IconsInfo::GetIconResource(extension, icon_size_in_px, match_type),
+      gfx::Size(icon_size_in_px, icon_size_in_px),
+      base::BindOnce(&OnExtensionIconLoaded, std::move(callback)));
+  return true;
+}
+
+}  // anonymous namespace
+
+BookmarkAppIconManager::BookmarkAppIconManager(Profile* profile)
+    : profile_(profile) {}
+
+BookmarkAppIconManager::~BookmarkAppIconManager() = default;
+
+bool BookmarkAppIconManager::ReadIcon(const web_app::AppId& app_id,
+                                      int icon_size_in_px,
+                                      ReadIconCallback callback) {
+  return ReadExtensionIcon(profile_, app_id, icon_size_in_px,
+                           ExtensionIconSet::MATCH_EXACTLY,
+                           std::move(callback));
+}
+
+bool BookmarkAppIconManager::ReadSmallestIcon(const web_app::AppId& app_id,
+                                              int icon_size_in_px,
+                                              ReadIconCallback callback) {
+  return ReadExtensionIcon(profile_, app_id, icon_size_in_px,
+                           ExtensionIconSet::MATCH_BIGGER, std::move(callback));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h
new file mode 100644
index 0000000..6880206c
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_ICON_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_ICON_MANAGER_H_
+
+#include "chrome/browser/web_applications/components/app_icon_manager.h"
+
+class Profile;
+
+namespace extensions {
+
+// Class used to read icons of extensions-based bookmark apps.
+// TODO(crbug.com/877898): Erase this subclass once BookmarkApps are off
+// Extensions.
+class BookmarkAppIconManager : public web_app::AppIconManager {
+ public:
+  explicit BookmarkAppIconManager(Profile* profile);
+  ~BookmarkAppIconManager() override;
+
+  // AppIconManager:
+  bool ReadIcon(const web_app::AppId& app_id,
+                int icon_size_in_px,
+                ReadIconCallback callback) override;
+  bool ReadSmallestIcon(const web_app::AppId& app_id,
+                        int icon_size_in_px,
+                        ReadIconCallback callback) override;
+
+ private:
+  Profile* const profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkAppIconManager);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_ICON_MANAGER_H_
diff --git a/chrome/browser/web_applications/web_app_icon_manager.cc b/chrome/browser/web_applications/web_app_icon_manager.cc
index e164c99..0809b49c 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/file_utils_wrapper.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -171,8 +172,9 @@
 }  // namespace
 
 WebAppIconManager::WebAppIconManager(Profile* profile,
+                                     WebAppRegistrar& registrar,
                                      std::unique_ptr<FileUtilsWrapper> utils)
-    : utils_(std::move(utils)) {
+    : registrar_(registrar), utils_(std::move(utils)) {
   web_apps_directory_ = GetWebAppsDirectory(profile);
 }
 
@@ -191,19 +193,18 @@
       std::move(callback));
 }
 
-bool WebAppIconManager::ReadIcon(const WebApp& web_app,
+bool WebAppIconManager::ReadIcon(const AppId& app_id,
                                  int icon_size_in_px,
                                  ReadIconCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  for (const WebApp::IconInfo& icon_info : web_app.icons()) {
-    if (icon_info.size_in_px == icon_size_in_px) {
-      base::PostTaskAndReplyWithResult(
-          FROM_HERE, kTaskTraits,
-          base::BindOnce(ReadIconBlocking, utils_->Clone(), web_apps_directory_,
-                         web_app.app_id(), icon_size_in_px),
-          std::move(callback));
+  const WebApp* web_app = registrar_.GetAppById(app_id);
+  if (!web_app)
+    return false;
 
+  for (const WebApp::IconInfo& icon_info : web_app->icons()) {
+    if (icon_info.size_in_px == icon_size_in_px) {
+      ReadIconInternal(app_id, icon_size_in_px, std::move(callback));
       return true;
     }
   }
@@ -211,4 +212,38 @@
   return false;
 }
 
+bool WebAppIconManager::ReadSmallestIcon(const AppId& app_id,
+                                         int icon_size_in_px,
+                                         ReadIconCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  const WebApp* web_app = registrar_.GetAppById(app_id);
+  if (!web_app)
+    return false;
+
+  int best_size_in_px = std::numeric_limits<int>::max();
+  for (const WebApp::IconInfo& icon_info : web_app->icons()) {
+    if (icon_info.size_in_px >= icon_size_in_px &&
+        icon_info.size_in_px < best_size_in_px) {
+      best_size_in_px = icon_info.size_in_px;
+    }
+  }
+
+  if (best_size_in_px == std::numeric_limits<int>::max())
+    return false;
+
+  ReadIconInternal(app_id, best_size_in_px, std::move(callback));
+  return true;
+}
+
+void WebAppIconManager::ReadIconInternal(const AppId& app_id,
+                                         int icon_size_in_px,
+                                         ReadIconCallback callback) {
+  base::PostTaskAndReplyWithResult(
+      FROM_HERE, kTaskTraits,
+      base::BindOnce(ReadIconBlocking, utils_->Clone(), web_apps_directory_,
+                     app_id, icon_size_in_px),
+      std::move(callback));
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_icon_manager.h b/chrome/browser/web_applications/web_app_icon_manager.h
index 98bb3e7f..3e7be1b 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.h
+++ b/chrome/browser/web_applications/web_app_icon_manager.h
@@ -7,26 +7,25 @@
 
 #include <memory>
 
-#include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/common/web_application_info.h"
 
 class Profile;
-class SkBitmap;
-struct WebApplicationInfo;
 
 namespace web_app {
 
 class FileUtilsWrapper;
-class WebApp;
+class WebAppRegistrar;
 
 // Exclusively used from the UI thread.
-class WebAppIconManager {
+class WebAppIconManager : public AppIconManager {
  public:
-  WebAppIconManager(Profile* profile, std::unique_ptr<FileUtilsWrapper> utils);
-  ~WebAppIconManager();
+  WebAppIconManager(Profile* profile,
+                    WebAppRegistrar& registrar,
+                    std::unique_ptr<FileUtilsWrapper> utils);
+  ~WebAppIconManager() override;
 
   // Writes all data (icons) for an app.
   using WriteDataCallback = base::OnceCallback<void(bool success)>;
@@ -34,14 +33,20 @@
                  std::unique_ptr<WebApplicationInfo> web_app_info,
                  WriteDataCallback callback);
 
-  // Reads icon's bitmap for an app. Returns false if no IconInfo for
-  // |icon_size_in_px|. Returns empty SkBitmap in |callback| if IO error.
-  using ReadIconCallback = base::OnceCallback<void(SkBitmap)>;
-  bool ReadIcon(const WebApp& web_app,
+  // AppIconManager:
+  bool ReadIcon(const AppId& app_id,
                 int icon_size_in_px,
-                ReadIconCallback callback);
+                ReadIconCallback callback) override;
+  bool ReadSmallestIcon(const AppId& app_id,
+                        int icon_size_in_px,
+                        ReadIconCallback callback) override;
 
  private:
+  void ReadIconInternal(const AppId& app_id,
+                        int icon_size_in_px,
+                        ReadIconCallback callback);
+
+  const WebAppRegistrar& registrar_;
   base::FilePath web_apps_directory_;
   std::unique_ptr<FileUtilsWrapper> utils_;
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
index 24cff04..9e7689df 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
@@ -9,9 +9,11 @@
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/web_applications/components/web_app_icon_generator.h"
 #include "chrome/browser/web_applications/test/test_file_utils.h"
+#include "chrome/browser/web_applications/test/test_web_app_database.h"
 #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -25,11 +27,50 @@
     auto file_utils = std::make_unique<TestFileUtils>();
     file_utils_ = file_utils.get();
 
-    icon_manager_ =
-        std::make_unique<WebAppIconManager>(profile(), std::move(file_utils));
+    database_ = std::make_unique<TestWebAppDatabase>();
+    registrar_ = std::make_unique<WebAppRegistrar>(nullptr, database_.get());
+    icon_manager_ = std::make_unique<WebAppIconManager>(profile(), *registrar_,
+                                                        std::move(file_utils));
   }
 
  protected:
+  void WriteIcons(const AppId& app_id,
+                  const GURL& app_url,
+                  const std::vector<int>& sizes_px,
+                  const std::vector<SkColor>& colors) {
+    DCHECK_EQ(sizes_px.size(), colors.size());
+    auto web_app_info = std::make_unique<WebApplicationInfo>();
+    web_app_info->icons.reserve(sizes_px.size());
+    for (size_t i = 0; i < sizes_px.size(); ++i) {
+      std::string icon_name = base::StringPrintf("app-%d.ico", sizes_px[i]);
+      GURL icon_url = app_url.Resolve(icon_name);
+      web_app_info->icons.push_back(
+          GenerateIconInfo(icon_url, sizes_px[i], colors[i]));
+    }
+
+    base::RunLoop run_loop;
+    icon_manager_->WriteData(app_id, std::move(web_app_info),
+                             base::BindLambdaForTesting([&](bool success) {
+                               EXPECT_TRUE(success);
+                               run_loop.Quit();
+                             }));
+    run_loop.Run();
+  }
+
+  WebApp::Icons ListIcons(const GURL& app_url,
+                          const std::vector<int>& sizes_px) {
+    WebApp::Icons icons;
+    icons.reserve(sizes_px.size());
+    for (size_t i = 0; i < sizes_px.size(); ++i) {
+      std::string icon_name = base::StringPrintf("app-%d.ico", sizes_px[i]);
+      GURL icon_url = app_url.Resolve(icon_name);
+      icons.push_back({icon_url, sizes_px[i]});
+    }
+    return icons;
+  }
+
+  std::unique_ptr<TestWebAppDatabase> database_;
+  std::unique_ptr<WebAppRegistrar> registrar_;
   std::unique_ptr<WebAppIconManager> icon_manager_;
 
   // Owned by icon_manager_:
@@ -37,58 +78,37 @@
 };
 
 TEST_F(WebAppIconManagerTest, WriteAndReadIcon) {
+  const std::string name = "Name";
   const GURL app_url = GURL("https://example.com/path");
   const AppId app_id = GenerateAppIdFromURL(app_url);
 
-  const GURL icon_url = GURL("https://example.com/app.ico");
-  const SkColor color = SK_ColorYELLOW;
-  const int icon_size_px = icon_size::k512;
-
-  // Write icon's bitmap to disk.
-  {
-    WebApplicationInfo::IconInfo icon_info =
-        GenerateIconInfo(icon_url, icon_size_px, color);
-
-    auto web_app_info = std::make_unique<WebApplicationInfo>();
-    web_app_info->icons.push_back(std::move(icon_info));
-
-    base::RunLoop run_loop;
-    bool callback_called = false;
-
-    icon_manager_->WriteData(app_id, std::move(web_app_info),
-                             base::BindLambdaForTesting([&](bool success) {
-                               callback_called = true;
-                               EXPECT_TRUE(success);
-                               run_loop.Quit();
-                             }));
-
-    run_loop.Run();
-    EXPECT_TRUE(callback_called);
-  }
+  const std::vector<int> sizes_px{icon_size::k512};
+  const std::vector<SkColor> colors{SK_ColorYELLOW};
+  WriteIcons(app_id, app_url, sizes_px, colors);
 
   auto web_app = std::make_unique<WebApp>(app_id);
+  web_app->SetName(name);
+  web_app->SetLaunchUrl(app_url);
+  web_app->SetIcons(ListIcons(app_url, sizes_px));
+  registrar_->RegisterApp(std::move(web_app));
 
-  WebApp::Icons icons;
-  icons.push_back({icon_url, icon_size_px});
-  web_app->SetIcons(std::move(icons));
+  {
+    base::RunLoop run_loop;
 
-  base::RunLoop run_loop;
-  bool callback_called = false;
+    const bool icon_requested = icon_manager_->ReadIcon(
+        app_id, sizes_px[0], base::BindLambdaForTesting([&](SkBitmap bitmap) {
+          EXPECT_FALSE(bitmap.empty());
+          EXPECT_EQ(colors[0], bitmap.getColor(0, 0));
+          run_loop.Quit();
+        }));
+    EXPECT_TRUE(icon_requested);
 
-  const bool icon_requested = icon_manager_->ReadIcon(
-      *web_app, icon_size_px, base::BindLambdaForTesting([&](SkBitmap bitmap) {
-        callback_called = true;
-        EXPECT_FALSE(bitmap.empty());
-        EXPECT_EQ(color, bitmap.getColor(0, 0));
-        run_loop.Quit();
-      }));
-  EXPECT_TRUE(icon_requested);
-
-  run_loop.Run();
-  EXPECT_TRUE(callback_called);
+    run_loop.Run();
+  }
 }
 
 TEST_F(WebAppIconManagerTest, ReadIconFailed) {
+  const std::string name = "Name";
   const GURL app_url = GURL("https://example.com/path");
   const AppId app_id = GenerateAppIdFromURL(app_url);
 
@@ -96,30 +116,120 @@
   const int icon_size_px = icon_size::k256;
 
   auto web_app = std::make_unique<WebApp>(app_id);
+  web_app->SetName(name);
+  web_app->SetLaunchUrl(app_url);
 
   // Set icon meta-info but don't write bitmap to disk.
   WebApp::Icons icons;
   icons.push_back({icon_url, icon_size_px});
   web_app->SetIcons(std::move(icons));
+  registrar_->RegisterApp(std::move(web_app));
 
   // Request non-existing icon size.
   EXPECT_FALSE(
-      icon_manager_->ReadIcon(*web_app, icon_size::k96, base::DoNothing()));
+      icon_manager_->ReadIcon(app_id, icon_size::k96, base::DoNothing()));
 
   // Request existing icon size which doesn't exist on disk.
   base::RunLoop run_loop;
-  bool callback_called = false;
 
   const bool icon_requested = icon_manager_->ReadIcon(
-      *web_app, icon_size_px, base::BindLambdaForTesting([&](SkBitmap bitmap) {
-        callback_called = true;
+      app_id, icon_size_px, base::BindLambdaForTesting([&](SkBitmap bitmap) {
         EXPECT_TRUE(bitmap.empty());
         run_loop.Quit();
       }));
   EXPECT_TRUE(icon_requested);
 
   run_loop.Run();
-  EXPECT_TRUE(callback_called);
+}
+
+TEST_F(WebAppIconManagerTest, FindExact) {
+  const std::string name = "Name";
+  const GURL app_url = GURL("https://example.com/path");
+  const AppId app_id = GenerateAppIdFromURL(app_url);
+
+  const std::vector<int> sizes_px{10, 60, 50, 20, 30};
+  const std::vector<SkColor> colors{SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN,
+                                    SK_ColorBLUE, SK_ColorMAGENTA};
+  WriteIcons(app_id, app_url, sizes_px, colors);
+
+  auto web_app = std::make_unique<WebApp>(app_id);
+  web_app->SetName(name);
+  web_app->SetLaunchUrl(app_url);
+  web_app->SetIcons(ListIcons(app_url, sizes_px));
+  registrar_->RegisterApp(std::move(web_app));
+
+  {
+    const bool icon_requested = icon_manager_->ReadIcon(
+        app_id, 40,
+        base::BindLambdaForTesting([&](SkBitmap bitmap) { NOTREACHED(); }));
+    EXPECT_FALSE(icon_requested);
+  }
+
+  {
+    base::RunLoop run_loop;
+
+    const bool icon_requested = icon_manager_->ReadIcon(
+        app_id, 20, base::BindLambdaForTesting([&](SkBitmap bitmap) {
+          EXPECT_FALSE(bitmap.empty());
+          EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(0, 0));
+          run_loop.Quit();
+        }));
+    EXPECT_TRUE(icon_requested);
+
+    run_loop.Run();
+  }
+}
+
+TEST_F(WebAppIconManagerTest, FindSmallest) {
+  const std::string name = "Name";
+  const GURL app_url = GURL("https://example.com/path");
+  const AppId app_id = GenerateAppIdFromURL(app_url);
+
+  const std::vector<int> sizes_px{10, 60, 50, 20, 30};
+  const std::vector<SkColor> colors{SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN,
+                                    SK_ColorBLUE, SK_ColorMAGENTA};
+  WriteIcons(app_id, app_url, sizes_px, colors);
+
+  auto web_app = std::make_unique<WebApp>(app_id);
+  web_app->SetName(name);
+  web_app->SetLaunchUrl(app_url);
+  web_app->SetIcons(ListIcons(app_url, sizes_px));
+  registrar_->RegisterApp(std::move(web_app));
+
+  {
+    const bool icon_requested = icon_manager_->ReadSmallestIcon(
+        app_id, 70,
+        base::BindLambdaForTesting([&](SkBitmap bitmap) { NOTREACHED(); }));
+    EXPECT_FALSE(icon_requested);
+  }
+
+  {
+    base::RunLoop run_loop;
+
+    const bool icon_requested = icon_manager_->ReadSmallestIcon(
+        app_id, 40, base::BindLambdaForTesting([&](SkBitmap bitmap) {
+          EXPECT_FALSE(bitmap.empty());
+          EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(0, 0));
+          run_loop.Quit();
+        }));
+    EXPECT_TRUE(icon_requested);
+
+    run_loop.Run();
+  }
+
+  {
+    base::RunLoop run_loop;
+
+    const bool icon_requested = icon_manager_->ReadSmallestIcon(
+        app_id, 20, base::BindLambdaForTesting([&](SkBitmap bitmap) {
+          EXPECT_FALSE(bitmap.empty());
+          EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(0, 0));
+          run_loop.Quit();
+        }));
+    EXPECT_TRUE(icon_requested);
+
+    run_loop.Run();
+  }
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.h b/chrome/browser/web_applications/web_app_install_finalizer.h
index 0701f60..a631919d 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.h
+++ b/chrome/browser/web_applications/web_app_install_finalizer.h
@@ -49,8 +49,8 @@
                      std::unique_ptr<WebApp> web_app,
                      bool success);
 
+  WebAppIconManager* const icon_manager_;
   WebAppRegistrar* registrar_ = nullptr;
-  WebAppIconManager* icon_manager_;
 
   base::WeakPtrFactory<WebAppInstallFinalizer> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 6737d1b..0b28abd 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -122,8 +122,8 @@
     auto file_utils = std::make_unique<TestFileUtils>();
     file_utils_ = file_utils.get();
 
-    icon_manager_ =
-        std::make_unique<WebAppIconManager>(profile(), std::move(file_utils));
+    icon_manager_ = std::make_unique<WebAppIconManager>(profile(), *registrar_,
+                                                        std::move(file_utils));
 
     ui_manager_ = std::make_unique<TestWebAppUiManager>();
 
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 434cbca..d7984ea 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/external_web_app_manager.h"
@@ -116,6 +117,11 @@
   return *file_handler_manager_;
 }
 
+AppIconManager& WebAppProvider::icon_manager() {
+  CheckIsConnected();
+  return *icon_manager_;
+}
+
 SystemWebAppManager& WebAppProvider::system_web_app_manager() {
   CheckIsConnected();
   return *system_web_app_manager_;
@@ -145,15 +151,18 @@
   database_ = std::make_unique<WebAppDatabase>(database_factory_.get());
   registrar_ = std::make_unique<WebAppRegistrar>(profile, database_.get());
   sync_manager_ = std::make_unique<WebAppSyncManager>();
-  icon_manager_ = std::make_unique<WebAppIconManager>(
-      profile, std::make_unique<FileUtilsWrapper>());
+  auto icon_manager = std::make_unique<WebAppIconManager>(
+      profile, *registrar_->AsWebAppRegistrar(),
+      std::make_unique<FileUtilsWrapper>());
   install_finalizer_ =
-      std::make_unique<WebAppInstallFinalizer>(icon_manager_.get());
+      std::make_unique<WebAppInstallFinalizer>(icon_manager.get());
+  icon_manager_ = std::move(icon_manager);
   file_handler_manager_ = std::make_unique<WebAppFileHandlerManager>(profile);
 }
 
 void WebAppProvider::CreateBookmarkAppsSubsystems(Profile* profile) {
   registrar_ = std::make_unique<extensions::BookmarkAppRegistrar>(profile);
+  icon_manager_ = std::make_unique<extensions::BookmarkAppIconManager>(profile);
   install_finalizer_ =
       std::make_unique<extensions::BookmarkAppInstallFinalizer>(profile);
   file_handler_manager_ =
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index 6d40631..d6bf5a5 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -29,6 +29,7 @@
 namespace web_app {
 
 // Forward declarations of generalized interfaces.
+class AppIconManager;
 class ExternalWebAppManager;
 class FileHandlerManager;
 class InstallFinalizer;
@@ -41,7 +42,6 @@
 // Forward declarations for new extension-independent subsystems.
 class WebAppDatabaseFactory;
 class WebAppDatabase;
-class WebAppIconManager;
 class WebAppSyncManager;
 
 // Connects Web App features, such as the installation of default and
@@ -74,6 +74,7 @@
   WebAppUiManager& ui_manager() override;
   WebAppAudioFocusIdMap& audio_focus_id_map() override;
   FileHandlerManager& file_handler_manager() override;
+  AppIconManager& icon_manager() override;
 
   WebAppDatabaseFactory& database_factory() { return *database_factory_; }
   WebAppSyncManager& sync_manager() { return *sync_manager_; }
@@ -111,13 +112,13 @@
   // New extension-independent subsystems:
   std::unique_ptr<WebAppDatabaseFactory> database_factory_;
   std::unique_ptr<WebAppDatabase> database_;
-  std::unique_ptr<WebAppIconManager> icon_manager_;
   std::unique_ptr<WebAppSyncManager> sync_manager_;
 
   // Generalized subsystems:
   std::unique_ptr<AppRegistrar> registrar_;
   std::unique_ptr<ExternalWebAppManager> external_web_app_manager_;
   std::unique_ptr<FileHandlerManager> file_handler_manager_;
+  std::unique_ptr<AppIconManager> icon_manager_;
   std::unique_ptr<InstallFinalizer> install_finalizer_;
   std::unique_ptr<PendingAppManager> pending_app_manager_;
   std::unique_ptr<SystemWebAppManager> system_web_app_manager_;
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index 4fa2a3e..1e4937f 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/strings/string_util.h"
 #include "chrome/browser/web_applications/abstract_web_app_database.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -105,8 +106,32 @@
 
 base::Optional<AppId> WebAppRegistrar::FindAppWithUrlInScope(
     const GURL& url) const {
-  NOTIMPLEMENTED();
-  return base::nullopt;
+  const std::string url_path = url.spec();
+
+  base::Optional<AppId> best_app;
+  size_t best_path_length = 0U;
+  bool best_is_shortcut = true;
+
+  for (const WebApp& app : AllApps()) {
+    // TODO(crbug.com/915038): Implement and use WebApp::IsShortcut().
+    // TODO(crbug.com/910016): Treat shortcuts as PWAs.
+    bool app_is_shortcut = app.scope().is_empty();
+    if (app_is_shortcut && !best_is_shortcut)
+      continue;
+
+    const std::string app_path = app.scope().is_empty()
+                                     ? app.launch_url().Resolve(".").spec()
+                                     : app.scope().spec();
+    if ((app_path.size() > best_path_length ||
+         (best_is_shortcut && !app_is_shortcut)) &&
+        base::StartsWith(url_path, app_path, base::CompareCase::SENSITIVE)) {
+      best_app = app.app_id();
+      best_path_length = app_path.size();
+      best_is_shortcut = app_is_shortcut;
+    }
+  }
+
+  return best_app;
 }
 
 int WebAppRegistrar::CountUserInstalledApps() const {
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
index b7b7fc4..aa841de2 100644
--- a/chrome/browser/web_applications/web_app_registrar.h
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -6,12 +6,14 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_
 
 #include <memory>
+#include <string>
 
 #include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "chrome/browser/web_applications/abstract_web_app_database.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
diff --git a/chrome/browser/web_applications/web_app_registrar_unittest.cc b/chrome/browser/web_applications/web_app_registrar_unittest.cc
index 8fe83a4b..dc1382c 100644
--- a/chrome/browser/web_applications/web_app_registrar_unittest.cc
+++ b/chrome/browser/web_applications/web_app_registrar_unittest.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/bind_helpers.h"
+#include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
@@ -325,6 +326,121 @@
   EXPECT_THAT(in_scope, testing::UnorderedElementsAre("3"));
 }
 
+TEST_F(WebAppRegistrarTest, CanFindAppWithUrlInScope) {
+  const GURL origin_scope("https://example.com/");
+  const GURL app1_scope("https://example.com/app");
+  const GURL app2_scope("https://example.com/app-two");
+  const GURL app3_scope("https://not-example.com/app");
+
+  auto app1 = std::make_unique<WebApp>("1");
+  app1->SetScope(app1_scope);
+  registrar().RegisterApp(std::move(app1));
+
+  base::Optional<AppId> app2_match =
+      registrar().FindAppWithUrlInScope(app2_scope);
+  DCHECK(app2_match);
+  EXPECT_EQ(*app2_match, "1");
+
+  base::Optional<AppId> app3_match =
+      registrar().FindAppWithUrlInScope(app3_scope);
+  EXPECT_FALSE(app3_match);
+
+  auto app2 = std::make_unique<WebApp>("2");
+  app2->SetScope(app2_scope);
+  registrar().RegisterApp(std::move(app2));
+
+  auto app3 = std::make_unique<WebApp>("3");
+  app3->SetScope(app3_scope);
+  registrar().RegisterApp(std::move(app3));
+
+  base::Optional<AppId> origin_match =
+      registrar().FindAppWithUrlInScope(origin_scope);
+  EXPECT_FALSE(origin_match);
+
+  base::Optional<AppId> app1_match =
+      registrar().FindAppWithUrlInScope(app1_scope);
+  DCHECK(app1_match);
+  EXPECT_EQ(*app1_match, "1");
+
+  app2_match = registrar().FindAppWithUrlInScope(app2_scope);
+  DCHECK(app2_match);
+  EXPECT_EQ(*app2_match, "2");
+
+  app3_match = registrar().FindAppWithUrlInScope(app3_scope);
+  DCHECK(app3_match);
+  EXPECT_EQ(*app3_match, "3");
+}
+
+TEST_F(WebAppRegistrarTest, CanFindShortcutWithUrlInScope) {
+  const GURL app1_page("https://example.com/app/page");
+  const GURL app2_page("https://example.com/app-two/page");
+  const GURL app3_page("https://not-example.com/app/page");
+
+  const GURL app1_launch("https://example.com/app/launch");
+  const GURL app2_launch("https://example.com/app-two/launch");
+  const GURL app3_launch("https://not-example.com/app/launch");
+
+  // Implicit scope "https://example.com/app/"
+  auto app1 = std::make_unique<WebApp>("1");
+  app1->SetLaunchUrl(app1_launch);
+  registrar().RegisterApp(std::move(app1));
+
+  base::Optional<AppId> app2_match =
+      registrar().FindAppWithUrlInScope(app2_page);
+  EXPECT_FALSE(app2_match);
+
+  base::Optional<AppId> app3_match =
+      registrar().FindAppWithUrlInScope(app3_page);
+  EXPECT_FALSE(app3_match);
+
+  auto app2 = std::make_unique<WebApp>("2");
+  app2->SetLaunchUrl(app2_launch);
+  registrar().RegisterApp(std::move(app2));
+
+  auto app3 = std::make_unique<WebApp>("3");
+  app3->SetLaunchUrl(app3_launch);
+  registrar().RegisterApp(std::move(app3));
+
+  base::Optional<AppId> app1_match =
+      registrar().FindAppWithUrlInScope(app1_page);
+  DCHECK(app1_match);
+  EXPECT_EQ(app1_match, base::Optional<AppId>("1"));
+
+  app2_match = registrar().FindAppWithUrlInScope(app2_page);
+  DCHECK(app2_match);
+  EXPECT_EQ(app2_match, base::Optional<AppId>("2"));
+
+  app3_match = registrar().FindAppWithUrlInScope(app3_page);
+  DCHECK(app3_match);
+  EXPECT_EQ(app3_match, base::Optional<AppId>("3"));
+}
+
+TEST_F(WebAppRegistrarTest, FindPwaOverShortcut) {
+  const GURL app1_launch("https://example.com/app/specific/launch1");
+
+  const GURL app2_scope("https://example.com/app");
+  const GURL app2_page("https://example.com/app/specific/page2");
+
+  const GURL app3_launch("https://example.com/app/specific/launch3");
+
+  auto app1 = std::make_unique<WebApp>("1");
+  app1->SetLaunchUrl(app1_launch);
+  registrar().RegisterApp(std::move(app1));
+
+  auto app2 = std::make_unique<WebApp>("2");
+  app2->SetScope(app2_scope);
+  registrar().RegisterApp(std::move(app2));
+
+  auto app3 = std::make_unique<WebApp>("3");
+  app3->SetLaunchUrl(app3_launch);
+  registrar().RegisterApp(std::move(app3));
+
+  base::Optional<AppId> app2_match =
+      registrar().FindAppWithUrlInScope(app2_page);
+  DCHECK(app2_match);
+  EXPECT_EQ(app2_match, base::Optional<AppId>("2"));
+}
+
 TEST_F(WebAppRegistrarTest, DatabaseWriteAndDeleteAppsFail) {
   auto app = CreateWebApp(GURL("https://example.com/path"));
   auto app_id = app->app_id();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cc44983..856e4f8f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2614,9 +2614,9 @@
       ":browser_tests",
     ]
     data = [
-      "//out/apprtc/out/app_engine/",
-      "//out/apprtc/temp/google-cloud-sdk/",
-      "//out/collider/",
+      "//third_party/webrtc/rtc_tools/testing/webrtc_apprtc_browsertest/apprtc/out/app_engine/",
+      "//third_party/webrtc/rtc_tools/testing/webrtc_apprtc_browsertest/apprtc/temp/google-cloud-sdk/",
+      "//third_party/webrtc/rtc_tools/testing/webrtc_apprtc_browsertest/collider/",
     ]
     if (is_win) {
       write_runtime_deps = "$root_out_dir/$target_name.exe.runtime_deps"
@@ -3962,6 +3962,7 @@
       "../browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc",
       "../browser/sharing/click_to_call/click_to_call_utils_unittest.cc",
       "../browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc",
+      "../browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop_unittest.cc",
       "../browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc",
       "../browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc",
       "../browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc",
@@ -4992,7 +4993,8 @@
       ]
     }
     if ((is_linux && !is_chromeos) || is_win) {
-      sources += [ "../browser/ui/views/message_center/popups_only_ui_delegate_unittest.cc" ]
+      sources +=
+          [ "../browser/notifications/popups_only_ui_controller_unittest.cc" ]
     }
     if (use_aura) {
       sources += [
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index ae52e5e..e524e83 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -105,6 +105,9 @@
 _OS_SPECIFIC_FILTER['linux'] = [
     'ChromeDriverTestLegacy.testMouseMoveTo',
     'MobileEmulationCapabilityTest.testDoesntWaitWhenPageLoadStrategyIsNone',
+    # https://bugs.chromium.org/p/chromium/issues/detail?id=1000530
+    'ChromeDriverTest.testActionsMouseMove',
+    'ChromeDriverTest.testActionsMouseDrag',
 ]
 _OS_SPECIFIC_FILTER['mac'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1927
@@ -116,6 +119,9 @@
     'ChromeDownloadDirTest.testFileDownloadWithGetHeadless',
     'ChromeDriverTestLegacy.testMouseMoveTo',
     'MobileEmulationCapabilityTest.testDoesntWaitWhenPageLoadStrategyIsNone',
+    # https://bugs.chromium.org/p/chromium/issues/detail?id=1000530
+    'ChromeDriverTest.testActionsMouseMove',
+    'ChromeDriverTest.testActionsMouseDrag',
 ]
 
 _DESKTOP_NEGATIVE_FILTER = [
diff --git a/chrome/test/data/webui/history/history_browsertest.js b/chrome/test/data/webui/history/history_browsertest.js
index baf4c6f..cae32ab 100644
--- a/chrome/test/data/webui/history/history_browsertest.js
+++ b/chrome/test/data/webui/history/history_browsertest.js
@@ -117,7 +117,8 @@
   ]),
 };
 
-TEST_F('HistoryMetricsTest', 'All', function() {
+// TODO(https://crbug.com/1000573): Re-enable once flakiness is fixed.
+TEST_F('HistoryMetricsTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index 5d4fb38..5f3cbab 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -351,9 +351,6 @@
 // Force system compositor mode when set.
 const char kForceSystemCompositorMode[] = "force-system-compositor-mode";
 
-// Forces to use chrome camera app when camera icon is clicked.
-const char kForceUseChromeCamera[] = "force-use-chrome-camera";
-
 // Indicates that the browser is in "browse without sign-in" (Guest session)
 // mode. Should completely disable extensions, sync and bookmarks.
 const char kGuestSession[] = "bwsi";
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index a1e5f5b8..6b8603ca5 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -148,8 +148,6 @@
 extern const char kForceLoginManagerInTests[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const char kForceSystemCompositorMode[];
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const char kForceUseChromeCamera[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kGuestSession[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kGuestWallpaperLarge[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kGuestWallpaperSmall[];
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index 7f85d33de..e550289 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -54,6 +54,12 @@
 const base::Feature kNativeBridgeToggleFeature{
     "ArcNativeBridgeExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls ARC picture-in-picture feature. If this is enabled, then Android
+// will control which apps can enter PIP. If this is disabled, then ARC PIP
+// will be disabled.
+const base::Feature kPictureInPictureFeature{"ArcPictureInPicture",
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Controls experimental print spooler feature for ARC.
 const base::Feature kPrintSpoolerExperimentFeature{
     "ArcPrintSpoolerExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index c696665..6cbf9eb7 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -22,6 +22,7 @@
 extern const base::Feature kEnableUnifiedAudioFocusFeature;
 extern const base::Feature kFilePickerExperimentFeature;
 extern const base::Feature kNativeBridgeToggleFeature;
+extern const base::Feature kPictureInPictureFeature;
 extern const base::Feature kPrintSpoolerExperimentFeature;
 extern const base::Feature kSmartTextSelectionFeature;
 extern const base::Feature kUsbHostFeature;
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index 4b9971b8..245e442 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -120,16 +120,6 @@
       chromeos::switches::kEnableArcVm);
 }
 
-void EnableArcVmForTesting() {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      chromeos::switches::kEnableArcVm);
-}
-
-void DisableArcVmForTesting() {
-  base::CommandLine::ForCurrentProcess()->RemoveSwitch(
-      chromeos::switches::kEnableArcVm);
-}
-
 bool ShouldArcAlwaysStart() {
   const auto* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(chromeos::switches::kArcStartMode))
diff --git a/components/arc/arc_util.h b/components/arc/arc_util.h
index f6b7b92..7660757 100644
--- a/components/arc/arc_util.h
+++ b/components/arc/arc_util.h
@@ -43,11 +43,6 @@
 // Returns true if ARC VM is enabled.
 bool IsArcVmEnabled();
 
-// These two methods used for testing only add and remove the arcvm flag so that
-// IsArcVmEnabled() returns the corresponding result.
-void EnableArcVmForTesting();
-void DisableArcVmForTesting();
-
 // Returns true if ARC should always start within the primary user session
 // (opted in user or not), and other supported mode such as guest and Kiosk
 // mode.
diff --git a/components/autofill_assistant/browser/devtools/devtools_api/domain_cc.template b/components/autofill_assistant/browser/devtools/devtools_api/domain_cc.template
index 6fcaa7c8..ffa1cde 100644
--- a/components/autofill_assistant/browser/devtools/devtools_api/domain_cc.template
+++ b/components/autofill_assistant/browser/devtools/devtools_api/domain_cc.template
@@ -46,7 +46,9 @@
   {% for command in domain.commands %}
     {% set class_name = 'ExperimentalDomain' if command.experimental else 'Domain' %}
     {% set method_name = command.name | sanitize_literal | to_title_case %}
-void {{class_name}}::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback) {
+void {{class_name}}::{{method_name}}(
+    std::unique_ptr<{{method_name}}Params> params,
+    base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback) {
   dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), base::BindOnce(&Domain::Handle{{method_name}}Response, std::move(callback)));
 }
     {# Generate convenience methods that take the required parameters directly. #}
@@ -64,7 +66,7 @@
     {% endfor %}
     {% if command.get("parameters", []) and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#}
     {% if command.get("returns", []) -%}
-      base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback{##}
+      base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback{##}
     {% else -%}
       base::OnceClosure callback{##}
     {% endif %}) {
@@ -99,18 +101,22 @@
   {% set method_name = command.name | sanitize_literal | to_title_case %}
 
 // static
-void Domain::Handle{{method_name}}Response(base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response) {
+void Domain::Handle{{method_name}}Response(
+    base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback,
+    const MessageDispatcher::ReplyStatus& reply_status,
+    const base::Value& response) {
   if (callback.is_null())
     return;
+
   // This is an error response.
   if (response.is_none()) {
-    std::move(callback).Run(nullptr);
+    std::move(callback).Run(reply_status, nullptr);
     return;
   }
   ErrorReporter errors;
   std::unique_ptr<{{method_name}}Result> result = {{method_name}}Result::Parse(response, &errors);
   DCHECK(!errors.HasErrors()) << errors.ToString();
-  std::move(callback).Run(std::move(result));
+  std::move(callback).Run(reply_status, std::move(result));
 }
 {% endfor %}
 {% if "events" in domain %}
diff --git a/components/autofill_assistant/browser/devtools/devtools_api/domain_h.template b/components/autofill_assistant/browser/devtools/devtools_api/domain_h.template
index ab5397e..785d4cd 100644
--- a/components/autofill_assistant/browser/devtools/devtools_api/domain_h.template
+++ b/components/autofill_assistant/browser/devtools/devtools_api/domain_h.template
@@ -23,7 +23,7 @@
   {% if command.description %}
   // {{ command.description.replace('\n', '\n  // ') }}
   {% endif %}
-  void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)>());
+  void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)>());
   {# Generate convenience methods that take the required parameters directly. #}
   {# Don't generate these for experimental commands. #}
   {% if "parameters" in command and not command.experimental %}
@@ -37,7 +37,7 @@
     {% endfor %}
     {% if command.get("parameters", []) and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#}
     {% if command.get("returns", []) -%}
-      base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)>(){##}
+      base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)>(){##}
     {% else -%}
       base::OnceClosure callback = base::OnceClosure(){##}
     {% endif %});
@@ -108,7 +108,10 @@
   {% for command in domain.commands %}
     {% if not "returns" in command %}{% continue %}{% endif %}
     {% set method_name = command.name | sanitize_literal | to_title_case %}
-  static void Handle{{method_name}}Response(base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response);
+  static void Handle{{method_name}}Response(
+      base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback,
+      const MessageDispatcher::ReplyStatus& reply_status,
+      const base::Value& response);
   {% endfor %}
 
   {# Generate event dispatchers. #}
diff --git a/components/autofill_assistant/browser/devtools/devtools_client.cc b/components/autofill_assistant/browser/devtools/devtools_client.cc
index 0d58d00..39911cd 100644
--- a/components/autofill_assistant/browser/devtools/devtools_client.cc
+++ b/components/autofill_assistant/browser/devtools/devtools_client.cc
@@ -56,7 +56,7 @@
 void DevtoolsClient::SendMessage(
     const char* method,
     std::unique_ptr<base::Value> params,
-    base::OnceCallback<void(const base::Value&)> callback) {
+    base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback) {
   SendMessageWithParams(method, std::move(params), std::move(callback));
 }
 
@@ -132,6 +132,7 @@
   pending_messages_.erase(it);
   if (!callback.callback_with_result.is_null()) {
     const base::DictionaryValue* result_dict;
+    ReplyStatus status;
     if (message_dict.GetDictionary("result", &result_dict)) {
       if (browser_main_thread_) {
         browser_main_thread_->PostTask(
@@ -139,22 +140,24 @@
             base::BindOnce(
                 &DevtoolsClient::DispatchMessageReplyWithResultTask,
                 weak_ptr_factory_.GetWeakPtr(), std::move(owning_message),
-                std::move(callback.callback_with_result), result_dict));
+                std::move(callback.callback_with_result), status, result_dict));
       } else {
-        std::move(callback.callback_with_result).Run(*result_dict);
+        std::move(callback.callback_with_result).Run(status, *result_dict);
       }
     } else if (message_dict.GetDictionary("error", &result_dict)) {
       auto null_value = std::make_unique<base::Value>();
       DLOG(ERROR) << "Error in method call result: " << *result_dict;
+      FillReplyStatusFromErrorDict(&status, *result_dict);
       if (browser_main_thread_) {
         browser_main_thread_->PostTask(
             FROM_HERE,
-            base::BindOnce(
-                &DevtoolsClient::DispatchMessageReplyWithResultTask,
-                weak_ptr_factory_.GetWeakPtr(), std::move(null_value),
-                std::move(callback.callback_with_result), null_value.get()));
+            base::BindOnce(&DevtoolsClient::DispatchMessageReplyWithResultTask,
+                           weak_ptr_factory_.GetWeakPtr(),
+                           std::move(null_value),
+                           std::move(callback.callback_with_result), status,
+                           null_value.get()));
       } else {
-        std::move(callback.callback_with_result).Run(*null_value);
+        std::move(callback.callback_with_result).Run(status, *null_value);
       }
     } else {
       NOTREACHED() << "Reply has neither result nor error";
@@ -180,9 +183,10 @@
 
 void DevtoolsClient::DispatchMessageReplyWithResultTask(
     std::unique_ptr<base::Value> owning_message,
-    base::OnceCallback<void(const base::Value&)> callback,
+    base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback,
+    const ReplyStatus& reply_status,
     const base::Value* result_dict) {
-  std::move(callback).Run(*result_dict);
+  std::move(callback).Run(reply_status, *result_dict);
 }
 
 bool DevtoolsClient::DispatchEvent(std::unique_ptr<base::Value> owning_message,
@@ -227,6 +231,24 @@
   event_handler->Run(*result_dict);
 }
 
+void DevtoolsClient::FillReplyStatusFromErrorDict(
+    ReplyStatus* status,
+    const base::DictionaryValue& error_dict) {
+  const base::Value* code;
+  if (error_dict.Get("code", &code) && code->is_int()) {
+    status->error_code = code->GetInt();
+  } else {
+    status->error_code = -1;  // unknown error code
+  }
+
+  const base::Value* message;
+  if (error_dict.Get("message", &message) && message->is_string()) {
+    status->error_message = message->GetString();
+  } else {
+    status->error_message = "unknown";
+  }
+}
+
 void DevtoolsClient::AgentHostClosed(content::DevToolsAgentHost* agent_host) {
   // Agent host is not expected to be closed when this object is alive.
   renderer_crashed_ = true;
@@ -240,7 +262,7 @@
     : callback(std::move(callback)) {}
 
 DevtoolsClient::Callback::Callback(
-    base::OnceCallback<void(const base::Value&)> callback)
+    base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback)
     : callback_with_result(std::move(callback)) {}
 
 DevtoolsClient::Callback::~Callback() = default;
diff --git a/components/autofill_assistant/browser/devtools/devtools_client.h b/components/autofill_assistant/browser/devtools/devtools_client.h
index 479d5ed9..4b86b9e 100644
--- a/components/autofill_assistant/browser/devtools/devtools_client.h
+++ b/components/autofill_assistant/browser/devtools/devtools_client.h
@@ -44,7 +44,8 @@
   void SendMessage(
       const char* method,
       std::unique_ptr<base::Value> params,
-      base::OnceCallback<void(const base::Value&)> callback) override;
+      base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback)
+      override;
   void SendMessage(const char* method,
                    std::unique_ptr<base::Value> params,
                    base::OnceClosure callback) override;
@@ -64,13 +65,15 @@
     Callback();
     Callback(Callback&& other);
     explicit Callback(base::OnceClosure callback);
-    explicit Callback(base::OnceCallback<void(const base::Value&)> callback);
+    explicit Callback(base::OnceCallback<void(const ReplyStatus&,
+                                              const base::Value&)> callback);
     ~Callback();
 
     Callback& operator=(Callback&& other);
 
     base::OnceClosure callback;
-    base::OnceCallback<void(const base::Value&)> callback_with_result;
+    base::OnceCallback<void(const ReplyStatus&, const base::Value&)>
+        callback_with_result;
   };
 
   template <typename CallbackType>
@@ -81,7 +84,8 @@
                             const base::DictionaryValue& message_dict);
   void DispatchMessageReplyWithResultTask(
       std::unique_ptr<base::Value> owning_message,
-      base::OnceCallback<void(const base::Value&)> callback,
+      base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback,
+      const ReplyStatus& reply_status,
       const base::Value* result_dict);
   bool DispatchEvent(std::unique_ptr<base::Value> owning_message,
                      const base::DictionaryValue& message_dict);
@@ -91,6 +95,8 @@
   void DispatchEventTask(std::unique_ptr<base::Value> owning_message,
                          const EventHandler* event_handler,
                          const base::DictionaryValue* result_dict);
+  void FillReplyStatusFromErrorDict(ReplyStatus* status,
+                                    const base::DictionaryValue& error_dict);
 
   scoped_refptr<content::DevToolsAgentHost> agent_host_;
   scoped_refptr<base::SequencedTaskRunner> browser_main_thread_;
diff --git a/components/autofill_assistant/browser/devtools/message_dispatcher.h b/components/autofill_assistant/browser/devtools/message_dispatcher.h
index c78c9547..a517138 100644
--- a/components/autofill_assistant/browser/devtools/message_dispatcher.h
+++ b/components/autofill_assistant/browser/devtools/message_dispatcher.h
@@ -22,10 +22,24 @@
 // An internal interface for sending DevTools messages from the domain agents.
 class MessageDispatcher {
  public:
+  // Status of a SendMessage operation.
+  struct ReplyStatus {
+    // Error codes, as a number, -1 if error code is unknown.
+    //
+    // Possible values are listed on:
+    // src/third_party/inspector_protocol/lib/DispatcherBase_h.template
+    long error_code = 0;
+
+    std::string error_message;
+
+    bool is_ok() const { return error_code == 0; }
+  };
+
   virtual void SendMessage(
       const char* method,
       std::unique_ptr<base::Value> params,
-      base::OnceCallback<void(const base::Value&)> callback) = 0;
+      base::OnceCallback<void(const ReplyStatus&, const base::Value&)>
+          callback) = 0;
   virtual void SendMessage(const char* method,
                            std::unique_ptr<base::Value> params,
                            base::OnceClosure callback) = 0;
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index d8e7d83..e4be415 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -565,6 +565,12 @@
   // JavaScript exception column number, within the js snippet that was sent to
   // devtools runtime by the client, if reporting a JavaScript error.
   optional int32 js_exception_column_number = 5;
+
+  // Error code returned by devtools, if any. 0 is considered a success.
+  optional int32 devtools_error_code = 6;
+
+  // Error message returned by devtools, if any.
+  optional string devtools_error_message = 7;
 }
 
 // Message to report autofill related errors for debugging purposes.
diff --git a/components/autofill_assistant/browser/web/element_finder.cc b/components/autofill_assistant/browser/web/element_finder.cc
index 41cc5b1f..86fadcc 100644
--- a/components/autofill_assistant/browser/web/element_finder.cc
+++ b/components/autofill_assistant/browser/web/element_finder.cc
@@ -148,8 +148,10 @@
 }
 
 void ElementFinder::OnGetDocumentElement(
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::EvaluateResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to get document root element.";
     SendResult(status);
@@ -218,6 +220,7 @@
 
 void ElementFinder::OnQuerySelectorAll(
     size_t index,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result) {
     // It is possible for a document element to already exist, but not be
@@ -229,7 +232,8 @@
     SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
     return;
   }
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(1) << __func__ << ": Failed to query selector " << index << " of "
              << selector_;
@@ -282,10 +286,11 @@
 
 void ElementFinder::OnDescribeNodeForPseudoElement(
     dom::PseudoType pseudo_type,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::DescribeNodeResult> result) {
   if (!result || !result->GetNode()) {
     DVLOG(1) << __func__ << " Failed to describe the node for pseudo element.";
-    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+    SendResult(UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
 
@@ -310,6 +315,7 @@
 }
 
 void ElementFinder::OnResolveNodeForPseudoElement(
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::ResolveNodeResult> result) {
   if (result && result->GetObject() && result->GetObject()->HasObjectId()) {
     element_result_->object_id = result->GetObject()->GetObjectId();
@@ -320,10 +326,11 @@
 void ElementFinder::OnDescribeNode(
     const std::string& object_id,
     size_t index,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::DescribeNodeResult> result) {
   if (!result || !result->GetNode()) {
     DVLOG(1) << __func__ << " Failed to describe the node.";
-    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+    SendResult(UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
 
@@ -354,7 +361,8 @@
         frame_name, node->GetContentDocument()->GetDocumentURL());
     if (!element_result_->container_frame_host) {
       DVLOG(1) << __func__ << " Failed to find corresponding owner frame.";
-      SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+      SendResult(
+          UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
       return;
     }
   } else if (node->HasFrameId()) {
@@ -385,10 +393,11 @@
 
 void ElementFinder::OnResolveNode(
     size_t index,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::ResolveNodeResult> result) {
   if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
     DVLOG(1) << __func__ << " Failed to resolve object id from backend id.";
-    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+    SendResult(UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
 
@@ -410,4 +419,4 @@
   return ret_frame;
 }
 
-}  // namespace autofill_assistant
\ No newline at end of file
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/element_finder.h b/components/autofill_assistant/browser/web/element_finder.h
index 1db746fb..3acc08bd 100644
--- a/components/autofill_assistant/browser/web/element_finder.h
+++ b/components/autofill_assistant/browser/web/element_finder.h
@@ -14,6 +14,7 @@
 #include "components/autofill_assistant/browser/client_status.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
 #include "components/autofill_assistant/browser/selector.h"
 #include "components/autofill_assistant/browser/web/web_controller_worker.h"
 
@@ -61,20 +62,26 @@
 
  private:
   void SendResult(const ClientStatus& status);
-  void OnGetDocumentElement(std::unique_ptr<runtime::EvaluateResult> result);
+  void OnGetDocumentElement(const DevtoolsClient::ReplyStatus& reply_status,
+                            std::unique_ptr<runtime::EvaluateResult> result);
   void RecursiveFindElement(const std::string& object_id, size_t index);
   void OnQuerySelectorAll(
       size_t index,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnDescribeNodeForPseudoElement(
       dom::PseudoType pseudo_type,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<dom::DescribeNodeResult> result);
   void OnResolveNodeForPseudoElement(
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<dom::ResolveNodeResult> result);
   void OnDescribeNode(const std::string& object_id,
                       size_t index,
+                      const DevtoolsClient::ReplyStatus& reply_status,
                       std::unique_ptr<dom::DescribeNodeResult> result);
   void OnResolveNode(size_t index,
+                     const DevtoolsClient::ReplyStatus& reply_status,
                      std::unique_ptr<dom::ResolveNodeResult> result);
   content::RenderFrameHost* FindCorrespondingRenderFrameHost(
       std::string name,
diff --git a/components/autofill_assistant/browser/web/element_position_getter.cc b/components/autofill_assistant/browser/web/element_position_getter.cc
index 8bbbd16..09e0aab 100644
--- a/components/autofill_assistant/browser/web/element_position_getter.cc
+++ b/components/autofill_assistant/browser/web/element_position_getter.cc
@@ -69,6 +69,7 @@
 }
 
 void ElementPositionGetter::OnGetBoxModelForStableCheck(
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::GetBoxModelResult> result) {
   if (!result || !result->GetModel() || !result->GetModel()->GetContent()) {
     DVLOG(1) << __func__ << " Failed to get box model.";
@@ -137,8 +138,10 @@
 }
 
 void ElementPositionGetter::OnScrollIntoView(
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to scroll the element: " << status;
     OnError();
@@ -165,4 +168,4 @@
   }
 }
 
-}  // namespace autofill_assistant
\ No newline at end of file
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/element_position_getter.h b/components/autofill_assistant/browser/web/element_position_getter.h
index 7a30f6f..6639c419 100644
--- a/components/autofill_assistant/browser/web/element_position_getter.h
+++ b/components/autofill_assistant/browser/web/element_position_getter.h
@@ -14,6 +14,7 @@
 #include "components/autofill_assistant/browser/client_settings.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
 #include "components/autofill_assistant/browser/selector.h"
 #include "components/autofill_assistant/browser/web/web_controller_worker.h"
 
@@ -22,7 +23,6 @@
 }  // namespace content
 
 namespace autofill_assistant {
-class DevtoolsClient;
 
 // Worker class to get an element's position in viewport coordinates when it is
 // stable and the frame it belongs to has finished its visual update.
@@ -49,8 +49,10 @@
   void OnVisualStateUpdatedCallback(bool success);
   void GetAndWaitBoxModelStable();
   void OnGetBoxModelForStableCheck(
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<dom::GetBoxModelResult> result);
-  void OnScrollIntoView(std::unique_ptr<runtime::CallFunctionOnResult> result);
+  void OnScrollIntoView(const DevtoolsClient::ReplyStatus& reply_status,
+                        std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnResult(int x, int y);
   void OnError();
 
@@ -78,4 +80,4 @@
 
 }  // namespace autofill_assistant
 
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
\ No newline at end of file
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc
index 650e84e..85c2ae72 100644
--- a/components/autofill_assistant/browser/web/web_controller.cc
+++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -229,8 +229,10 @@
 template <typename T>
 void OnWaitForDocumentReadyState(
     base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<T> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   DVLOG_IF(1, !status.ok())
       << __func__ << " Failed to get document ready state.";
   int ready_state;
@@ -340,8 +342,10 @@
     std::unique_ptr<ElementFinder::Result> target_element,
     base::OnceCallback<void(const ClientStatus&)> callback,
     ClickAction::ClickType click_type,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to scroll the element.";
     std::move(callback).Run(status);
@@ -378,8 +382,10 @@
 
 void WebController::OnClickJS(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to click (javascript) the element.";
   }
@@ -436,11 +442,13 @@
     base::OnceCallback<void(const ClientStatus&)> callback,
     int x,
     int y,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<input::DispatchMouseEventResult> result) {
   if (!result) {
     DVLOG(1) << __func__
              << " Failed to dispatch mouse left button pressed event.";
-    std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
+    std::move(callback).Run(
+        UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
 
@@ -458,16 +466,25 @@
 
 void WebController::OnDispatchReleaseMouseEvent(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<input::DispatchMouseEventResult> result) {
+  if (!result) {
+    DVLOG(1) << __func__ << " Failed to dispatch release mouse event.";
+    std::move(callback).Run(
+        UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
+    return;
+  }
   std::move(callback).Run(OkClientStatus());
 }
 
 void WebController::OnDispatchTouchEventStart(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<input::DispatchTouchEventResult> result) {
   if (!result) {
     DVLOG(1) << __func__ << " Failed to dispatch touch start event.";
-    std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
+    std::move(callback).Run(
+        UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
 
@@ -484,8 +501,14 @@
 
 void WebController::OnDispatchTouchEventEnd(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<input::DispatchTouchEventResult> result) {
-  DCHECK(result);
+  if (!result) {
+    DVLOG(1) << __func__ << " Failed to dispatch touch end event.";
+    std::move(callback).Run(
+        UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
+    return;
+  }
   std::move(callback).Run(OkClientStatus());
 }
 
@@ -522,9 +545,10 @@
 
 void WebController::OnWaitForWindowHeightChange(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::EvaluateResult> result) {
   std::move(callback).Run(
-      CheckJavaScriptResult(result.get(), __FILE__, __LINE__));
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
 }
 
 void WebController::GetDocumentReadyState(
@@ -672,8 +696,10 @@
 
 void WebController::OnFocusElement(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   DVLOG_IF(1, !status.ok()) << __func__ << " Failed to focus on element.";
   std::move(callback).Run(status);
 }
@@ -728,8 +754,7 @@
     const autofill::FormFieldData& form_field) {
   if (form_data.fields.empty()) {
     DVLOG(1) << __func__ << " Failed to get form data to fill form.";
-    std::move(callback).Run(
-        UnexpectedErrorStatus(__FILE__, __LINE__));  // unexpected
+    std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
     return;
   }
 
@@ -737,8 +762,7 @@
       ContentAutofillDriver::GetForRenderFrameHost(container_frame_host);
   if (!driver) {
     DVLOG(1) << __func__ << " Failed to get the autofill driver.";
-    std::move(callback).Run(
-        UnexpectedErrorStatus(__FILE__, __LINE__));  // unexpected
+    std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
     return;
   }
 
@@ -812,8 +836,10 @@
 
 void WebController::OnSelectOption(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to select option.";
     std::move(callback).Run(status);
@@ -821,7 +847,8 @@
   }
   bool found;
   if (!SafeGetBool(result->GetResult(), &found)) {
-    std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
+    std::move(callback).Run(
+        UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
   if (!found) {
@@ -870,8 +897,10 @@
 
 void WebController::OnHighlightElement(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   DVLOG_IF(1, !status.ok()) << __func__ << " Failed to highlight element.";
   std::move(callback).Run(status);
 }
@@ -921,9 +950,11 @@
 
 void WebController::OnGetValueAttribute(
     base::OnceCallback<void(bool, const std::string&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   std::string value;
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   // Read the result returned from Javascript code.
   DVLOG_IF(1, !status.ok())
       << __func__ << "Failed to get attribute value: " << status;
@@ -1090,9 +1121,10 @@
 
 void WebController::OnSetValueAttribute(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   std::move(callback).Run(
-      CheckJavaScriptResult(result.get(), __FILE__, __LINE__));
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
 }
 
 void WebController::SetAttribute(
@@ -1149,9 +1181,10 @@
 
 void WebController::OnSetAttribute(
     base::OnceCallback<void(const ClientStatus&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   std::move(callback).Run(
-      CheckJavaScriptResult(result.get(), __FILE__, __LINE__));
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
 }
 
 void WebController::SendKeyboardInput(
@@ -1219,8 +1252,10 @@
 
 void WebController::OnGetVisualViewport(
     base::OnceCallback<void(bool, const RectF&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::EvaluateResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok() || !result->GetResult()->HasValue() ||
       !result->GetResult()->GetValue()->is_list() ||
       result->GetResult()->GetValue()->GetList().size() != 4u) {
@@ -1282,8 +1317,10 @@
 
 void WebController::OnGetElementPositionResult(
     base::OnceCallback<void(bool, const RectF&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok() || !result->GetResult()->HasValue() ||
       !result->GetResult()->GetValue()->is_list() ||
       result->GetResult()->GetValue()->GetList().size() != 4u) {
@@ -1327,8 +1364,10 @@
 
 void WebController::OnGetOuterHtml(
     base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
     DVLOG(2) << __func__ << " Failed to get HTML content for GetOuterHtml";
     std::move(callback).Run(status, "");
@@ -1358,8 +1397,10 @@
     int remaining_rounds,
     std::string object_id,
     base::OnceCallback<void(bool)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok() || remaining_rounds <= 0) {
     DVLOG(1) << __func__
              << " Failed to wait for the document to become interactive with "
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h
index 46d1bea..31c32e2 100644
--- a/components/autofill_assistant/browser/web/web_controller.h
+++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -237,10 +237,12 @@
       ClickAction::ClickType click_type,
       base::OnceCallback<void(const ClientStatus&)> callback);
   void OnClickJS(base::OnceCallback<void(const ClientStatus&)> callback,
+                 const DevtoolsClient::ReplyStatus& reply_status,
                  std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnScrollIntoView(std::unique_ptr<ElementFinder::Result> target_element,
                         base::OnceCallback<void(const ClientStatus&)> callback,
                         ClickAction::ClickType click_type,
+                        const DevtoolsClient::ReplyStatus& reply_status,
                         std::unique_ptr<runtime::CallFunctionOnResult> result);
   void TapOrClickOnCoordinates(
       ElementPositionGetter* getter_to_release,
@@ -253,21 +255,26 @@
       base::OnceCallback<void(const ClientStatus&)> callback,
       int x,
       int y,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<input::DispatchMouseEventResult> result);
   void OnDispatchReleaseMouseEvent(
       base::OnceCallback<void(const ClientStatus&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<input::DispatchMouseEventResult> result);
   void OnDispatchTouchEventStart(
       base::OnceCallback<void(const ClientStatus&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<input::DispatchTouchEventResult> result);
   void OnDispatchTouchEventEnd(
       base::OnceCallback<void(const ClientStatus&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<input::DispatchTouchEventResult> result);
   void OnFindElementForCheck(base::OnceCallback<void(bool)> callback,
                              const ClientStatus& status,
                              std::unique_ptr<ElementFinder::Result> result);
   void OnWaitForWindowHeightChange(
       base::OnceCallback<void(const ClientStatus&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::EvaluateResult> result);
 
   // Find the element given by |selector|. If multiple elements match
@@ -303,6 +310,7 @@
       std::unique_ptr<ElementFinder::Result> target_element,
       bool result);
   void OnFocusElement(base::OnceCallback<void(const ClientStatus&)> callback,
+                      const DevtoolsClient::ReplyStatus& reply_status,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForSelectOption(
       const std::string& selected_option,
@@ -310,6 +318,7 @@
       const ClientStatus& status,
       std::unique_ptr<ElementFinder::Result> element_result);
   void OnSelectOption(base::OnceCallback<void(const ClientStatus&)> callback,
+                      const DevtoolsClient::ReplyStatus& reply_status,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForHighlightElement(
       base::OnceCallback<void(const ClientStatus&)> callback,
@@ -317,6 +326,7 @@
       std::unique_ptr<ElementFinder::Result> element_result);
   void OnHighlightElement(
       base::OnceCallback<void(const ClientStatus&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForGetFieldValue(
       base::OnceCallback<void(bool, const std::string&)> callback,
@@ -324,6 +334,7 @@
       std::unique_ptr<ElementFinder::Result> element_result);
   void OnGetValueAttribute(
       base::OnceCallback<void(bool, const std::string&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void InternalSetFieldValue(
       const Selector& selector,
@@ -358,6 +369,7 @@
       const ClientStatus& status,
       std::unique_ptr<ElementFinder::Result> element_result);
   void OnSetAttribute(base::OnceCallback<void(const ClientStatus&)> callback,
+                      const DevtoolsClient::ReplyStatus& reply_status,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForSendKeyboardInput(
       const Selector& selector,
@@ -373,6 +385,7 @@
       std::unique_ptr<ElementFinder::Result> element_result);
   void OnSetValueAttribute(
       base::OnceCallback<void(const ClientStatus&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForGetOuterHtml(
       base::OnceCallback<void(const ClientStatus&, const std::string&)>
@@ -381,6 +394,7 @@
       std::unique_ptr<ElementFinder::Result> element_result);
   void OnGetOuterHtml(base::OnceCallback<void(const ClientStatus&,
                                               const std::string&)> callback,
+                      const DevtoolsClient::ReplyStatus& reply_status,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForPosition(
       base::OnceCallback<void(bool, const RectF&)> callback,
@@ -388,9 +402,11 @@
       std::unique_ptr<ElementFinder::Result> result);
   void OnGetVisualViewport(
       base::OnceCallback<void(bool, const RectF&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::EvaluateResult> result);
   void OnGetElementPositionResult(
       base::OnceCallback<void(bool, const RectF&)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
 
   // Creates a new instance of DispatchKeyEventParams for the specified type and
@@ -410,6 +426,7 @@
       int remaining_rounds,
       std::string object_id,
       base::OnceCallback<void(bool)> callback,
+      const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForWaitForDocumentReadyState(
       DocumentReadyState min_ready_state,
diff --git a/components/autofill_assistant/browser/web/web_controller_util.cc b/components/autofill_assistant/browser/web/web_controller_util.cc
index 8ca38eeb..aa0f66d7 100644
--- a/components/autofill_assistant/browser/web/web_controller_util.cc
+++ b/components/autofill_assistant/browser/web/web_controller_util.cc
@@ -14,14 +14,28 @@
   return status;
 }
 
-ClientStatus JavaScriptErrorStatus(const std::string& file,
-                                   int line,
-                                   const runtime::ExceptionDetails* exception) {
-  ClientStatus status(UNEXPECTED_JS_ERROR);
-  auto* info = status.mutable_details()->mutable_unexpected_error_info();
-  info->set_source_file(file);
-  info->set_source_line_number(line);
+ClientStatus UnexpectedDevtoolsErrorStatus(
+    const DevtoolsClient::ReplyStatus& reply_status,
+    const std::string& file,
+    int line) {
+  ClientStatus status = UnexpectedErrorStatus(file, line);
+  if (!reply_status.is_ok()) {
+    auto* info = status.mutable_details()->mutable_unexpected_error_info();
+    info->set_devtools_error_code(reply_status.error_code);
+    info->set_devtools_error_message(reply_status.error_message);
+  }
+  return status;
+}
+
+ClientStatus JavaScriptErrorStatus(
+    const DevtoolsClient::ReplyStatus& reply_status,
+    const std::string& file,
+    int line,
+    const runtime::ExceptionDetails* exception) {
+  ClientStatus status = UnexpectedDevtoolsErrorStatus(reply_status, file, line);
+  status.set_proto_status(UNEXPECTED_JS_ERROR);
   if (exception) {
+    auto* info = status.mutable_details()->mutable_unexpected_error_info();
     if (exception->HasException() &&
         exception->GetException()->HasClassName()) {
       info->set_js_exception_classname(
@@ -67,4 +81,4 @@
   return false;
 }
 
-}  //  namespace autofill_assistant
\ No newline at end of file
+}  //  namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/web_controller_util.h b/components/autofill_assistant/browser/web/web_controller_util.h
index 79c618c..b966695 100644
--- a/components/autofill_assistant/browser/web/web_controller_util.h
+++ b/components/autofill_assistant/browser/web/web_controller_util.h
@@ -8,30 +8,48 @@
 #include <string>
 #include "components/autofill_assistant/browser/client_status.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
 
 namespace autofill_assistant {
 
 // Builds a ClientStatus appropriate for an unexpected error.
 //
 // This should only be used in situations where getting an error cannot be
-// anything but a bug in the client.
+// anything but a bug in the client and no devtools ReplyStatus is available.
 ClientStatus UnexpectedErrorStatus(const std::string& file, int line);
 
+// Builds a ClientStatus appropriate for an unexpected error in a devtools
+// response.
+//
+// This should only be used in situations where getting an error cannot be
+// anything but a bug in the client.
+ClientStatus UnexpectedDevtoolsErrorStatus(
+    const DevtoolsClient::ReplyStatus& reply_status,
+    const std::string& file,
+    int line);
+
 // Builds a ClientStatus appropriate for a JavaScript error.
-ClientStatus JavaScriptErrorStatus(const std::string& file,
-                                   int line,
-                                   const runtime::ExceptionDetails* exception);
+ClientStatus JavaScriptErrorStatus(
+    const DevtoolsClient::ReplyStatus& reply_status,
+    const std::string& file,
+    int line,
+    const runtime::ExceptionDetails* exception);
 
 // Makes sure that the given EvaluateResult exists, is successful and contains a
 // result.
 template <typename T>
-ClientStatus CheckJavaScriptResult(T* result, const char* file, int line) {
+ClientStatus CheckJavaScriptResult(
+    const DevtoolsClient::ReplyStatus& reply_status,
+    T* result,
+    const char* file,
+    int line) {
   if (!result)
-    return JavaScriptErrorStatus(file, line, nullptr);
+    return JavaScriptErrorStatus(reply_status, file, line, nullptr);
   if (result->HasExceptionDetails())
-    return JavaScriptErrorStatus(file, line, result->GetExceptionDetails());
+    return JavaScriptErrorStatus(reply_status, file, line,
+                                 result->GetExceptionDetails());
   if (!result->GetResult())
-    return JavaScriptErrorStatus(file, line, nullptr);
+    return JavaScriptErrorStatus(reply_status, file, line, nullptr);
   return OkClientStatus();
 }
 
@@ -49,4 +67,4 @@
 
 }  //  namespace autofill_assistant
 
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
\ No newline at end of file
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
diff --git a/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc b/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc
index 88ec255..37a70d0 100644
--- a/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc
+++ b/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc
@@ -5,9 +5,12 @@
 #include "components/chromeos_camera/fake_mjpeg_decode_accelerator.h"
 
 #include "base/bind.h"
+#include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "media/base/unaligned_shared_memory.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_types.h"
 
 namespace chromeos_camera {
 
@@ -58,8 +61,17 @@
                      std::move(video_frame), base::Passed(&src_shm)));
 }
 
+void FakeMjpegDecodeAccelerator::Decode(
+    int32_t task_id,
+    base::ScopedFD src_dmabuf_fd,
+    size_t src_size,
+    off_t src_offset,
+    scoped_refptr<media::VideoFrame> dst_frame) {
+  NOTIMPLEMENTED();
+}
+
 void FakeMjpegDecodeAccelerator::DecodeOnDecoderThread(
-    int32_t bitstream_buffer_id,
+    int32_t task_id,
     scoped_refptr<media::VideoFrame> video_frame,
     std::unique_ptr<media::UnalignedSharedMemory> src_shm) {
   DCHECK(decoder_task_runner_->BelongsToCurrentThread());
@@ -73,32 +85,29 @@
   client_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&FakeMjpegDecodeAccelerator::OnDecodeDoneOnClientThread,
-                     weak_factory_.GetWeakPtr(), bitstream_buffer_id));
+                     weak_factory_.GetWeakPtr(), task_id));
 }
 
 bool FakeMjpegDecodeAccelerator::IsSupported() {
   return true;
 }
 
-void FakeMjpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
-                                             Error error) {
+void FakeMjpegDecodeAccelerator::NotifyError(int32_t task_id, Error error) {
   client_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&FakeMjpegDecodeAccelerator::NotifyErrorOnClientThread,
-                     weak_factory_.GetWeakPtr(), bitstream_buffer_id, error));
+                     weak_factory_.GetWeakPtr(), task_id, error));
 }
 
-void FakeMjpegDecodeAccelerator::NotifyErrorOnClientThread(
-    int32_t bitstream_buffer_id,
-    Error error) {
+void FakeMjpegDecodeAccelerator::NotifyErrorOnClientThread(int32_t task_id,
+                                                           Error error) {
   DCHECK(client_task_runner_->BelongsToCurrentThread());
-  client_->NotifyError(bitstream_buffer_id, error);
+  client_->NotifyError(task_id, error);
 }
 
-void FakeMjpegDecodeAccelerator::OnDecodeDoneOnClientThread(
-    int32_t input_buffer_id) {
+void FakeMjpegDecodeAccelerator::OnDecodeDoneOnClientThread(int32_t task_id) {
   DCHECK(client_task_runner_->BelongsToCurrentThread());
-  client_->VideoFrameReady(input_buffer_id);
+  client_->VideoFrameReady(task_id);
 }
 
 }  // namespace chromeos_camera
diff --git a/components/chromeos_camera/fake_mjpeg_decode_accelerator.h b/components/chromeos_camera/fake_mjpeg_decode_accelerator.h
index 14db64ab..ea51eb55 100644
--- a/components/chromeos_camera/fake_mjpeg_decode_accelerator.h
+++ b/components/chromeos_camera/fake_mjpeg_decode_accelerator.h
@@ -34,16 +34,21 @@
   bool Initialize(MjpegDecodeAccelerator::Client* client) override;
   void Decode(media::BitstreamBuffer bitstream_buffer,
               scoped_refptr<media::VideoFrame> video_frame) override;
+  void Decode(int32_t task_id,
+              base::ScopedFD src_dmabuf_fd,
+              size_t src_size,
+              off_t src_offset,
+              scoped_refptr<media::VideoFrame> dst_frame) override;
   bool IsSupported() override;
 
  private:
   void DecodeOnDecoderThread(
-      int32_t bitstream_buffer_id,
+      int32_t task_id,
       scoped_refptr<media::VideoFrame> video_frame,
       std::unique_ptr<media::UnalignedSharedMemory> src_shm);
-  void NotifyError(int32_t bitstream_buffer_id, Error error);
-  void NotifyErrorOnClientThread(int32_t bitstream_buffer_id, Error error);
-  void OnDecodeDoneOnClientThread(int32_t input_buffer_id);
+  void NotifyError(int32_t task_id, Error error);
+  void NotifyErrorOnClientThread(int32_t task_id, Error error);
+  void OnDecodeDoneOnClientThread(int32_t task_id);
 
   // Task runner for calls to |client_|.
   const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_;
diff --git a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
index d1ee1ea3..fe3ff09 100644
--- a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
+++ b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -310,9 +310,9 @@
   // support them.
   const std::vector<TestImage*>& test_aligned_images_;
 
-  // JpegClient doesn't own |test_images_|.
+  // JpegClient doesn't own |test_unaligned_images_|.
   // The resolutions of these images may be unaligned.
-  const std::vector<TestImage*>& test_images_;
+  const std::vector<TestImage*>& test_unaligned_images_;
 
   // A map that stores HW encoding start timestamp for each output buffer id.
   std::map<int, base::TimeTicks> buffer_id_to_start_time_;
@@ -349,7 +349,7 @@
                        const std::vector<TestImage*>& test_images,
                        media::test::ClientStateNotification<ClientState>* note)
     : test_aligned_images_(test_aligned_images),
-      test_images_(test_images),
+      test_unaligned_images_(test_images),
       state_(ClientState::CREATED),
       note_(note),
       gpu_memory_buffer_manager_(new media::LocalGpuMemoryBufferManager()) {}
@@ -399,7 +399,8 @@
   if (buffer_id < static_cast<int32_t>(test_aligned_images_.size())) {
     test_image = test_aligned_images_[buffer_id];
   } else {
-    test_image = test_images_[buffer_id - test_aligned_images_.size()];
+    test_image =
+        test_unaligned_images_[buffer_id - test_aligned_images_.size()];
   }
 
   if (hw_out_frame_ && !hw_out_frame_->IsMappable()) {
@@ -530,13 +531,13 @@
 
 TestImage* JpegClient::GetTestImage(int32_t bitstream_buffer_id) {
   DCHECK_LT(static_cast<size_t>(bitstream_buffer_id),
-            test_aligned_images_.size() + test_images_.size());
+            test_aligned_images_.size() + test_unaligned_images_.size());
   TestImage* image_file;
   if (bitstream_buffer_id < static_cast<int32_t>(test_aligned_images_.size())) {
     image_file = test_aligned_images_[bitstream_buffer_id];
   } else {
-    image_file =
-        test_images_[bitstream_buffer_id - test_aligned_images_.size()];
+    image_file = test_unaligned_images_[bitstream_buffer_id -
+                                        test_aligned_images_.size()];
   }
 
   return image_file;
@@ -682,10 +683,10 @@
   // JpegEncodeAccelerator implementations.
   base::test::TaskEnvironment task_environment_;
 
-  // The elements of |test_aligned_images_| and |test_images_| are
+  // The elements of |test_aligned_images_| and |test_unaligned_images_| are
   // owned by JpegEncodeAcceleratorTestEnvironment.
   std::vector<TestImage*> test_aligned_images_;
-  std::vector<TestImage*> test_images_;
+  std::vector<TestImage*> test_unaligned_images_;
 
  protected:
   DISALLOW_COPY_AND_ASSIGN(JpegEncodeAcceleratorTest);
@@ -706,7 +707,7 @@
     notes.push_back(
         std::make_unique<media::test::ClientStateNotification<ClientState>>());
     clients.push_back(std::make_unique<JpegClient>(
-        test_aligned_images_, test_images_, notes.back().get()));
+        test_aligned_images_, test_unaligned_images_, notes.back().get()));
     encoder_thread.task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&JpegClient::CreateJpegEncoder,
                                   base::Unretained(clients.back().get())));
@@ -750,12 +751,12 @@
   // For unaligned images, V4L2 may not be able to encode them so skip for V4L2
   // cases.
 #else
-  for (size_t index = 0; index < test_images_.size(); index++) {
+  for (size_t index = 0; index < test_unaligned_images_.size(); index++) {
     int buffer_id = index + test_aligned_images_.size();
     VLOG(3) << buffer_id
-            << ",width:" << test_images_[index]->visible_size.width();
-    VLOG(3) << buffer_id
-            << ",height:" << test_images_[index]->visible_size.height();
+            << ",width:" << test_unaligned_images_[index]->visible_size.width();
+    VLOG(3) << buffer_id << ",height:"
+            << test_unaligned_images_[index]->visible_size.height();
 
     if (!is_dma) {
       for (size_t i = 0; i < num_concurrent_encoders; i++) {
@@ -794,7 +795,7 @@
 TEST_F(JpegEncodeAcceleratorTest, SimpleEncode) {
   for (size_t i = 0; i < g_env->repeat_; i++) {
     for (auto& image : g_env->image_data_user_) {
-      test_images_.push_back(image.get());
+      test_aligned_images_.push_back(image.get());
     }
   }
   TestEncode(1, false);
@@ -802,14 +803,13 @@
 
 TEST_F(JpegEncodeAcceleratorTest, MultipleEncoders) {
   for (auto& image : g_env->image_data_user_) {
-    test_images_.push_back(image.get());
+    test_aligned_images_.push_back(image.get());
   }
   TestEncode(3, false);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, ResolutionChange) {
-  test_images_.push_back(g_env->image_data_640x368_black_.get());
-  test_images_.push_back(g_env->image_data_640x360_black_.get());
+  test_aligned_images_.push_back(g_env->image_data_640x368_black_.get());
   test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get());
   TestEncode(1, false);
 }
@@ -822,14 +822,14 @@
 }
 
 TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignment) {
-  test_images_.push_back(g_env->image_data_640x360_black_.get());
+  test_unaligned_images_.push_back(g_env->image_data_640x360_black_.get());
   TestEncode(1, false);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, SimpleDmaEncode) {
   for (size_t i = 0; i < g_env->repeat_; i++) {
     for (auto& image : g_env->image_data_user_) {
-      test_images_.push_back(image.get());
+      test_aligned_images_.push_back(image.get());
     }
   }
   TestEncode(1, true);
@@ -837,14 +837,13 @@
 
 TEST_F(JpegEncodeAcceleratorTest, MultipleDmaEncoders) {
   for (auto& image : g_env->image_data_user_) {
-    test_images_.push_back(image.get());
+    test_aligned_images_.push_back(image.get());
   }
   TestEncode(3, true);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, ResolutionChangeDma) {
-  test_images_.push_back(g_env->image_data_640x368_black_.get());
-  test_images_.push_back(g_env->image_data_640x360_black_.get());
+  test_aligned_images_.push_back(g_env->image_data_640x368_black_.get());
   test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get());
   TestEncode(1, true);
 }
@@ -857,7 +856,7 @@
 }
 
 TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignmentDma) {
-  test_images_.push_back(g_env->image_data_640x360_black_.get());
+  test_unaligned_images_.push_back(g_env->image_data_640x360_black_.get());
   TestEncode(1, true);
 }
 
diff --git a/components/chromeos_camera/mjpeg_decode_accelerator.h b/components/chromeos_camera/mjpeg_decode_accelerator.h
index 35c704b..454b4b0c 100644
--- a/components/chromeos_camera/mjpeg_decode_accelerator.h
+++ b/components/chromeos_camera/mjpeg_decode_accelerator.h
@@ -5,19 +5,26 @@
 #ifndef COMPONENTS_CHROMEOS_CAMERA_MJPEG_DECODE_ACCELERATOR_H_
 #define COMPONENTS_CHROMEOS_CAMERA_MJPEG_DECODE_ACCELERATOR_H_
 
+#include <stddef.h>
 #include <stdint.h>
+#include <sys/types.h>
 
+#include "base/callback.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_refptr.h"
 #include "media/base/bitstream_buffer.h"
-#include "media/base/video_frame.h"
+
+namespace media {
+class VideoFrame;
+}
 
 namespace chromeos_camera {
 
 // MJPEG decoder interface.
 // The input are JPEG images including headers (Huffman tables may be omitted).
-// The output color format is I420. The decoder will convert the color format
-// to I420 if the color space or subsampling does not match that and if it is
-// capable of doing so. The client is responsible for allocating buffers and
-// keeps the ownership of them.
+// The decoder will convert to the output color format if the input color format
+// or subsampling does not match that and if it is capable of doing so. The
+// client is responsible for allocating buffers and keeps the ownership of them.
 // The intended use case of this interface is decoding MJPEG images coming
 // from camera capture. It can also be used for normal still JPEG image
 // decoding, but normal JPEG images may use more JPEG features that may not be
@@ -27,7 +34,7 @@
   // Callback for JPEG decoder initialization.
   typedef base::Callback<void(bool success)> InitCB;
 
-  static const int32_t kInvalidBitstreamBufferId = -1;
+  static const int32_t kInvalidTaskId = -1;
 
   // Enumeration of decode errors generated by NotifyError callback. These
   // values are persisted to logs. Entries should not be renumbered and numeric
@@ -58,9 +65,8 @@
    public:
     // Callback called after each successful Decode().
     // Parameters:
-    //  |bitstream_buffer_id| is the id of BitstreamBuffer corresponding to
-    //  Decode() call.
-    virtual void VideoFrameReady(int32_t bitstream_buffer_id) = 0;
+    //  |task_id| is the id passed to Decode() call.
+    virtual void VideoFrameReady(int32_t task_id) = 0;
 
     // Callback to notify errors. Client is responsible for destroying JDA when
     // receiving a fatal error, i.e. PLATFORM_FAILURE. For other errors, client
@@ -68,11 +74,11 @@
     // using the same instance of JDA.
     // Parameters:
     //  |error| is the error code.
-    //  |bitstream_buffer_id| is the bitstream buffer id that resulted in the
-    //  recoverable error. For PLATFORM_FAILURE, |bitstream_buffer_id| may be
-    //  kInvalidBitstreamBufferId if the error was not related to any
-    //  particular buffer being processed.
-    virtual void NotifyError(int32_t bitstream_buffer_id, Error error) = 0;
+    //  |task_id| is the id passed to Decode() call that resulted in the
+    //  recoverable error. For PLATFORM_FAILURE, |task_id| may be
+    //  |kInvalidTaskId| if the error was not related to any particular buffer
+    //  being processed.
+    virtual void NotifyError(int32_t task_id, Error error) = 0;
 
    protected:
     virtual ~Client() {}
@@ -100,27 +106,37 @@
   // Decodes the given bitstream buffer that contains one JPEG frame. It
   // supports at least baseline encoding defined in JPEG ISO/IEC 10918-1. The
   // decoder will convert the output to |video_frame->format()| or return
-  // PLATFORM_FAILURE if it cannot convert. Client still owns this buffer, but
-  // should deallocate or access the buffer only after receiving a decode
-  // callback VideoFrameReady with the corresponding |bitstream_buffer_id|, or
-  // NotifyError.
+  // PLATFORM_FAILURE if it cannot convert.
   // Parameters:
   //  |bitstream_buffer| contains encoded JPEG frame.
   //  |video_frame| contains an allocated video frame for the output, backed
-  //  with an UnsafeSharedMemoryRegion.
+  //  with an UnsafeSharedMemoryRegion or DMA buffer.
   //
   //  Client is responsible for filling the |video_frame->coded_size()|,
   //  |video_frame->visible_rect()|, and allocating its backing buffer. For
-  //  unsafe shared memory backed VideoFrames, only I420 format is supported.
-  //  For DMA-buf backed VideoFrames, the supported formats depend on the
-  //  underlying hardware implementation. After decode completes, the decoded
-  //  JPEG frame will be filled into the |video_frame|. Ownership of the
+  //  unsafe shared memory backed VideoFrames, I420 and NV12 formats are
+  //  supported. For DMA-buf backed VideoFrames, the supported formats depend on
+  //  the underlying hardware implementation. After decode completes, the
+  //  decoded JPEG frame will be filled into the |video_frame|. Ownership of the
   //  |bitstream_buffer| and |video_frame| remains with the client. The client
   //  is not allowed to deallocate them before VideoFrameReady or NotifyError()
   //  is invoked for given id of |bitstream_buffer|, or destructor returns.
   virtual void Decode(media::BitstreamBuffer bitstream_buffer,
                       scoped_refptr<media::VideoFrame> video_frame) = 0;
 
+  // The same as above but the JPEG image is stored in a DMA buffer.
+  // Parameters:
+  //  |src_dmabuf_fd| contains encoded JPEG frame.
+  //  |src_size| is the size of the JPEG frame.
+  //  |src_offset| is the offset at which the JPEG data starts.
+  //  |dst_frame| contains an allocated video frame for the output, backed with
+  //  an UnsafeSharedMemoryRegion or DMA buffer.
+  virtual void Decode(int32_t task_id,
+                      base::ScopedFD src_dmabuf_fd,
+                      size_t src_size,
+                      off_t src_offset,
+                      scoped_refptr<media::VideoFrame> dst_frame) = 0;
+
   // Returns true when the JPEG decoder is supported. This can be called before
   // Initialize().
   virtual bool IsSupported() = 0;
diff --git a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
index 286b3a1..917452a4 100644
--- a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
+++ b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <memory>
 #include <string>
@@ -18,11 +19,13 @@
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/platform_shared_memory_region.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/optional.h"
 #include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
@@ -201,6 +204,10 @@
       const media::VideoFrameLayout& layout,
       const gfx::Rect& visible_rect);
 
+  // Creates a DMA buffer file descriptor that contains |size| bytes of linear
+  // data initialized with |data|.
+  base::ScopedFD CreateDmaBufFd(const void* data, size_t size);
+
   // Gets a list of supported DMA-buf frame formats for
   // CreateDmaBufVideoFrame().
   std::vector<media::VideoPixelFormat> GetSupportedDmaBufFormats();
@@ -266,7 +273,8 @@
     media::VideoPixelFormat format,
     const gfx::Size& coded_size,
     const gfx::Size& visible_size) {
-  size_t data_size = media::VideoFrame::AllocationSize(format, coded_size);
+  const size_t data_size =
+      media::VideoFrame::AllocationSize(format, coded_size);
   auto shm_region = base::UnsafeSharedMemoryRegion::Create(data_size);
   if (!shm_region.IsValid()) {
     LOG(ERROR) << "Failed to create shared memory";
@@ -299,13 +307,10 @@
     const gfx::Size& coded_size,
     const gfx::Size& visible_size,
     std::unique_ptr<gfx::GpuMemoryBuffer>* backing_gmb) {
-  if (!gpu_memory_buffer_manager_) {
-    LOG(ERROR) << "GpuMemoryBufferManager is not created" << format;
-    return nullptr;
-  }
+  DCHECK(gpu_memory_buffer_manager_);
 
   // Create a GpuMemoryBuffer and get a NativePixmapHandle from it.
-  base::Optional<gfx::BufferFormat> gfx_format =
+  const base::Optional<gfx::BufferFormat> gfx_format =
       media::VideoPixelFormatToGfxBufferFormat(format);
   if (!gfx_format) {
     LOG(ERROR) << "Unsupported pixel format: " << format;
@@ -331,7 +336,7 @@
     return nullptr;
   }
 
-  // Zero the memory.
+  // Fill in the memory with zeros.
   if (!gmb->Map()) {
     LOG(ERROR) << "Failed to map GpuMemoryBuffer";
     return nullptr;
@@ -352,7 +357,7 @@
                         base::checked_cast<size_t>(plane.size));
     dmabuf_fds.push_back(std::move(plane.fd));
   }
-  base::Optional<media::VideoFrameLayout> layout =
+  const base::Optional<media::VideoFrameLayout> layout =
       media::VideoFrameLayout::CreateWithPlanes(format, coded_size,
                                                 std::move(planes));
   if (!layout) {
@@ -394,6 +399,51 @@
   return frame;
 }
 
+base::ScopedFD MjpegDecodeAcceleratorTestEnvironment::CreateDmaBufFd(
+    const void* data,
+    size_t size) {
+  DCHECK(data);
+  DCHECK_GT(size, 0u);
+  DCHECK(gpu_memory_buffer_manager_);
+
+  // The DMA-buf FD is intended to allow importing into hardware accelerators,
+  // so we allocate the buffer by GMB manager instead of simply memfd_create().
+  // The GMB has R_8 format and dimensions (|size|, 1).
+  std::unique_ptr<gfx::GpuMemoryBuffer> gmb =
+      gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
+          gfx::Size(base::checked_cast<int>(size), 1), gfx::BufferFormat::R_8,
+          kBufferUsage, gpu::kNullSurfaceHandle);
+  if (!gmb) {
+    LOG(ERROR) << "Failed to create GpuMemoryBuffer";
+    return base::ScopedFD();
+  }
+
+  gfx::GpuMemoryBufferHandle gmb_handle = gmb->CloneHandle();
+  if (gmb_handle.type != gfx::NATIVE_PIXMAP) {
+    LOG(ERROR) << "The GpuMemoryBufferHandle doesn't have type NATIVE_PIXMAP";
+    return base::ScopedFD();
+  }
+  if (gmb_handle.native_pixmap_handle.planes.size() != 1) {
+    LOG(ERROR) << "The number of planes of NativePixmapHandle is not 1 for R_8 "
+                  "format";
+    return base::ScopedFD();
+  }
+  if (gmb_handle.native_pixmap_handle.planes[0].offset != 0) {
+    LOG(ERROR) << "The memory offset is not zero";
+    return base::ScopedFD();
+  }
+
+  // Fill in the memory with |data|.
+  if (!gmb->Map()) {
+    LOG(ERROR) << "Failed to map GpuMemoryBuffer";
+    return base::ScopedFD();
+  }
+  memcpy(gmb->memory(0), data, size);
+  gmb->Unmap();
+
+  return std::move(gmb_handle.native_pixmap_handle.planes[0].fd);
+}
+
 std::vector<media::VideoPixelFormat>
 MjpegDecodeAcceleratorTestEnvironment::GetSupportedDmaBufFormats() {
   constexpr media::VideoPixelFormat kPreferredFormats[] = {
@@ -428,13 +478,13 @@
       bool is_skip);
   ~JpegClient() override;
   void CreateJpegDecoder();
-  void StartDecode(int32_t bitstream_buffer_id, bool do_prepare_memory);
-  void PrepareMemory(int32_t bitstream_buffer_id);
-  bool GetSoftwareDecodeResult(int32_t bitstream_buffer_id);
+  void StartDecode(int32_t task_id, bool do_prepare_memory);
+  void PrepareMemory(int32_t task_id);
+  bool GetSoftwareDecodeResult(int32_t task_id);
 
   // MjpegDecodeAccelerator::Client implementation.
-  void VideoFrameReady(int32_t bitstream_buffer_id) override;
-  void NotifyError(int32_t bitstream_buffer_id,
+  void VideoFrameReady(int32_t task_id) override;
+  void NotifyError(int32_t task_id,
                    MjpegDecodeAccelerator::Error error) override;
 
   // Accessors.
@@ -449,7 +499,7 @@
 
   // Save a video frame that contains a decoded JPEG. The output is a PNG file.
   // The suffix will be added before the .png extension.
-  void SaveToFile(int32_t bitstream_buffer_id,
+  void SaveToFile(int32_t task_id,
                   scoped_refptr<media::VideoFrame> in_frame,
                   const std::string& suffix = "");
 
@@ -471,9 +521,11 @@
   // Skip JDA decode result. Used for testing performance.
   bool is_skip_;
 
-  // Mapped memory of input file.
+  // Input shared memory and mapping.
   base::UnsafeSharedMemoryRegion in_shm_;
   base::WritableSharedMemoryMapping in_shm_mapping_;
+  // Input DMA buffer file descriptor.
+  base::ScopedFD in_dmabuf_fd_;
   // Output video frame from the hardware decoder.
   std::unique_ptr<gfx::GpuMemoryBuffer> hw_out_gmb_;
   scoped_refptr<media::VideoFrame> hw_out_dmabuf_frame_;
@@ -533,13 +585,13 @@
   SetState(CS_INITIALIZED);
 }
 
-void JpegClient::VideoFrameReady(int32_t bitstream_buffer_id) {
+void JpegClient::VideoFrameReady(int32_t task_id) {
   if (is_skip_) {
     SetState(CS_DECODE_PASS);
     return;
   }
 
-  if (!GetSoftwareDecodeResult(bitstream_buffer_id)) {
+  if (!GetSoftwareDecodeResult(task_id)) {
     SetState(CS_ERROR);
     return;
   }
@@ -556,8 +608,8 @@
   }
 
   if (g_save_to_file) {
-    SaveToFile(bitstream_buffer_id, hw_out_frame_, "_hw");
-    SaveToFile(bitstream_buffer_id, sw_out_frame_, "_sw");
+    SaveToFile(task_id, hw_out_frame_, "_hw");
+    SaveToFile(task_id, sw_out_frame_, "_sw");
   }
 
   double difference = GetMeanAbsoluteDifference();
@@ -570,25 +622,20 @@
   }
 }
 
-void JpegClient::NotifyError(int32_t bitstream_buffer_id,
+void JpegClient::NotifyError(int32_t task_id,
                              MjpegDecodeAccelerator::Error error) {
-  LOG(ERROR) << "Notifying of error " << error << " for buffer id "
-             << bitstream_buffer_id;
+  LOG(ERROR) << "Notifying of error " << error << " for task id " << task_id;
   SetState(CS_ERROR);
 }
 
-void JpegClient::PrepareMemory(int32_t bitstream_buffer_id) {
-  ParsedJpegImage* image_file = test_image_files_[bitstream_buffer_id];
-
-  size_t input_size = image_file->data_str.size();
-  if (!in_shm_mapping_.IsValid() || input_size > in_shm_mapping_.size()) {
-    in_shm_ = base::UnsafeSharedMemoryRegion::Create(input_size);
-    in_shm_mapping_ = in_shm_.Map();
-    ASSERT_TRUE(in_shm_mapping_.IsValid());
-  }
-  memcpy(in_shm_mapping_.memory(), image_file->data_str.data(), input_size);
+void JpegClient::PrepareMemory(int32_t task_id) {
+  ParsedJpegImage* image_file = test_image_files_[task_id];
 
   if (use_dmabuf_) {
+    in_dmabuf_fd_ = g_env->CreateDmaBufFd(image_file->data_str.data(),
+                                          image_file->data_str.size());
+    ASSERT_TRUE(in_dmabuf_fd_.is_valid());
+
     // TODO(kamesan): create test cases for more formats when they're used.
     std::vector<media::VideoPixelFormat> supported_formats =
         g_env->GetSupportedDmaBufFormats();
@@ -599,6 +646,15 @@
     ASSERT_TRUE(hw_out_dmabuf_frame_);
     ASSERT_TRUE(hw_out_gmb_);
   } else {
+    in_shm_mapping_ = base::WritableSharedMemoryMapping();
+    in_shm_ =
+        base::UnsafeSharedMemoryRegion::Create(image_file->data_str.size());
+    ASSERT_TRUE(in_shm_.IsValid());
+    in_shm_mapping_ = in_shm_.Map();
+    ASSERT_TRUE(in_shm_mapping_.IsValid());
+    memcpy(in_shm_mapping_.memory(), image_file->data_str.data(),
+           image_file->data_str.size());
+
     // MJDA only supports I420 format for SHM output buffer.
     hw_out_frame_ = g_env->CreateShmVideoFrame(media::PIXEL_FORMAT_I420,
                                                image_file->coded_size,
@@ -618,11 +674,11 @@
   state_ = new_state;
 }
 
-void JpegClient::SaveToFile(int32_t bitstream_buffer_id,
+void JpegClient::SaveToFile(int32_t task_id,
                             scoped_refptr<media::VideoFrame> in_frame,
                             const std::string& suffix) {
   LOG_ASSERT(in_frame);
-  ParsedJpegImage* image_file = test_image_files_[bitstream_buffer_id];
+  ParsedJpegImage* image_file = test_image_files_[task_id];
 
   // First convert to ARGB format. Note that in our case, the coded size and the
   // visible size will be the same.
@@ -697,40 +753,48 @@
   return mean_abs_difference;
 }
 
-void JpegClient::StartDecode(int32_t bitstream_buffer_id,
-                             bool do_prepare_memory) {
-  ASSERT_LT(static_cast<size_t>(bitstream_buffer_id), test_image_files_.size());
-  ParsedJpegImage* image_file = test_image_files_[bitstream_buffer_id];
+void JpegClient::StartDecode(int32_t task_id, bool do_prepare_memory) {
+  ASSERT_LT(base::checked_cast<size_t>(task_id), test_image_files_.size());
+  ParsedJpegImage* image_file = test_image_files_[task_id];
 
   if (do_prepare_memory)
-    PrepareMemory(bitstream_buffer_id);
+    PrepareMemory(task_id);
 
-  auto dup_region = base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
-      in_shm_.Duplicate());
-  media::BitstreamBuffer bitstream_buffer(
-      bitstream_buffer_id, std::move(dup_region), image_file->data_str.size());
-
-  decoder_->Decode(std::move(bitstream_buffer),
-                   use_dmabuf_ ? hw_out_dmabuf_frame_ : hw_out_frame_);
+  if (use_dmabuf_) {
+    base::ScopedFD duped_in_dmabuf_fd(HANDLE_EINTR(dup(in_dmabuf_fd_.get())));
+    ASSERT_TRUE(duped_in_dmabuf_fd.is_valid());
+    decoder_->Decode(task_id, std::move(duped_in_dmabuf_fd),
+                     image_file->data_str.size(), 0 /* src_offset */,
+                     hw_out_dmabuf_frame_);
+  } else {
+    base::subtle::PlatformSharedMemoryRegion dup_region =
+        base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
+            in_shm_.Duplicate());
+    ASSERT_EQ(dup_region.GetSize(), image_file->data_str.size());
+    media::BitstreamBuffer bitstream_buffer(task_id, std::move(dup_region),
+                                            dup_region.GetSize());
+    decoder_->Decode(std::move(bitstream_buffer), hw_out_frame_);
+  }
 }
 
-bool JpegClient::GetSoftwareDecodeResult(int32_t bitstream_buffer_id) {
+bool JpegClient::GetSoftwareDecodeResult(int32_t task_id) {
   DCHECK(sw_out_frame_->IsMappable());
   DCHECK_EQ(sw_out_frame_->format(), media::PIXEL_FORMAT_I420);
-  ParsedJpegImage* image_file = test_image_files_[bitstream_buffer_id];
-  if (libyuv::ConvertToI420(static_cast<uint8_t*>(in_shm_mapping_.memory()),
-                            image_file->data_str.size(),
-                            sw_out_frame_->data(media::VideoFrame::kYPlane),
-                            sw_out_frame_->stride(media::VideoFrame::kYPlane),
-                            sw_out_frame_->data(media::VideoFrame::kUPlane),
-                            sw_out_frame_->stride(media::VideoFrame::kUPlane),
-                            sw_out_frame_->data(media::VideoFrame::kVPlane),
-                            sw_out_frame_->stride(media::VideoFrame::kVPlane),
-                            0, 0, sw_out_frame_->visible_rect().width(),
-                            sw_out_frame_->visible_rect().height(),
-                            sw_out_frame_->visible_rect().width(),
-                            sw_out_frame_->visible_rect().height(),
-                            libyuv::kRotate0, libyuv::FOURCC_MJPG) != 0) {
+  ParsedJpegImage* image_file = test_image_files_[task_id];
+  if (libyuv::ConvertToI420(
+          reinterpret_cast<const uint8_t*>(image_file->data_str.data()),
+          image_file->data_str.size(),
+          sw_out_frame_->data(media::VideoFrame::kYPlane),
+          sw_out_frame_->stride(media::VideoFrame::kYPlane),
+          sw_out_frame_->data(media::VideoFrame::kUPlane),
+          sw_out_frame_->stride(media::VideoFrame::kUPlane),
+          sw_out_frame_->data(media::VideoFrame::kVPlane),
+          sw_out_frame_->stride(media::VideoFrame::kVPlane), 0, 0,
+          sw_out_frame_->visible_rect().width(),
+          sw_out_frame_->visible_rect().height(),
+          sw_out_frame_->visible_rect().width(),
+          sw_out_frame_->visible_rect().height(), libyuv::kRotate0,
+          libyuv::FOURCC_MJPG) != 0) {
     LOG(ERROR) << "Software decode " << image_file->filename() << " failed.";
     return false;
   }
@@ -833,15 +897,14 @@
                                 base::Unretained(scoped_client->client())));
   ASSERT_EQ(scoped_client->client()->note()->Wait(), CS_INITIALIZED);
 
-  const int32_t bitstream_buffer_id = 0;
-  scoped_client->client()->PrepareMemory(bitstream_buffer_id);
+  const int32_t task_id = 0;
+  scoped_client->client()->PrepareMemory(task_id);
   const base::ElapsedTimer timer;
   for (int index = 0; index < decode_times; index++) {
     decoder_thread.task_runner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&JpegClient::StartDecode,
-                       base::Unretained(scoped_client->client()),
-                       bitstream_buffer_id, false /* do_prepare_memory */));
+        FROM_HERE, base::BindOnce(&JpegClient::StartDecode,
+                                  base::Unretained(scoped_client->client()),
+                                  task_id, false /* do_prepare_memory */));
     ASSERT_EQ(scoped_client->client()->note()->Wait(), CS_DECODE_PASS);
   }
   const base::TimeDelta elapsed_time = timer.Elapsed();
@@ -862,11 +925,11 @@
       std::make_unique<media::test::ClientStateNotification<ClientState>>(),
       false /* use_dmabuf */, true /* is_skip */);
 
-  const int32_t bitstream_buffer_id = 0;
-  client->PrepareMemory(bitstream_buffer_id);
+  const int32_t task_id = 0;
+  client->PrepareMemory(task_id);
   const base::ElapsedTimer timer;
   for (int index = 0; index < decode_times; index++)
-    client->GetSoftwareDecodeResult(bitstream_buffer_id);
+    client->GetSoftwareDecodeResult(task_id);
   const base::TimeDelta elapsed_time = timer.Elapsed();
   LOG(INFO) << elapsed_time << " for " << decode_times
             << " iterations (avg: " << elapsed_time / decode_times << ") -- "
diff --git a/components/chromeos_camera/mojo_mjpeg_decode_accelerator.cc b/components/chromeos_camera/mojo_mjpeg_decode_accelerator.cc
index 2265332..39af013f 100644
--- a/components/chromeos_camera/mojo_mjpeg_decode_accelerator.cc
+++ b/components/chromeos_camera/mojo_mjpeg_decode_accelerator.cc
@@ -76,6 +76,15 @@
                                    base::Unretained(this)));
 }
 
+void MojoMjpegDecodeAccelerator::Decode(
+    int32_t task_id,
+    base::ScopedFD src_dmabuf_fd,
+    size_t src_size,
+    off_t src_offset,
+    scoped_refptr<media::VideoFrame> dst_frame) {
+  NOTIMPLEMENTED();
+}
+
 bool MojoMjpegDecodeAccelerator::IsSupported() {
   return true;
 }
@@ -116,7 +125,7 @@
 void MojoMjpegDecodeAccelerator::OnLostConnectionToJpegDecoder() {
   DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
   OnDecodeAck(
-      kInvalidBitstreamBufferId,
+      kInvalidTaskId,
       ::chromeos_camera::MjpegDecodeAccelerator::Error::PLATFORM_FAILURE);
 }
 
diff --git a/components/chromeos_camera/mojo_mjpeg_decode_accelerator.h b/components/chromeos_camera/mojo_mjpeg_decode_accelerator.h
index 1b57915..51b68e2 100644
--- a/components/chromeos_camera/mojo_mjpeg_decode_accelerator.h
+++ b/components/chromeos_camera/mojo_mjpeg_decode_accelerator.h
@@ -36,6 +36,11 @@
   void InitializeAsync(Client* client, InitCB init_cb) override;
   void Decode(media::BitstreamBuffer bitstream_buffer,
               scoped_refptr<media::VideoFrame> video_frame) override;
+  void Decode(int32_t task_id,
+              base::ScopedFD src_dmabuf_fd,
+              size_t src_size,
+              off_t src_offset,
+              scoped_refptr<media::VideoFrame> dst_frame) override;
   bool IsSupported() override;
 
  private:
diff --git a/components/dom_distiller/DEPS b/components/dom_distiller/DEPS
index ea653ead..9e2dcd6 100644
--- a/components/dom_distiller/DEPS
+++ b/components/dom_distiller/DEPS
@@ -8,6 +8,7 @@
   "+components/sync/protocol",
   "+components/sync_preferences",
   "+components/variations",
+  "+crypto", # For sha256
   "+google", # For third_party/protobuf.
   "+third_party/dom_distiller_js",
   "+third_party/re2",
diff --git a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index 855ff791..21a0178 100644
--- a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -55,8 +55,7 @@
       public content::WebContentsObserver {
  public:
   RequestViewerHandle(content::WebContents* web_contents,
-                      const std::string& expected_scheme,
-                      const std::string& expected_request_path,
+                      const GURL& expected_url,
                       DistilledPagePrefs* distilled_page_prefs,
                       DistillerUIHandle* ui_handle);
   ~RequestViewerHandle() override;
@@ -83,11 +82,8 @@
   // cancelled.
   void Cancel();
 
-  // The scheme hosting the current view request;
-  std::string expected_scheme_;
-
-  // The query path for the current view request.
-  std::string expected_request_path_;
+  // The URL hosting the current view request;
+  const GURL expected_url_;
 
   // Whether the page is sufficiently initialized to handle updates from the
   // distiller.
@@ -108,13 +104,11 @@
 
 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
     content::WebContents* web_contents,
-    const std::string& expected_scheme,
-    const std::string& expected_request_path,
+    const GURL& expected_url,
     DistilledPagePrefs* distilled_page_prefs,
     DistillerUIHandle* ui_handle)
     : DomDistillerRequestViewBase(distilled_page_prefs),
-      expected_scheme_(expected_scheme),
-      expected_request_path_(expected_request_path),
+      expected_url_(expected_url),
       waiting_for_page_ready_(true),
       distiller_ui_handle_(ui_handle) {
   content::WebContentsObserver::Observe(web_contents);
@@ -146,9 +140,7 @@
     return;
 
   const GURL& navigation = navigation_handle->GetURL();
-  bool expected_main_view_request =
-      navigation.SchemeIs(expected_scheme_) &&
-      expected_request_path_ == navigation.query();
+  bool expected_main_view_request = navigation == expected_url_;
   if (navigation_handle->IsSameDocument() || expected_main_view_request) {
     // In-page navigations, as well as the main view request can be ignored.
     if (expected_main_view_request) {
@@ -260,21 +252,29 @@
     }
   }
 
-  // An empty |path| is invalid, but guard against it. If not empty, assume
-  // |path| starts with '?', which is stripped away.
-  const std::string path_after_query_separator =
-      path.size() > 0 ? path.substr(1) : "";
+  // We need the host part to validate the parameter, but it's not available
+  // from |URLDataSource|. |web_contents| is the most convenient place to
+  // obtain the full URL.
+  // TODO(crbug.com/991888): pass GURL in URLDataSource::StartDataRequest().
+  const std::string query = GURL("https://host/" + path).query();
+  GURL request_url = web_contents->GetVisibleURL();
+  // The query should match what's seen in |web_contents|.
+  // For javascript:window.open(), it's not the case, but it's not a supported
+  // use case.
+  if (request_url.query() != query || request_url.path() != "/") {
+    request_url = GURL();
+  }
   RequestViewerHandle* request_viewer_handle =
-      new RequestViewerHandle(web_contents, scheme_, path_after_query_separator,
+      new RequestViewerHandle(web_contents, request_url,
                               dom_distiller_service_->GetDistilledPagePrefs(),
                               distiller_ui_handle_.get());
   std::unique_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
-      dom_distiller_service_, path, request_viewer_handle,
+      dom_distiller_service_, request_url, request_viewer_handle,
       web_contents->GetContainerBounds().size());
 
-  GURL current_url(url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey));
+  GURL current_url(url_utils::GetOriginalUrlFromDistillerUrl(request_url));
   std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml(
-      url_utils::GetOriginalUrlFromDistillerUrl(current_url).spec(),
+      current_url.spec(),
       dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(),
       dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily());
 
diff --git a/components/dom_distiller/core/url_utils.cc b/components/dom_distiller/core/url_utils.cc
index cac08dd..cd7fc39bf 100644
--- a/components/dom_distiller/core/url_utils.cc
+++ b/components/dom_distiller/core/url_utils.cc
@@ -8,11 +8,14 @@
 
 #include "base/guid.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/grit/components_resources.h"
+#include "crypto/sha2.h"
 #include "net/base/url_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "url/gurl.h"
+#include "url/url_util.h"
 
 namespace dom_distiller {
 
@@ -21,6 +24,12 @@
 namespace {
 
 const char kDummyInternalUrlPrefix[] = "chrome-distiller-internal://dummy/";
+const char kSeparator[] = "_";
+
+std::string SHA256InHex(base::StringPiece str) {
+  std::string sha256 = crypto::SHA256HashString(str);
+  return base::ToLowerASCII(base::HexEncode(sha256.c_str(), sha256.size()));
+}
 
 }  // namespace
 
@@ -31,28 +40,44 @@
 }
 
 const GURL GetDistillerViewUrlFromUrl(const std::string& scheme,
-                                      const GURL& view_url,
+                                      const GURL& url,
                                       int64_t start_time_ms) {
-  GURL url(scheme + "://" + base::GenerateGUID());
+  GURL view_url(scheme + "://" + base::GenerateGUID() + kSeparator +
+                SHA256InHex(url.spec()));
   if (start_time_ms > 0) {
-    url = net::AppendOrReplaceQueryParameter(
-        url, kTimeKey, base::NumberToString(start_time_ms));
+    view_url = net::AppendOrReplaceQueryParameter(
+        view_url, kTimeKey, base::NumberToString(start_time_ms));
   }
-  return net::AppendOrReplaceQueryParameter(url, kUrlKey, view_url.spec());
+  return net::AppendOrReplaceQueryParameter(view_url, kUrlKey, url.spec());
 }
 
 const GURL GetOriginalUrlFromDistillerUrl(const GURL& url) {
-  if (!dom_distiller::url_utils::IsDistilledPage(url))
+  if (!IsDistilledPage(url))
     return url;
 
   std::string original_url_str;
   net::GetValueForKeyInQuery(url, kUrlKey, &original_url_str);
 
-  return GURL(original_url_str);
+  // Make sure kDomDistillerScheme is considered standard scheme for
+  // |GURL::host_piece()| to work correctly.
+  DCHECK(url::IsStandard(kDomDistillerScheme,
+                         url::Component(0, strlen(kDomDistillerScheme))));
+  std::vector<base::StringPiece> pieces =
+      base::SplitStringPiece(url.host_piece(), kSeparator,
+                             base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  if (pieces.size() != 2)
+    return GURL();
+  if (SHA256InHex(original_url_str) != pieces[1])
+    return GURL();
+  const GURL original_url(original_url_str);
+  if (!IsUrlDistillable(original_url))
+    return GURL();
+
+  return original_url;
 }
 
 int64_t GetTimeFromDistillerUrl(const GURL& url) {
-  if (!dom_distiller::url_utils::IsDistilledPage(url))
+  if (!IsDistilledPage(url))
     return 0;
 
   std::string time_str;
diff --git a/components/dom_distiller/core/url_utils.h b/components/dom_distiller/core/url_utils.h
index d0beeb8..8f94a56 100644
--- a/components/dom_distiller/core/url_utils.h
+++ b/components/dom_distiller/core/url_utils.h
@@ -25,7 +25,9 @@
                                       int64_t start_time_ms = 0);
 
 // Returns the original URL from the distilled URL.
-// If the URL is not distilled, it is returned as is.
+// If |distilled_url| is not distilled, it is returned as is.
+// If |distilled_url| looks like distilled, but no original URL can be found,
+// an empty, invalid URL is returned.
 const GURL GetOriginalUrlFromDistillerUrl(const GURL& distilled_url);
 
 // Returns the starting time from the distilled URL.
diff --git a/components/dom_distiller/core/url_utils_unittest.cc b/components/dom_distiller/core/url_utils_unittest.cc
index ed10e23b..5dd2100 100644
--- a/components/dom_distiller/core/url_utils_unittest.cc
+++ b/components/dom_distiller/core/url_utils_unittest.cc
@@ -5,8 +5,10 @@
 #include "components/dom_distiller/core/url_utils.h"
 
 #include "components/dom_distiller/core/url_constants.h"
+#include "net/base/url_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
+#include "url/url_util.h"
 
 namespace dom_distiller {
 
@@ -15,9 +17,12 @@
 TEST(DomDistillerUrlUtilsTest, TestPathUtil) {
   const std::string single_key = "mypath?foo=bar";
   EXPECT_EQ("bar", GetValueForKeyInUrlPathQuery(single_key, "foo"));
+
   const std::string two_keys = "mypath?key1=foo&key2=bar";
   EXPECT_EQ("foo", GetValueForKeyInUrlPathQuery(two_keys, "key1"));
   EXPECT_EQ("bar", GetValueForKeyInUrlPathQuery(two_keys, "key2"));
+
+  // First occurrence wins.
   const std::string multiple_same_key = "mypath?key=foo&key=bar";
   EXPECT_EQ("foo", GetValueForKeyInUrlPathQuery(multiple_same_key, "key"));
 }
@@ -41,16 +46,43 @@
   EXPECT_EQ("foo", GetValueForKeyInUrlPathQuery(valid_url_two_keys, "key"));
 }
 
-std::string ThroughDistiller(const std::string& url) {
-  return GetOriginalUrlFromDistillerUrl(
-             GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url), 123))
-      .spec();
+void AssertEqualExceptHost(const GURL& a, const GURL& b) {
+  url::Replacements<char> no_host;
+  no_host.ClearHost();
+  EXPECT_EQ(a.ReplaceComponents(no_host), b.ReplaceComponents(no_host));
+}
+
+TEST(DomDistillerUrlUtilsTest, TestGetDistillerViewUrlFromUrl) {
+  AssertEqualExceptHost(
+      GURL("chrome-distiller://any/"
+           "?time=123&url=http%3A%2F%2Fexample.com%2Fpath%3Fq%3Dabc%26p%3D1%"
+           "23anchor"),
+      GetDistillerViewUrlFromUrl(
+          kDomDistillerScheme, GURL("http://example.com/path?q=abc&p=1#anchor"),
+          123));
 }
 
 std::string GetOriginalUrlFromDistillerUrl(const std::string& url) {
   return GetOriginalUrlFromDistillerUrl(GURL(url)).spec();
 }
 
+TEST(DomDistillerUrlUtilsTest, TestGetOriginalUrlFromDistillerUrl) {
+  EXPECT_EQ(
+      "http://example.com/path?q=abc&p=1#anchor",
+      GetOriginalUrlFromDistillerUrl(
+          "chrome-distiller://"
+          "any_"
+          "d091ebf8f841eae9ca23822c3d0f369c16d3748478d0b74111be176eb96722e5/"
+          "?time=123&url=http%3A%2F%2Fexample.com%2Fpath%3Fq%3Dabc%26p%3D1%"
+          "23anchor"));
+}
+
+std::string ThroughDistiller(const std::string& url) {
+  return GetOriginalUrlFromDistillerUrl(
+             GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url), 123))
+      .spec();
+}
+
 TEST(DomDistillerUrlUtilsTest, TestDistillerEndToEnd) {
   // Tests a normal url.
   const std::string url = "http://example.com/";
@@ -65,8 +97,24 @@
 
   // Tests a url with file:// scheme.
   const std::string url_file = "file:///home/userid/path/index.html";
-  EXPECT_EQ(url_file, ThroughDistiller(url_file));
+  EXPECT_EQ("", ThroughDistiller(url_file));
   EXPECT_EQ(url_file, GetOriginalUrlFromDistillerUrl(url_file));
+
+  // Tests a nested url.
+  const std::string nested_url =
+      GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url)).spec();
+  EXPECT_EQ("", ThroughDistiller(nested_url));
+  EXPECT_EQ(url, GetOriginalUrlFromDistillerUrl(nested_url));
+}
+
+TEST(DomDistillerUrlUtilsTest, TestRejectInvalidURLs) {
+  const std::string url = "http://example.com/";
+  const std::string url2 = "http://example.org/";
+  const GURL view_url =
+      GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url), 123);
+  GURL bad_view_url =
+      net::AppendOrReplaceQueryParameter(view_url, kUrlKey, url2);
+  EXPECT_EQ(GURL(), GetOriginalUrlFromDistillerUrl(bad_view_url));
 }
 }  // namespace url_utils
 
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc
index 6f5739d8a..6fa4702 100644
--- a/components/dom_distiller/core/viewer.cc
+++ b/components/dom_distiller/core/viewer.cc
@@ -250,17 +250,17 @@
 
 std::unique_ptr<ViewerHandle> CreateViewRequest(
     DomDistillerServiceInterface* dom_distiller_service,
-    const std::string& path,
+    const GURL& url,
     ViewRequestDelegate* view_request_delegate,
     const gfx::Size& render_view_size) {
-  std::string entry_id =
-      url_utils::GetValueForKeyInUrlPathQuery(path, kEntryIdKey);
+  if (!url_utils::IsDistilledPage(url)) {
+    return nullptr;
+  }
+  std::string entry_id = url_utils::GetValueForKeyInUrl(url, kEntryIdKey);
   bool has_valid_entry_id = !entry_id.empty();
   entry_id = base::ToUpperASCII(entry_id);
 
-  std::string requested_url_str =
-      url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey);
-  GURL requested_url(requested_url_str);
+  GURL requested_url(url_utils::GetOriginalUrlFromDistillerUrl(url));
   bool has_valid_url = url_utils::IsUrlDistillable(requested_url);
 
   if (has_valid_entry_id && has_valid_url) {
diff --git a/components/dom_distiller/core/viewer.h b/components/dom_distiller/core/viewer.h
index 724e95a..96269dd 100644
--- a/components/dom_distiller/core/viewer.h
+++ b/components/dom_distiller/core/viewer.h
@@ -12,6 +12,7 @@
 #include "base/strings/string16.h"
 #include "components/dom_distiller/core/distilled_page_prefs.h"
 #include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
 
 namespace dom_distiller {
 
@@ -75,7 +76,7 @@
 // viewing distilled content based on the |path|.
 std::unique_ptr<ViewerHandle> CreateViewRequest(
     DomDistillerServiceInterface* dom_distiller_service,
-    const std::string& path,
+    const GURL& url,
     ViewRequestDelegate* view_request_delegate,
     const gfx::Size& render_view_size);
 
diff --git a/components/dom_distiller/core/viewer_unittest.cc b/components/dom_distiller/core/viewer_unittest.cc
index 1e69a43..493daad 100644
--- a/components/dom_distiller/core/viewer_unittest.cc
+++ b/components/dom_distiller/core/viewer_unittest.cc
@@ -9,11 +9,24 @@
 #include "components/dom_distiller/core/dom_distiller_test_util.h"
 #include "components/dom_distiller/core/task_tracker.h"
 #include "components/dom_distiller/core/url_constants.h"
+#include "components/dom_distiller/core/url_utils.h"
+#include "net/base/url_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/url_util.h"
 
 namespace dom_distiller {
 
-const char kTestScheme[] = "myscheme";
+namespace {
+
+const GURL GetDistillerViewUrlFromUrl(const std::string& url) {
+  return url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url));
+}
+
+const GURL GetDistillerViewUrlFromEntryId(const std::string& id) {
+  return url_utils::GetDistillerViewUrlFromEntryId(kDomDistillerScheme, id);
+}
+
+}  // namespace
 
 class FakeViewRequestDelegate : public ViewRequestDelegate {
  public:
@@ -78,10 +91,10 @@
 
  protected:
   std::unique_ptr<ViewerHandle> CreateViewRequest(
-      const std::string& path,
+      const GURL& url,
       ViewRequestDelegate* view_request_delegate) {
-    return viewer::CreateViewRequest(service_.get(), path,
-                                     view_request_delegate, gfx::Size());
+    return viewer::CreateViewRequest(service_.get(), url, view_request_delegate,
+                                     gfx::Size());
   }
 
   std::unique_ptr<TestDomDistillerService> service_;
@@ -94,9 +107,8 @@
   EXPECT_CALL(*service_, ViewUrlImpl())
       .WillOnce(testing::Return(viewer_handle));
   EXPECT_CALL(*service_, ViewEntryImpl()).Times(0);
-  CreateViewRequest(
-      std::string("?") + kUrlKey + "=http%3A%2F%2Fwww.example.com%2F",
-      view_request_delegate.get());
+  CreateViewRequest(GetDistillerViewUrlFromUrl("http://www.example.com/"),
+                    view_request_delegate.get());
 }
 
 TEST_F(DomDistillerViewerTest, TestCreatingViewEntryRequest) {
@@ -106,7 +118,7 @@
   EXPECT_CALL(*service_, ViewEntryImpl())
       .WillOnce(testing::Return(viewer_handle));
   EXPECT_CALL(*service_, ViewUrlImpl()).Times(0);
-  CreateViewRequest(std::string("?") + kEntryIdKey + "=abc-def",
+  CreateViewRequest(GetDistillerViewUrlFromEntryId("abc-def"),
                     view_request_delegate.get());
 }
 
@@ -116,19 +128,24 @@
   EXPECT_CALL(*service_, ViewEntryImpl()).Times(0);
   EXPECT_CALL(*service_, ViewUrlImpl()).Times(0);
   // Specify none of the required query parameters.
-  CreateViewRequest("?foo=bar", view_request_delegate.get());
+  CreateViewRequest(GURL(std::string(kDomDistillerScheme) + "://host?foo=bar"),
+                    view_request_delegate.get());
   // Specify both of the required query parameters.
-  CreateViewRequest("?" + std::string(kUrlKey) +
-                        "=http%3A%2F%2Fwww.example.com%2F&" +
-                        std::string(kEntryIdKey) + "=abc-def",
+  CreateViewRequest(net::AppendOrReplaceQueryParameter(
+                        GetDistillerViewUrlFromUrl("http://www.example.com/"),
+                        kEntryIdKey, "abc-def"),
                     view_request_delegate.get());
   // Specify an internal Chrome page.
-  CreateViewRequest("?" + std::string(kUrlKey) + "=chrome%3A%2F%2Fsettings%2F",
+  CreateViewRequest(GetDistillerViewUrlFromUrl("chrome://settings/"),
                     view_request_delegate.get());
   // Specify a recursive URL.
-  CreateViewRequest("?" + std::string(kUrlKey) + "=" +
-                        std::string(kTestScheme) + "%3A%2F%2Fabc-def%2F",
+  CreateViewRequest(GetDistillerViewUrlFromUrl(
+                        GetDistillerViewUrlFromEntryId("abc-def").spec()),
                     view_request_delegate.get());
+  // Specify a non-distilled URL.
+  CreateViewRequest(GURL("https://example.com"), view_request_delegate.get());
+  // Specify an empty URL.
+  CreateViewRequest(GURL(), view_request_delegate.get());
 }
 
 DistilledPagePrefs* TestDomDistillerService::GetDistilledPagePrefs() {
diff --git a/components/language/content/browser/test_utils.cc b/components/language/content/browser/test_utils.cc
index e922745..4d904d5f 100644
--- a/components/language/content/browser/test_utils.cc
+++ b/components/language/content/browser/test_utils.cc
@@ -6,7 +6,7 @@
 
 namespace language {
 
-MockGeoLocation::MockGeoLocation() : binding_(this) {}
+MockGeoLocation::MockGeoLocation() {}
 MockGeoLocation::~MockGeoLocation() {}
 
 void MockGeoLocation::SetHighAccuracy(bool high_accuracy) {}
@@ -17,8 +17,8 @@
 }
 
 void MockGeoLocation::BindGeoLocation(
-    device::mojom::GeolocationRequest request) {
-  binding_.Bind(std::move(request));
+    mojo::PendingReceiver<device::mojom::Geolocation> receiver) {
+  receiver_.Bind(std::move(receiver));
 }
 
 void MockGeoLocation::MoveToLocation(float latitude, float longitude) {
@@ -28,13 +28,14 @@
 
 MockIpGeoLocationProvider::MockIpGeoLocationProvider(
     MockGeoLocation* mock_geo_location)
-    : mock_geo_location_(mock_geo_location), binding_(this) {}
+    : mock_geo_location_(mock_geo_location) {}
 
 MockIpGeoLocationProvider::~MockIpGeoLocationProvider() {}
 
 void MockIpGeoLocationProvider::Bind(mojo::ScopedMessagePipeHandle handle) {
-  binding_.Bind(device::mojom::PublicIpAddressGeolocationProviderRequest(
-      std::move(handle)));
+  receiver_.Bind(
+      mojo::PendingReceiver<device::mojom::PublicIpAddressGeolocationProvider>(
+          std::move(handle)));
 }
 
 void MockIpGeoLocationProvider::CreateGeolocation(
diff --git a/components/language/content/browser/test_utils.h b/components/language/content/browser/test_utils.h
index 9755c614..7423311 100644
--- a/components/language/content/browser/test_utils.h
+++ b/components/language/content/browser/test_utils.h
@@ -5,7 +5,8 @@
 #ifndef COMPONENTS_LANGUAGE_CONTENT_BROWSER_TEST_UTILS_H_
 #define COMPONENTS_LANGUAGE_CONTENT_BROWSER_TEST_UTILS_H_
 
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/device/public/mojom/constants.mojom.h"
 #include "services/device/public/mojom/geolocation.mojom.h"
 #include "services/device/public/mojom/geoposition.mojom.h"
@@ -26,7 +27,8 @@
   void SetHighAccuracy(bool high_accuracy) override;
   void QueryNextPosition(QueryNextPositionCallback callback) override;
 
-  void BindGeoLocation(device::mojom::GeolocationRequest request);
+  void BindGeoLocation(
+      mojo::PendingReceiver<device::mojom::Geolocation> receiver);
   void MoveToLocation(float latitude, float longitude);
 
   int query_next_position_called_times() const {
@@ -36,7 +38,7 @@
  private:
   int query_next_position_called_times_ = 0;
   device::mojom::Geoposition position_;
-  mojo::Binding<device::mojom::Geolocation> binding_;
+  mojo::Receiver<device::mojom::Geolocation> receiver_{this};
 };
 
 // Mock impl of mojom::PublicIpAddressGeolocationProvider that binds Geolocation
@@ -55,7 +57,8 @@
 
  private:
   MockGeoLocation* mock_geo_location_;
-  mojo::Binding<device::mojom::PublicIpAddressGeolocationProvider> binding_;
+  mojo::Receiver<device::mojom::PublicIpAddressGeolocationProvider> receiver_{
+      this};
 };
 
 }  // namespace language
diff --git a/components/open_from_clipboard/OWNERS b/components/open_from_clipboard/OWNERS
index f566e77..730ca68 100644
--- a/components/open_from_clipboard/OWNERS
+++ b/components/open_from_clipboard/OWNERS
@@ -1 +1,3 @@
-olivierrobin@chromium.org
\ No newline at end of file
+olivierrobin@chromium.org
+# COMPONENT: UI>Browser>Omnibox>ZeroSuggest
+# TEAM: ios-directory-owners@chromium.org
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index ce2b652..d89a682 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -652,7 +652,7 @@
 }  // namespace
 
 LoginDatabase::LoginDatabase(const base::FilePath& db_path,
-                             bool is_account_store)
+                             IsAccountStore is_account_store)
     : db_path_(db_path), is_account_store_(is_account_store) {}
 
 LoginDatabase::~LoginDatabase() {
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h
index 89a21946..dba2f87 100644
--- a/components/password_manager/core/browser/login_database.h
+++ b/components/password_manager/core/browser/login_database.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/pickle.h"
 #include "base/strings/string16.h"
+#include "base/util/type_safety/strong_alias.h"
 #include "build/build_config.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_change.h"
@@ -40,12 +41,14 @@
 extern const int kCurrentVersionNumber;
 extern const int kCompatibleVersionNumber;
 
+using IsAccountStore = util::StrongAlias<class IsAccountStoreTag, bool>;
+
 // Interface to the database storage of login information, intended as a helper
 // for PasswordStore on platforms that need internal storage of some or all of
 // the login information.
 class LoginDatabase : public PasswordStoreSync::MetadataStore {
  public:
-  LoginDatabase(const base::FilePath& db_path, bool is_account_store);
+  LoginDatabase(const base::FilePath& db_path, IsAccountStore is_account_store);
   ~LoginDatabase() override;
 
   // Returns whether this is the profile-scoped or the account-scoped storage:
@@ -53,7 +56,7 @@
   //        syncing users.
   // false: Profile-scoped store, which is used for local storage and for
   //        syncing users.
-  bool is_account_store() const { return is_account_store_; }
+  bool is_account_store() const { return is_account_store_.value(); }
 
   // Actually creates/opens the database. If false is returned, no other method
   // should be called.
@@ -310,7 +313,7 @@
   bool IsUsingCleanupMechanism() const;
 
   const base::FilePath db_path_;
-  const bool is_account_store_;
+  const IsAccountStore is_account_store_;
 
   mutable sql::Database db_;
   sql::MetaTable meta_table_;
diff --git a/components/password_manager/core/browser/login_database_ios_unittest.cc b/components/password_manager/core/browser/login_database_ios_unittest.cc
index 9478112..a59e5b5 100644
--- a/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -30,7 +30,7 @@
     base::FilePath login_db_path =
         temp_dir_.GetPath().AppendASCII("temp_login.db");
     login_db_.reset(new password_manager::LoginDatabase(
-        login_db_path, /*is_account_store=*/false));
+        login_db_path, password_manager::IsAccountStore(false)));
     login_db_->Init();
   }
 
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index a18a10e..2f6decd8 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -187,7 +187,7 @@
     file_ = temp_dir_.GetPath().AppendASCII("TestMetadataStoreMacDatabase");
     OSCryptMocker::SetUp();
 
-    db_.reset(new LoginDatabase(file_, /*is_account_store=*/false));
+    db_.reset(new LoginDatabase(file_, IsAccountStore(false)));
     ASSERT_TRUE(db_->Init());
   }
 
@@ -1797,7 +1797,7 @@
   GenerateExamplePasswordForm(&password_form);
   base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
   {
-    LoginDatabase db(file, /*is_account_store=*/false);
+    LoginDatabase db(file, IsAccountStore(false));
     ASSERT_TRUE(db.Init());
     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
   }
@@ -1818,7 +1818,7 @@
   GenerateExamplePasswordForm(&password_form);
   base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
   {
-    LoginDatabase db(file, /*is_account_store=*/false);
+    LoginDatabase db(file, IsAccountStore(false));
     db.disable_encryption();
     ASSERT_TRUE(db.Init());
     EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
@@ -1841,7 +1841,7 @@
 
   base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
   {
-    LoginDatabase db(file, /*is_account_store=*/false);
+    LoginDatabase db(file, IsAccountStore(false));
     ASSERT_TRUE(db.Init());
     // Add obfuscated (new) entries.
     PasswordForm password_form;
@@ -1862,7 +1862,7 @@
 
   std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
   {
-    LoginDatabase db(file, /*is_account_store=*/false);
+    LoginDatabase db(file, IsAccountStore(false));
     ASSERT_TRUE(db.Init());
     ASSERT_TRUE(db.GetAutofillableLogins(&forms));
   }
@@ -1900,7 +1900,7 @@
 
   // Now try to init the database with the file. The test succeeds if it does
   // not crash.
-  LoginDatabase db(database_path, /*is_account_store=*/false);
+  LoginDatabase db(database_path, IsAccountStore(false));
   EXPECT_FALSE(db.Init());
 }
 
@@ -1975,7 +1975,7 @@
   {
     // Assert that the database was successfully opened and updated
     // to current version.
-    LoginDatabase db(database_path_, /*is_account_store=*/false);
+    LoginDatabase db(database_path_, IsAccountStore(false));
     ASSERT_TRUE(db.Init());
 
     // Check that the contents was preserved.
@@ -2125,7 +2125,7 @@
   form.signon_realm = origin.GetOrigin().spec();
 
   {
-    LoginDatabase db(database_path(), /*is_account_store=*/false);
+    LoginDatabase db(database_path(), IsAccountStore(false));
     EXPECT_TRUE(db.Init());
     EXPECT_EQ(db.AddLogin(form), AddChangeForForm(form));
   }
@@ -2162,7 +2162,7 @@
   auto form2 = AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
   auto form3 = AddDummyLogin("foo3", GURL("https://foo3.com/"), false);
 
-  LoginDatabase db(database_path(), /*is_account_store=*/false);
+  LoginDatabase db(database_path(), IsAccountStore(false));
   base::HistogramTester histogram_tester;
   ASSERT_TRUE(db.Init());
 
@@ -2215,7 +2215,7 @@
   auto form2 = AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
   auto form3 = AddDummyLogin("foo3", GURL("https://foo3.com/"), false);
 
-  LoginDatabase db(database_path(), /*is_account_store=*/false);
+  LoginDatabase db(database_path(), IsAccountStore(false));
   ASSERT_TRUE(db.Init());
 
   testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery,
@@ -2248,7 +2248,7 @@
   AddDummyLogin("foo1", GURL("https://foo1.com/"), false);
   AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
 
-  LoginDatabase db(database_path(), /*is_account_store=*/false);
+  LoginDatabase db(database_path(), IsAccountStore(false));
   ASSERT_TRUE(db.Init());
 
   testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery,
@@ -2283,7 +2283,7 @@
 
   OSCryptMocker::SetBackendLocked(true);
 
-  LoginDatabase db(database_path(), /*is_account_store=*/false);
+  LoginDatabase db(database_path(), IsAccountStore(false));
   ASSERT_TRUE(db.Init());
 
   testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery,
@@ -2319,7 +2319,7 @@
   AddDummyLogin("foo2", GURL("https://foo2.com/"), true);
 
   OSCryptMocker::SetBackendLocked(true);
-  LoginDatabase db(database_path(), /*is_account_store=*/false);
+  LoginDatabase db(database_path(), IsAccountStore(false));
   base::HistogramTester histogram_tester;
   ASSERT_TRUE(db.Init());
   EXPECT_EQ(DatabaseCleanupResult::kEncryptionUnavailable,
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.cc b/components/password_manager/core/browser/password_form_metrics_recorder.cc
index ac25134..a40e214 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -267,6 +267,15 @@
     }
   }
 
+  if (user_typed_password_on_chrome_sign_in_page_ ||
+      password_hash_saved_on_chrome_sing_in_page_) {
+    auto value = password_hash_saved_on_chrome_sing_in_page_
+                     ? ChromeSignInPageHashSaved::kHashSaved
+                     : ChromeSignInPageHashSaved::kPasswordTypedHashNotSaved;
+    UMA_HISTOGRAM_ENUMERATION("PasswordManager.ChromeSignInPageHashSaved",
+                              value);
+  }
+
   ukm_entry_builder_.Record(ukm::UkmRecorder::Get());
 }
 
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.h b/components/password_manager/core/browser/password_form_metrics_recorder.h
index 1bb1c46..4608e74 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -260,6 +260,13 @@
     kMaxValue = kNoSavedCredentialsAndBlacklistedBySmartBubble,
   };
 
+  // Records whether a password hash was saved or not on Chrome sign-in page.
+  enum class ChromeSignInPageHashSaved {
+    kPasswordTypedHashNotSaved = 0,
+    kHashSaved = 1,
+    kMaxValue = kHashSaved,
+  };
+
   // The maximum number of combinations of the ManagerAction, UserAction and
   // SubmitResult enums.
   // This is used when recording the actions taken by the form in UMA.
@@ -386,6 +393,14 @@
       bool is_blacklisted,
       const std::vector<InteractionsStats>& interactions_stats);
 
+  void set_user_typed_password_on_chrome_sign_in_page() {
+    user_typed_password_on_chrome_sign_in_page_ = true;
+  }
+
+  void set_password_hash_saved_on_chrome_sing_in_page() {
+    password_hash_saved_on_chrome_sing_in_page_ = true;
+  }
+
  private:
   friend class base::RefCounted<PasswordFormMetricsRecorder>;
 
@@ -469,6 +484,9 @@
 
   bool recorded_wait_for_username_reason_ = false;
 
+  bool user_typed_password_on_chrome_sign_in_page_ = false;
+  bool password_hash_saved_on_chrome_sing_in_page_ = false;
+
   base::Optional<FillingAssistance> filling_assistance_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordFormMetricsRecorder);
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 9e183f8..e4a3bb09 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -324,7 +324,7 @@
     PasswordFormManagerInterface* manager = GetSubmittedManager();
     if (manager && manager->GetSubmittedForm()
                        ->form_data.is_gaia_with_skip_save_password_form) {
-      MaybeSavePasswordHash(*manager);
+      MaybeSavePasswordHash(manager);
     }
   }
 
@@ -429,17 +429,21 @@
 void PasswordManager::ShowManualFallbackForSaving(
     password_manager::PasswordManagerDriver* driver,
     const PasswordForm& password_form) {
+  PasswordFormManager* manager =
+      ProvisionallySaveForm(password_form.form_data, driver, true);
+
+  if (manager && password_form.form_data.is_gaia_with_skip_save_password_form) {
+    manager->GetMetricsRecorder()
+        ->set_user_typed_password_on_chrome_sign_in_page();
+  }
+
   if (!client_->GetPasswordStore()->IsAbleToSavePasswords() ||
       !client_->IsSavingAndFillingEnabled(password_form.origin) ||
       ShouldBlockPasswordForSameOriginButDifferentScheme(
           password_form.origin) ||
-      !client_->GetStoreResultFilter()->ShouldSave(password_form))
+      !client_->GetStoreResultFilter()->ShouldSave(password_form)) {
     return;
-
-  std::unique_ptr<PasswordFormManagerInterface> manager;
-  PasswordFormManager* matched_manager =
-      ProvisionallySaveForm(password_form.form_data, driver, true);
-  manager = matched_manager ? matched_manager->Clone() : nullptr;
+  }
 
   auto availability =
       manager ? PasswordManagerMetricsRecorder::FormManagerAvailable::kSuccess
@@ -456,7 +460,7 @@
     bool is_update = manager->IsPasswordUpdate();
     manager->GetMetricsRecorder()->RecordShowManualFallbackForSaving(
         has_generated_password, is_update);
-    client_->ShowManualFallbackForSaving(std::move(manager),
+    client_->ShowManualFallbackForSaving(manager->Clone(),
                                          has_generated_password, is_update);
   } else {
     HideManualFallbackForSaving();
@@ -847,7 +851,7 @@
   if (!able_to_save_passwords)
     return;
 
-  MaybeSavePasswordHash(*submitted_manager);
+  MaybeSavePasswordHash(submitted_manager);
 
   // TODO(https://crbug.com/831123): Implement checking whether to save with
   // PasswordFormManager.
@@ -904,13 +908,13 @@
 }
 
 void PasswordManager::MaybeSavePasswordHash(
-    const PasswordFormManagerInterface& submitted_manager) {
+    PasswordFormManagerInterface* submitted_manager) {
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+  const PasswordForm* submitted_form = submitted_manager->GetSubmittedForm();
   // When |username_value| is empty, it's not clear whether the submitted
   // credentials are really Gaia or enterprise credentials. Don't save
   // password hash in that case.
-  std::string username =
-      base::UTF16ToUTF8(submitted_manager.GetSubmittedForm()->username_value);
+  std::string username = base::UTF16ToUTF8(submitted_form->username_value);
   if (username.empty())
     return;
 
@@ -919,18 +923,21 @@
   if (!store)
     return;
 
-  const PasswordForm* password_form = submitted_manager.GetSubmittedForm();
-
   bool should_save_enterprise_pw =
       client_->GetStoreResultFilter()->ShouldSaveEnterprisePasswordHash(
-          *password_form);
+          *submitted_form);
   bool should_save_gaia_pw =
       client_->GetStoreResultFilter()->ShouldSaveGaiaPasswordHash(
-          *password_form);
+          *submitted_form);
 
   if (!should_save_enterprise_pw && !should_save_gaia_pw)
     return;
 
+  if (submitted_form->form_data.is_gaia_with_skip_save_password_form) {
+    submitted_manager->GetMetricsRecorder()
+        ->set_password_hash_saved_on_chrome_sing_in_page();
+  }
+
   if (password_manager_util::IsLoggingActive(client_)) {
     BrowserSavePasswordProgressLogger logger(client_->GetLogManager());
     logger.LogMessage(Logger::STRING_SAVE_PASSWORD_HASH);
@@ -939,10 +946,10 @@
   // Canonicalizes username if it is an email.
   if (username.find('@') != std::string::npos)
     username = gaia::CanonicalizeEmail(username);
-  bool is_password_change = !password_form->new_password_element.empty();
+  bool is_password_change = !submitted_form->new_password_element.empty();
   const base::string16 password = is_password_change
-                                      ? password_form->new_password_value
-                                      : password_form->password_value;
+                                      ? submitted_form->new_password_value
+                                      : submitted_form->password_value;
 
   if (should_save_enterprise_pw) {
     store->SaveEnterprisePasswordHash(username, password);
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index d2dd8b5..882d9c6 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -245,8 +245,7 @@
 
   // Helper function called inside OnLoginSuccessful() to save password hash
   // data from |submitted_manager| for password reuse detection purpose.
-  void MaybeSavePasswordHash(
-      const PasswordFormManagerInterface& submitted_manager);
+  void MaybeSavePasswordHash(PasswordFormManagerInterface* submitted_manager);
 
   // Checks for every form in |forms| whether |pending_login_managers_| already
   // contain a manager for that form. If not, adds a manager for each such form.
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc
index 9e986f4..040adb4e 100644
--- a/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -51,8 +51,7 @@
 // A mock LoginDatabase that simulates a failing Init() method.
 class BadLoginDatabase : public LoginDatabase {
  public:
-  BadLoginDatabase()
-      : LoginDatabase(base::FilePath(), /*is_account_store=*/false) {}
+  BadLoginDatabase() : LoginDatabase(base::FilePath(), IsAccountStore(false)) {}
   ~BadLoginDatabase() override {}
 
   // LoginDatabase:
@@ -110,7 +109,7 @@
   OSCryptMocker::SetUp();
   SetupTempDir();
   store_ = CreateInitializedStore(std::make_unique<LoginDatabase>(
-      test_login_db_file_path(), /*is_account_store=*/false));
+      test_login_db_file_path(), IsAccountStore(false)));
 }
 
 PasswordStoreDefaultTestDelegate::PasswordStoreDefaultTestDelegate(
diff --git a/components/password_manager/core/browser/password_store_factory_util.cc b/components/password_manager/core/browser/password_store_factory_util.cc
index 77d637ef..76ab074 100644
--- a/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/components/password_manager/core/browser/password_store_factory_util.cc
@@ -90,7 +90,7 @@
   base::FilePath login_db_file_path =
       profile_path.Append(kLoginDataForProfileFileName);
   return std::make_unique<LoginDatabase>(login_db_file_path,
-                                         /*is_account_store=*/false);
+                                         IsAccountStore(false));
 }
 
 std::unique_ptr<LoginDatabase> CreateLoginDatabaseForAccountStorage(
@@ -98,7 +98,7 @@
   base::FilePath login_db_file_path =
       profile_path.Append(kLoginDataForAccountFileName);
   return std::make_unique<LoginDatabase>(login_db_file_path,
-                                         /*is_account_store=*/true);
+                                         IsAccountStore(true));
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 79535e8..55b1a61 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -130,7 +130,7 @@
 
   scoped_refptr<PasswordStoreDefault> CreatePasswordStore() {
     return new PasswordStoreDefault(std::make_unique<LoginDatabase>(
-        test_login_db_file_path(), /*is_account_store=*/false));
+        test_login_db_file_path(), password_manager::IsAccountStore(false)));
   }
 
  private:
diff --git a/components/plugins/renderer/DEPS b/components/plugins/renderer/DEPS
index 9e68e68f..5ee90b7 100644
--- a/components/plugins/renderer/DEPS
+++ b/components/plugins/renderer/DEPS
@@ -6,6 +6,7 @@
   "+content/public/renderer",
   "+content/public/common",
   "+content/public/test",
+  "+mojo/public/cpp/bindings",
   "+services/service_manager/public/cpp",
   "+third_party/blink/public",
   "+third_party/re2",
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 06a3da6e..b632d29 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -18,6 +18,7 @@
 #include "content/public/common/web_preferences.h"
 #include "content/public/renderer/render_view.h"
 #include "gin/converter.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
@@ -262,10 +263,12 @@
   // ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
   // consistent view of our preferences.
   content::RenderView::ApplyWebPreferences(preferences, web_view_);
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker;
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker;
   WebLocalFrame* web_frame = WebLocalFrame::CreateMainFrame(
       web_view_, this, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
+      document_interface_broker.InitWithNewPipeAndPassReceiver().PassPipe(),
+      nullptr);
   // The created WebFrameWidget is owned by the |web_frame|.
   WebFrameWidget::CreateForMainFrame(this, web_frame);
 
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 4ab51f37..819c0c6d 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -33,6 +33,7 @@
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/render_view.h"
 #include "mojo/public/cpp/base/shared_memory_utils.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/escape.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "printing/buildflags/buildflags.h"
@@ -691,10 +692,12 @@
   };
 
   HeaderAndFooterClient frame_client;
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker;
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker;
   blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame(
       web_view, &frame_client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
+      document_interface_broker.InitWithNewPipeAndPassReceiver().PassPipe(),
+      nullptr);
 
   blink::WebWidgetClient web_widget_client;
   blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, frame);
@@ -928,10 +931,12 @@
       /*compositing_enabled=*/false,
       /*opener=*/nullptr);
   content::RenderView::ApplyWebPreferences(prefs, web_view);
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker;
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker;
   blink::WebLocalFrame* main_frame = blink::WebLocalFrame::CreateMainFrame(
       web_view, this, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
+      document_interface_broker.InitWithNewPipeAndPassReceiver().PassPipe(),
+      nullptr);
   frame_.Reset(main_frame);
   blink::WebFrameWidget::CreateForMainFrame(this, main_frame);
   node_to_print_.Reset();
diff --git a/components/safe_browsing/browser/safe_browsing_network_context.cc b/components/safe_browsing/browser/safe_browsing_network_context.cc
index 0b2ac17..713f202 100644
--- a/components/safe_browsing/browser/safe_browsing_network_context.cc
+++ b/components/safe_browsing/browser/safe_browsing_network_context.cc
@@ -15,7 +15,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_context_client_base.h"
 #include "content/public/browser/network_service_instance.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/net_buildflags.h"
 #include "services/network/network_context.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -44,12 +45,11 @@
       content::GetNetworkService()->CreateNetworkContext(
           MakeRequest(&network_context_), CreateNetworkContextParams());
 
-      network::mojom::NetworkContextClientPtr client_ptr;
-      auto client_request = mojo::MakeRequest(&client_ptr);
-      mojo::MakeStrongBinding(
+      mojo::PendingRemote<network::mojom::NetworkContextClient> client_remote;
+      mojo::MakeSelfOwnedReceiver(
           std::make_unique<content::NetworkContextClientBase>(),
-          std::move(client_request));
-      network_context_->SetClient(std::move(client_ptr));
+          client_remote.InitWithNewPipeAndPassReceiver());
+      network_context_->SetClient(std::move(client_remote));
     }
     return network_context_.get();
   }
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
index 7b6c3b8e..46b5457 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
@@ -34,28 +34,6 @@
 const char kAccountIdPrefix[] = "AccountId-";
 const size_t kAccountIdPrefixLength = 10;
 
-// Used to record token state transitions in histograms.
-// Do not change existing values, new values can only be added at the end.
-enum class TokenStateTransition {
-  // Update events.
-  kNoneToInvalid = 0,
-  kNoneToRegular,
-  kInvalidToRegular,
-  kRegularToInvalid,
-  kRegularToRegular,
-
-  // Revocation events.
-  kInvalidToNone,
-  kRegularToNone,
-
-  // Load events.
-  kLoadRegular,
-  kLoadInvalid,
-  kLoadInvalidNoTokenForPrimaryAccount,
-
-  kCount
-};
-
 // Enum for the Signin.LoadTokenFromDB histogram.
 // Do not modify, or add or delete other than directly before
 // NUM_LOAD_TOKEN_FROM_DB_STATUS.
@@ -88,14 +66,6 @@
   kMaxValue = kRequestSucceeded
 };
 
-// Adds a sample to the TokenStateTransition histogram. Encapsuled in a function
-// to reduce executable size, because histogram macros may generate a lot of
-// code.
-void RecordTokenStateTransition(TokenStateTransition transition) {
-  UMA_HISTOGRAM_ENUMERATION("Signin.TokenStateTransition", transition,
-                            TokenStateTransition::kCount);
-}
-
 // Adds a sample to the TokenRevocationRequestProgress histogram. Encapsuled in
 // a function to reduce executable size, because histogram macros may generate a
 // lot of code.
@@ -105,42 +75,6 @@
                             event);
 }
 
-// Record metrics when a token was updated.
-void RecordTokenChanged(const std::string& existing_token,
-                        const std::string& new_token) {
-  DCHECK_NE(existing_token, new_token);
-  DCHECK(!new_token.empty());
-  TokenStateTransition transition = TokenStateTransition::kCount;
-  if (existing_token.empty()) {
-    transition = (new_token == GaiaConstants::kInvalidRefreshToken)
-                     ? TokenStateTransition::kNoneToInvalid
-                     : TokenStateTransition::kNoneToRegular;
-  } else if (existing_token == GaiaConstants::kInvalidRefreshToken) {
-    transition = TokenStateTransition::kInvalidToRegular;
-  } else {
-    // Existing token is a regular token.
-    transition = (new_token == GaiaConstants::kInvalidRefreshToken)
-                     ? TokenStateTransition::kRegularToInvalid
-                     : TokenStateTransition::kRegularToRegular;
-  }
-  DCHECK_NE(TokenStateTransition::kCount, transition);
-  RecordTokenStateTransition(transition);
-}
-
-// Record metrics when a token was loaded.
-void RecordTokenLoaded(const std::string& token) {
-  RecordTokenStateTransition((token == GaiaConstants::kInvalidRefreshToken)
-                                 ? TokenStateTransition::kLoadInvalid
-                                 : TokenStateTransition::kLoadRegular);
-}
-
-// Record metrics when a token was revoked.
-void RecordTokenRevoked(const std::string& token) {
-  RecordTokenStateTransition((token == GaiaConstants::kInvalidRefreshToken)
-                                 ? TokenStateTransition::kInvalidToNone
-                                 : TokenStateTransition::kRegularToNone);
-}
-
 std::string ApplyAccountIdPrefix(const std::string& account_id) {
   return kAccountIdPrefix + account_id;
 }
@@ -179,35 +113,15 @@
 // Returns whether the token service should be migrated to Dice.
 // Migration can happen if the following conditions are met:
 // - Token service Dice migration is not already done,
-// - AccountTrackerService migration is done,
-// - All accounts in the AccountTrackerService are valid,
 // - Account consistency is DiceMigration or greater.
 // TODO(droger): Remove this code once Dice is fully enabled.
 bool ShouldMigrateToDice(signin::AccountConsistencyMethod account_consistency,
-                         PrefService* prefs,
-                         AccountTrackerService* account_tracker,
-                         const std::map<std::string, std::string>& db_tokens) {
-  AccountTrackerService::AccountIdMigrationState migration_state =
-      account_tracker->GetMigrationState();
-  if ((account_consistency == signin::AccountConsistencyMethod::kMirror) ||
-      !signin::DiceMethodGreaterOrEqual(
-          account_consistency,
-          signin::AccountConsistencyMethod::kDiceMigration) ||
-      (migration_state != AccountTrackerService::MIGRATION_DONE) ||
-      prefs->GetBoolean(prefs::kTokenServiceDiceCompatible)) {
-    return false;
-  }
-
-  // Do not migrate if some accounts are not valid.
-  for (auto iter = db_tokens.begin(); iter != db_tokens.end(); ++iter) {
-    const std::string& prefixed_account_id = iter->first;
-    CoreAccountId account_id = RemoveAccountIdPrefix(prefixed_account_id);
-    AccountInfo account_info = account_tracker->GetAccountInfo(account_id);
-    if (!account_info.IsValid()) {
-      return false;
-    }
-  }
-  return true;
+                         PrefService* prefs) {
+  return (account_consistency != signin::AccountConsistencyMethod::kMirror) &&
+         signin::DiceMethodGreaterOrEqual(
+             account_consistency,
+             signin::AccountConsistencyMethod::kDiceMigration) &&
+         !prefs->GetBoolean(prefs::kTokenServiceDiceCompatible);
 }
 
 }  // namespace
@@ -580,8 +494,6 @@
                      GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
                          GoogleServiceAuthError::InvalidGaiaCredentialsReason::
                              CREDENTIALS_MISSING));
-    RecordTokenStateTransition(
-        TokenStateTransition::kLoadInvalidNoTokenForPrimaryAccount);
     FireRefreshTokenAvailable(loading_primary_account_id_);
   }
 
@@ -600,8 +512,7 @@
     const std::map<std::string, std::string>& db_tokens) {
   std::string old_login_token;
   bool migrate_to_dice =
-      ShouldMigrateToDice(account_consistency_, client_->GetPrefs(),
-                          account_tracker_service_, db_tokens);
+      ShouldMigrateToDice(account_consistency_, client_->GetPrefs());
 
   {
     ScopedBatchChange batch(this);
@@ -692,8 +603,16 @@
           // Revoke old hosted domain accounts as part of Dice migration.
           AccountInfo account_info =
               account_tracker_service_->GetAccountInfo(account_id);
-          DCHECK(account_info.IsValid());
-          if (account_info.hosted_domain != kNoHostedDomainFound) {
+          bool is_hosted_domain = false;
+          if (account_info.hosted_domain.empty()) {
+            // The AccountInfo is incomplete. Use a conservative approximation.
+            is_hosted_domain =
+                !client_->IsNonEnterpriseUser(account_info.email);
+          } else {
+            is_hosted_domain =
+                (account_info.hosted_domain != kNoHostedDomainFound);
+          }
+          if (is_hosted_domain) {
             load_account = false;
             load_token_status =
                 LoadTokenFromDBStatus::TOKEN_REVOKED_DICE_MIGRATION;
@@ -716,11 +635,9 @@
             LoadTokenFromDBStatus::NUM_LOAD_TOKEN_FROM_DB_STATUS);
 
         if (load_account) {
-          RecordTokenLoaded(refresh_token);
           UpdateCredentialsInMemory(account_id, refresh_token);
           FireRefreshTokenAvailable(account_id);
         } else {
-          RecordTokenRevoked(refresh_token);
           RevokeCredentialsOnServer(refresh_token);
           ClearPersistedCredentials(account_id);
           FireRefreshTokenRevoked(account_id);
@@ -750,7 +667,6 @@
   const std::string& existing_token = GetRefreshToken(account_id);
   if (existing_token != refresh_token) {
     ScopedBatchChange batch(this);
-    RecordTokenChanged(existing_token, refresh_token);
     UpdateCredentialsInMemory(account_id, refresh_token);
     PersistCredentials(account_id, refresh_token);
     FireRefreshTokenAvailable(account_id);
@@ -945,7 +861,6 @@
     VLOG(1) << "MutablePO2TS::RevokeCredentials for account_id=" << account_id;
     ScopedBatchChange batch(this);
     const std::string& token = refresh_tokens_[account_id].refresh_token;
-    RecordTokenRevoked(token);
     if (revoke_on_server)
       RevokeCredentialsOnServer(token);
     refresh_tokens_.erase(account_id);
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h
index 9c398812..5f0380d 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h
@@ -111,6 +111,8 @@
   FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
                            DelayedRevoke);
   FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+                           DiceMigrationWithMissingHostedDomain);
+  FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
                            DiceMigrationHostedDomainPrimaryAccount);
   FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
                            ShutdownDuringRevoke);
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
index 9b7ac574..dc017b7 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -530,42 +530,53 @@
 // Tests that Dice migration does not happen if an account is invalid. In
 // particular, no hosted domain tokens are revoked.
 TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
-       DiceNoMigrationOnInvalidAccount) {
+       DiceMigrationWithMissingHostedDomain) {
   ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
   InitializeOAuth2ServiceDelegate(
       signin::AccountConsistencyMethod::kDiceMigration);
   oauth2_service_delegate_->RevokeAllCredentials();
 
-  // Add account info to the account tracker.
-  AccountInfo primary_account = CreateTestAccountInfo(
-      "primary_account", true /* is_hosted_domain*/, true /* is_valid*/);
-  AccountInfo secondary_account = CreateTestAccountInfo(
-      "secondary_account", false /* is_hosted_domain*/, false /* is_valid*/);
-  account_tracker_service_.SeedAccountInfo(primary_account);
-  account_tracker_service_.SeedAccountInfo(secondary_account);
+  // Add incomplete accounts info to the account tracker.
+  AccountInfo account_info_consummer;
+  account_info_consummer.account_id = "consummer";
+  account_info_consummer.gaia = "consummer";
+  // gmail.com is known as a non-enterprise domain.
+  account_info_consummer.email = "consummer@gmail.com";
+  account_tracker_service_.SeedAccountInfo(account_info_consummer);
+
+  AccountInfo account_info_enterprise;
+  account_info_enterprise.account_id = "enterprise";
+  account_info_enterprise.gaia = "enterprise";
+  account_info_enterprise.email = "enterprise@email.com";
+  account_tracker_service_.SeedAccountInfo(account_info_enterprise);
 
   ResetObserverCounts();
-  AddAuthTokenManually("AccountId-" + primary_account.account_id.id,
+  AddAuthTokenManually("AccountId-" + account_info_consummer.account_id.id,
                        "refresh_token");
-  AddAuthTokenManually("AccountId-" + secondary_account.account_id.id,
+  AddAuthTokenManually("AccountId-" + account_info_enterprise.account_id.id,
                        "refresh_token");
-  oauth2_service_delegate_->LoadCredentials(primary_account.account_id);
+  oauth2_service_delegate_->LoadCredentials(account_info_consummer.account_id);
   base::RunLoop().RunUntilIdle();
 
+  // Only the enterprise token is revoked.
   EXPECT_EQ(1, tokens_loaded_count_);
-  EXPECT_EQ(2, token_available_count_);
-  EXPECT_EQ(0, token_revoked_count_);
+  EXPECT_EQ(1, token_available_count_);
+  EXPECT_EQ(1, token_revoked_count_);
   EXPECT_EQ(1, end_batch_changes_);
-  EXPECT_EQ(2, auth_error_changed_count_);
+  EXPECT_EQ(1, auth_error_changed_count_);
+  EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+      account_info_enterprise.account_id));
   EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
-      primary_account.account_id));
-  EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
-      secondary_account.account_id));
+      account_info_consummer.account_id));
+  EXPECT_EQ("refresh_token",
+            oauth2_service_delegate_
+                ->refresh_tokens_[account_info_consummer.account_id]
+                .refresh_token);
   EXPECT_EQ(
       signin::LoadCredentialsState::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
       oauth2_service_delegate_->load_credentials_state());
 
-  EXPECT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+  EXPECT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
 }
 
 // Tests that the migration happened after loading consummer accounts.
@@ -913,6 +924,7 @@
 }
 
 TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, LoadInvalidToken) {
+  pref_service_.SetBoolean(prefs::kTokenServiceDiceCompatible, true);
   InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
   std::map<std::string, std::string> tokens;
   const CoreAccountId account_id("account_id");
diff --git a/components/signin/public/base/signin_client.cc b/components/signin/public/base/signin_client.cc
index 8a358e0..fe2bb1c1 100644
--- a/components/signin/public/base/signin_client.cc
+++ b/components/signin/public/base/signin_client.cc
@@ -14,3 +14,7 @@
 void SigninClient::PreGaiaLogout(base::OnceClosure callback) {
   std::move(callback).Run();
 }
+
+bool SigninClient::IsNonEnterpriseUser(const std::string& username) {
+  return false;
+}
diff --git a/components/signin/public/base/signin_client.h b/components/signin/public/base/signin_client.h
index 3189fa174..88ecd18 100644
--- a/components/signin/public/base/signin_client.h
+++ b/components/signin/public/base/signin_client.h
@@ -98,6 +98,11 @@
 
   // Schedules migration to happen at next startup.
   virtual void SetReadyForDiceMigration(bool is_ready) {}
+
+  // Checks whether a user is known to be non-enterprise. Domains such as
+  // gmail.com and googlemail.com are known to not be managed. Also returns
+  // false if the username is empty.
+  virtual bool IsNonEnterpriseUser(const std::string& username);
 };
 
 #endif  // COMPONENTS_SIGNIN_PUBLIC_BASE_SIGNIN_CLIENT_H_
diff --git a/components/signin/public/base/test_signin_client.cc b/components/signin/public/base/test_signin_client.cc
index 36b8cb7..cefecdd 100644
--- a/components/signin/public/base/test_signin_client.cc
+++ b/components/signin/public/base/test_signin_client.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/test/test_cookie_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -125,3 +126,7 @@
 void TestSigninClient::SetDiceMigrationCompleted() {
   is_dice_migration_completed_ = true;
 }
+
+bool TestSigninClient::IsNonEnterpriseUser(const std::string& email) {
+  return gaia::ExtractDomainName(email) == "gmail.com";
+}
diff --git a/components/signin/public/base/test_signin_client.h b/components/signin/public/base/test_signin_client.h
index 9ecf7fa55..120f2881 100644
--- a/components/signin/public/base/test_signin_client.h
+++ b/components/signin/public/base/test_signin_client.h
@@ -94,6 +94,7 @@
   void PreGaiaLogout(base::OnceClosure callback) override;
   void SetReadyForDiceMigration(bool ready) override;
   void SetDiceMigrationCompleted() override;
+  bool IsNonEnterpriseUser(const std::string& email) override;
 
  private:
   std::unique_ptr<network::TestURLLoaderFactory>
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 211198498..4989bc9 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -235,7 +235,8 @@
   // If sync is disabled permanently, clean up old data that may be around (e.g.
   // crash during signout).
   if (HasDisableReason(DISABLE_REASON_ENTERPRISE_POLICY) ||
-      HasDisableReason(DISABLE_REASON_NOT_SIGNED_IN)) {
+      (HasDisableReason(DISABLE_REASON_NOT_SIGNED_IN) &&
+       auth_manager_->IsActiveAccountInfoFullyLoaded())) {
     StopImpl(CLEAR_DATA);
   }
 
diff --git a/components/sync/driver/sync_auth_manager.cc b/components/sync/driver/sync_auth_manager.cc
index 843a85363..060f597 100644
--- a/components/sync/driver/sync_auth_manager.cc
+++ b/components/sync/driver/sync_auth_manager.cc
@@ -83,6 +83,13 @@
   sync_account_ = DetermineAccountToUse();
 }
 
+bool SyncAuthManager::IsActiveAccountInfoFullyLoaded() const {
+  // The result of DetermineAccountToUse() is influenced by refresh tokens being
+  // loaded due to how IdentityManager::ComputeUnconsentedPrimaryAccountInfo()
+  // is implemented, which requires a refresh token.
+  return identity_manager_->AreRefreshTokensLoaded();
+}
+
 SyncAccountInfo SyncAuthManager::GetActiveAccountInfo() const {
   // Note: |sync_account_| should generally be identical to the result of a
   // DetermineAccountToUse() call, but there are a few edge cases when it isn't:
@@ -369,6 +376,24 @@
   credentials_changed_callback_.Run();
 }
 
+void SyncAuthManager::OnRefreshTokensLoaded() {
+  DCHECK(IsActiveAccountInfoFullyLoaded());
+
+  if (UpdateSyncAccountIfNecessary()) {
+    // |account_state_changed_callback_| has already been called, no need to
+    // consider calling it again.
+    return;
+  }
+
+  if (sync_account_.account_info.account_id.empty()) {
+    // Nothing actually changed, so |account_state_changed_callback_| hasn't
+    // been called yet. However, this is the first time we can reliably tell the
+    // user is signed out, exposed via IsActiveAccountInfoFullyLoaded(), so
+    // let's treat it as account state change.
+    account_state_changed_callback_.Run();
+  }
+}
+
 void SyncAuthManager::OnAccountsInCookieUpdated(
     const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
     const GoogleServiceAuthError& error) {
diff --git a/components/sync/driver/sync_auth_manager.h b/components/sync/driver/sync_auth_manager.h
index 2180618..26598da 100644
--- a/components/sync/driver/sync_auth_manager.h
+++ b/components/sync/driver/sync_auth_manager.h
@@ -60,6 +60,10 @@
   // callbacks, even if there is an active account afterwards.
   void RegisterForAuthNotifications();
 
+  // Returns whether all relevant account information as returned by
+  // GetActiveAccountInfo() has been fully loaded.
+  bool IsActiveAccountInfoFullyLoaded() const;
+
   // Returns the account which should be used when communicating with the Sync
   // server. Note that this account may not be blessed for Sync-the-feature.
   SyncAccountInfo GetActiveAccountInfo() const;
@@ -107,6 +111,7 @@
       const CoreAccountInfo& account_info) override;
   void OnRefreshTokenRemovedForAccount(
       const CoreAccountId& account_id) override;
+  void OnRefreshTokensLoaded() override;
   void OnAccountsInCookieUpdated(
       const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
       const GoogleServiceAuthError& error) override;
@@ -122,6 +127,7 @@
   // DetermineAccountToUse) if necessary, and notifies observers of any changes
   // (sign-in/sign-out/"primary" bit change). Note that changing from one
   // account to another is exposed to observers as a sign-out + sign-in.
+  // Returns whether the syncing account was updated.
   bool UpdateSyncAccountIfNecessary();
 
   // Invalidates any current access token, which means invalidating it with the
diff --git a/components/test/components_test_suite.cc b/components/test/components_test_suite.cc
index da287d93..62432e1 100644
--- a/components/test/components_test_suite.cc
+++ b/components/test/components_test_suite.cc
@@ -90,6 +90,7 @@
     url::AddStandardScheme("chrome-extension", url::SCHEME_WITH_HOST);
     url::AddStandardScheme("devtools", url::SCHEME_WITH_HOST);
     url::AddStandardScheme("chrome-search", url::SCHEME_WITH_HOST);
+    url::AddStandardScheme("chrome-distiller", url::SCHEME_WITH_HOST);
 
     ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
         kNonWildcardDomainNonPortSchemes,
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 912ff8d..5c8701f 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -17,6 +17,7 @@
     "check_circle.icon",
     "close.icon",
     "close_rounded.icon",
+    "devices.icon",
     "edit.icon",
     "error.icon",
     "ethernet.icon",
diff --git a/components/vector_icons/devices.icon b/components/vector_icons/devices.icon
new file mode 100644
index 0000000..e29395a
--- /dev/null
+++ b/components/vector_icons/devices.icon
@@ -0,0 +1,34 @@
+// Copyright 2019 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 4, 6,
+R_H_LINE_TO, 18,
+V_LINE_TO, 4,
+H_LINE_TO, 4,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+R_V_LINE_TO, 11,
+H_LINE_TO, 0,
+R_V_LINE_TO, 3,
+R_H_LINE_TO, 14,
+R_V_LINE_TO, -3,
+H_LINE_TO, 4,
+V_LINE_TO, 6,
+CLOSE,
+R_MOVE_TO, 19, 2,
+R_H_LINE_TO, -6,
+R_CUBIC_TO, -0.55f, 0, -1, 0.45f, -1, 1,
+R_V_LINE_TO, 10,
+R_CUBIC_TO, 0, 0.55f, 0.45f, 1, 1, 1,
+R_H_LINE_TO, 6,
+R_CUBIC_TO, 0.55f, 0, 1, -0.45f, 1, -1,
+V_LINE_TO, 9,
+R_CUBIC_TO, 0, -0.55f, -0.45f, -1, -1, -1,
+CLOSE,
+R_MOVE_TO, -1, 9,
+R_H_LINE_TO, -4,
+R_V_LINE_TO, -7,
+R_H_LINE_TO, 4,
+R_V_LINE_TO, 7,
+CLOSE
\ No newline at end of file
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 25617596..18f6564 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1949,8 +1949,6 @@
     "worker_host/shared_worker_content_settings_proxy_impl.h",
     "worker_host/shared_worker_host.cc",
     "worker_host/shared_worker_host.h",
-    "worker_host/shared_worker_instance.cc",
-    "worker_host/shared_worker_instance.h",
     "worker_host/shared_worker_service_impl.cc",
     "worker_host/shared_worker_service_impl.h",
     "worker_host/worker_script_fetch_initiator.cc",
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 256f446..e82fb86 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -11,8 +11,8 @@
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/worker_host/dedicated_worker_host.h"
 #include "content/browser/worker_host/shared_worker_host.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/public/browser/service_worker_context.h"
+#include "content/public/browser/shared_worker_instance.h"
 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
 #include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom.h"
 
diff --git a/content/browser/content_index/content_index_database.cc b/content/browser/content_index/content_index_database.cc
index 0d2bf731..f3aaaa4 100644
--- a/content/browser/content_index/content_index_database.cc
+++ b/content/browser/content_index/content_index_database.cc
@@ -4,10 +4,12 @@
 
 #include "content/browser/content_index/content_index_database.h"
 
+#include <set>
 #include <string>
 
 #include "base/barrier_closure.h"
 #include "base/optional.h"
+#include "base/stl_util.h"
 #include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "content/browser/background_fetch/storage/image_helpers.h"
@@ -172,6 +174,15 @@
     return;
   }
 
+  auto* service_worker_registration =
+      service_worker_context_->GetLiveRegistration(
+          service_worker_registration_id);
+  if (!service_worker_registration ||
+      !service_worker_registration->active_version()) {
+    std::move(callback).Run(blink::mojom::ContentIndexError::NO_SERVICE_WORKER);
+    return;
+  }
+
   auto serialized_icons = std::make_unique<proto::SerializedIcons>();
   proto::SerializedIcons* serialized_icons_ptr = serialized_icons.get();
 
@@ -334,10 +345,12 @@
   service_worker_context_->GetRegistrationUserDataByKeyPrefix(
       service_worker_registration_id, kEntryPrefix,
       base::BindOnce(&ContentIndexDatabase::DidGetDescriptions,
-                     weak_ptr_factory_core_.GetWeakPtr(), std::move(callback)));
+                     weak_ptr_factory_core_.GetWeakPtr(),
+                     service_worker_registration_id, std::move(callback)));
 }
 
 void ContentIndexDatabase::DidGetDescriptions(
+    int64_t service_worker_registration_id,
     blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
@@ -356,10 +369,10 @@
   std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
   descriptions.reserve(data.size());
 
-  // TODO(crbug.com/973844): Clear the storage if there is data corruption.
   for (const auto& serialized_entry : data) {
     proto::ContentEntry entry;
     if (!entry.ParseFromString(serialized_entry)) {
+      ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
       std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
                               /* descriptions= */ {});
       return;
@@ -367,9 +380,14 @@
 
     auto description = DescriptionFromProto(entry.description());
     if (!description) {
-      std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
-                              /* descriptions= */ {});
-      return;
+      // Clear entry data.
+      service_worker_context_->ClearRegistrationUserData(
+          service_worker_registration_id,
+          {EntryKey(entry.description().id()),
+           IconsKey(entry.description().id())},
+          base::BindOnce(&content_index::RecordDatabaseOperationStatus,
+                         "ClearCorruptedData"));
+      continue;
     }
 
     descriptions.push_back(std::move(description));
@@ -410,10 +428,12 @@
   service_worker_context_->GetRegistrationUserData(
       service_worker_registration_id, {IconsKey(description_id)},
       base::BindOnce(&ContentIndexDatabase::DidGetSerializedIcons,
-                     weak_ptr_factory_core_.GetWeakPtr(), std::move(callback)));
+                     weak_ptr_factory_core_.GetWeakPtr(),
+                     service_worker_registration_id, std::move(callback)));
 }
 
 void ContentIndexDatabase::DidGetSerializedIcons(
+    int64_t service_worker_registration_id,
     ContentIndexContext::GetIconsCallback callback,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
@@ -429,7 +449,7 @@
   DCHECK_EQ(data.size(), 1u);
   proto::SerializedIcons serialized_icons;
   if (!serialized_icons.ParseFromString(data.front())) {
-    // TODO(crbug.com/973844): Clear the storage if there is data corruption.
+    ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
     std::move(callback).Run({});
     return;
   }
@@ -521,19 +541,28 @@
 
   std::vector<ContentIndexEntry> entries;
   entries.reserve(user_data.size());
+  std::set<int64_t> corrupted_sw_ids;
 
   for (const auto& ud : user_data) {
     auto entry = EntryFromSerializedProto(ud.first, ud.second);
-    // TODO(crbug.com/973844): Clear the storage if there is data corruption.
     if (!entry) {
-      std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
-                              /* entries= */ {});
-      return;
+      corrupted_sw_ids.insert(ud.first);
+      continue;
     }
 
     entries.emplace_back(std::move(*entry));
   }
 
+  if (!corrupted_sw_ids.empty()) {
+    // Remove soon-to-be-deleted entries.
+    base::EraseIf(entries, [&corrupted_sw_ids](const auto& entry) {
+      return corrupted_sw_ids.count(entry.service_worker_registration_id);
+    });
+
+    for (int64_t service_worker_registration_id : corrupted_sw_ids)
+      ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
+  }
+
   std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
                           std::move(entries));
 }
@@ -590,6 +619,16 @@
       EntryFromSerializedProto(service_worker_registration_id, data.front()));
 }
 
+void ContentIndexDatabase::ClearServiceWorkerDataOnCorruption(
+    int64_t service_worker_registration_id) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+
+  service_worker_context_->ClearRegistrationUserDataByKeyPrefixes(
+      service_worker_registration_id, {kEntryPrefix, kIconPrefix},
+      base::BindOnce(&content_index::RecordDatabaseOperationStatus,
+                     "ClearCorruptedData"));
+}
+
 void ContentIndexDatabase::DeleteItem(int64_t service_worker_registration_id,
                                       const url::Origin& origin,
                                       const std::string& description_id) {
diff --git a/content/browser/content_index/content_index_database.h b/content/browser/content_index/content_index_database.h
index 0ecabbae1..89c23e8 100644
--- a/content/browser/content_index/content_index_database.h
+++ b/content/browser/content_index/content_index_database.h
@@ -127,12 +127,14 @@
 
   // GetDescriptions Callbacks.
   void DidGetDescriptions(
+      int64_t service_worker_registration_id,
       blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
       const std::vector<std::string>& data,
       blink::ServiceWorkerStatusCode status);
 
   // GetIcons Callbacks.
-  void DidGetSerializedIcons(ContentIndexContext::GetIconsCallback callback,
+  void DidGetSerializedIcons(int64_t service_worker_registration_id,
+                             ContentIndexContext::GetIconsCallback callback,
                              const std::vector<std::string>& data,
                              blink::ServiceWorkerStatusCode status);
   void DidDeserializeIcons(ContentIndexContext::GetIconsCallback callback,
@@ -167,6 +169,10 @@
   void DidDispatchEvent(const url::Origin& origin,
                         blink::ServiceWorkerStatusCode service_worker_status);
 
+  // Clears all the content index related data in a service worker.
+  void ClearServiceWorkerDataOnCorruption(
+      int64_t service_worker_registration_id);
+
   // Callbacks on the UI thread to notify |provider_| of updates.
   void NotifyProviderContentAdded(std::vector<ContentIndexEntry> entries);
   void NotifyProviderContentDeleted(int64_t service_worker_registration_id,
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.h b/content/browser/devtools/shared_worker_devtools_agent_host.h
index 41b264e..6399c26 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.h
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/unguessable_token.h"
 #include "content/browser/devtools/devtools_agent_host_impl.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
+#include "content/public/browser/shared_worker_instance.h"
 
 namespace content {
 
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index 3ebe2a8..1b9e19c4 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -174,10 +174,10 @@
     int process_id,
     int new_routing_id,
     service_manager::mojom::InterfaceProviderRequest interface_provider_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_content_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_blink_request,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content_receiver,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_blink_receiver,
     mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker_receiver,
     blink::WebTreeScopeType scope,
@@ -222,11 +222,11 @@
   added_node->current_frame_host()->BindInterfaceProviderRequest(
       std::move(interface_provider_request));
 
-  DCHECK(document_interface_broker_content_request.is_pending());
-  DCHECK(document_interface_broker_blink_request.is_pending());
-  added_node->current_frame_host()->BindDocumentInterfaceBrokerRequest(
-      std::move(document_interface_broker_content_request),
-      std::move(document_interface_broker_blink_request));
+  DCHECK(document_interface_broker_content_receiver.is_valid());
+  DCHECK(document_interface_broker_blink_receiver.is_valid());
+  added_node->current_frame_host()->BindDocumentInterfaceBrokerReceiver(
+      std::move(document_interface_broker_content_receiver),
+      std::move(document_interface_broker_blink_receiver));
 
   DCHECK(browser_interface_broker_receiver.is_valid());
   added_node->current_frame_host()->BindBrowserInterfaceBrokerReceiver(
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index e1a920a..f32aadd 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -18,6 +18,7 @@
 #include "base/macros.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 
@@ -155,10 +156,10 @@
       int new_routing_id,
       service_manager::mojom::InterfaceProviderRequest
           interface_provider_request,
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_content_request,
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_blink_request,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_content_receiver,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_blink_receiver,
       mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
           browser_interface_broker_receiver,
       blink::WebTreeScopeType scope,
diff --git a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
index d1cc743..a3a425d 100644
--- a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
+++ b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
@@ -100,8 +100,8 @@
       tree()->AddFrame(
           node, process_id(), child_id,
           TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-          TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-          TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+          TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+          TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
           TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
           blink::WebTreeScopeType::kDocument, std::string(),
           base::StringPrintf("uniqueName%d", child_id), false,
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
index 2c7e09d..1ffe334 100644
--- a/content/browser/frame_host/frame_tree_unittest.cc
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -57,9 +57,9 @@
   return TestRenderFrameHost::CreateStubInterfaceProviderRequest();
 }
 
-blink::mojom::DocumentInterfaceBrokerRequest
-CreateStubDocumentInterfaceBrokerRequest() {
-  return TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest();
+mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+CreateStubDocumentInterfaceBrokerReceiver() {
+  return TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver();
 }
 
 mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
@@ -176,48 +176,48 @@
   // Simulate attaching a series of frames to build the frame tree.
   frame_tree->AddFrame(
       root, process_id, 14, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       root, process_id, 15, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       root, process_id, 16, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       root->child_at(0), process_id, 244, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       root->child_at(1), process_id, 255, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, no_children_node, "uniqueName4",
       false, base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       root->child_at(0), process_id, 245, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName5", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -232,40 +232,40 @@
   FrameTreeNode* child_16 = root->child_at(2);
   frame_tree->AddFrame(
       child_16, process_id, 264, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName6", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       child_16, process_id, 265, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName7", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       child_16, process_id, 266, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName8", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       child_16, process_id, 267, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, deep_subtree, "uniqueName9", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(
       child_16, process_id, 268, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName10", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -274,16 +274,16 @@
   FrameTreeNode* child_267 = child_16->child_at(3);
   frame_tree->AddFrame(
       child_267, process_id, 365, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName11", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), false, kOwnerType);
   frame_tree->AddFrame(child_267->child_at(0), process_id, 455,
                        CreateStubInterfaceProviderRequest(),
-                       CreateStubDocumentInterfaceBrokerRequest(),
-                       CreateStubDocumentInterfaceBrokerRequest(),
+                       CreateStubDocumentInterfaceBrokerReceiver(),
+                       CreateStubDocumentInterfaceBrokerReceiver(),
                        CreateStubBrowserInterfaceBrokerReceiver(),
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName12", false, base::UnguessableToken::Create(),
@@ -291,8 +291,8 @@
                        kOwnerType);
   frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555,
                        CreateStubInterfaceProviderRequest(),
-                       CreateStubDocumentInterfaceBrokerRequest(),
-                       CreateStubDocumentInterfaceBrokerRequest(),
+                       CreateStubDocumentInterfaceBrokerReceiver(),
+                       CreateStubDocumentInterfaceBrokerReceiver(),
                        CreateStubBrowserInterfaceBrokerReceiver(),
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName13", false, base::UnguessableToken::Create(),
@@ -300,8 +300,8 @@
                        kOwnerType);
   frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0),
                        process_id, 655, CreateStubInterfaceProviderRequest(),
-                       CreateStubDocumentInterfaceBrokerRequest(),
-                       CreateStubDocumentInterfaceBrokerRequest(),
+                       CreateStubDocumentInterfaceBrokerReceiver(),
+                       CreateStubDocumentInterfaceBrokerReceiver(),
                        CreateStubBrowserInterfaceBrokerReceiver(),
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName14", false, base::UnguessableToken::Create(),
@@ -380,24 +380,24 @@
   constexpr auto kOwnerType = blink::FrameOwnerElementType::kIframe;
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "child0", "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), kOwnerType);
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "child1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), kOwnerType);
   main_test_rfh()->OnCreateChildFrame(
       24, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -409,8 +409,8 @@
   // Add one grandchild frame.
   child1->current_frame_host()->OnCreateChildFrame(
       33, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -453,24 +453,24 @@
   FrameTreeNode* root = frame_tree->root();
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "child0", "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), kOwnerType);
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "child1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), kOwnerType);
   main_test_rfh()->OnCreateChildFrame(
       24, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "child2", "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -482,8 +482,8 @@
   // Add one grandchild frame.
   child1->current_frame_host()->OnCreateChildFrame(
       33, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -519,8 +519,8 @@
   // Simulate attaching a series of frames to build the frame tree.
   main_test_rfh()->OnCreateChildFrame(
       14, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -531,8 +531,8 @@
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(
       18, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -557,8 +557,8 @@
   constexpr auto kOwnerType = blink::FrameOwnerElementType::kIframe;
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -569,8 +569,8 @@
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -603,8 +603,8 @@
   // Simulate attaching a frame from mismatched process id.
   ASSERT_FALSE(frame_tree->AddFrame(
       root, process_id + 1, 1, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -623,16 +623,16 @@
   constexpr auto kOwnerType = blink::FrameOwnerElementType::kIframe;
   main_test_rfh()->OnCreateChildFrame(
       22, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
       FrameOwnerProperties(), kOwnerType);
   main_test_rfh()->OnCreateChildFrame(
       23, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -642,8 +642,8 @@
   RenderFrameHostImpl* child1_rfh = root->child_at(0)->current_frame_host();
   child1_rfh->OnCreateChildFrame(
       33, CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 3216e72a..d6e241a 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2023,8 +2023,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name0, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2063,8 +2063,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name1, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2103,8 +2103,8 @@
   subframe->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name2, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2161,8 +2161,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -3366,8 +3366,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -3535,8 +3535,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -4776,8 +4776,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 6522b96..1d74f6f 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -178,10 +178,12 @@
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/cookie_constants.h"
 #include "services/device/public/cpp/device_features.h"
 #include "services/device/public/mojom/sensor_provider.mojom.h"
 #include "services/device/public/mojom/wake_lock.mojom.h"
@@ -850,8 +852,6 @@
               {ServiceWorkerContext::GetCoreThreadId()}))),
       active_sandbox_flags_(blink::WebSandboxFlags::kNone),
       document_scoped_interface_provider_binding_(this),
-      document_interface_broker_content_binding_(this),
-      document_interface_broker_blink_binding_(this),
       keep_alive_timeout_(base::TimeDelta::FromSeconds(30)),
       subframe_unload_timeout_(base::TimeDelta::FromMilliseconds(
           RenderViewHostImpl::kUnloadTimeoutMS)),
@@ -1636,8 +1636,8 @@
   SetRenderFrameCreated(false);
   InvalidateMojoConnection();
   document_scoped_interface_provider_binding_.Close();
-  document_interface_broker_content_binding_.Close();
-  document_interface_broker_blink_binding_.Close();
+  document_interface_broker_content_receiver_.reset();
+  document_interface_broker_blink_receiver_.reset();
   broker_receiver_.reset();
   SetLastCommittedUrl(GURL());
   bundled_exchanges_handle_.reset();
@@ -1805,13 +1805,13 @@
   service_manager::mojom::InterfaceProviderPtr interface_provider;
   BindInterfaceProviderRequest(mojo::MakeRequest(&interface_provider));
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
-      document_interface_broker_content_info;
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
-      document_interface_broker_blink_info;
-  BindDocumentInterfaceBrokerRequest(
-      mojo::MakeRequest(&document_interface_broker_content_info),
-      mojo::MakeRequest(&document_interface_broker_blink_info));
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content;
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink;
+  BindDocumentInterfaceBrokerReceiver(
+      document_interface_broker_content.InitWithNewPipeAndPassReceiver(),
+      document_interface_broker_blink.InitWithNewPipeAndPassReceiver());
 
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker;
@@ -1821,8 +1821,8 @@
   mojom::CreateFrameParamsPtr params = mojom::CreateFrameParams::New();
   params->interface_bundle = mojom::DocumentScopedInterfaceBundle::New(
       interface_provider.PassInterface(),
-      std::move(document_interface_broker_content_info),
-      std::move(document_interface_broker_blink_info),
+      std::move(document_interface_broker_content),
+      std::move(document_interface_broker_blink),
       std::move(browser_interface_broker));
 
   params->routing_id = routing_id_;
@@ -2021,10 +2021,10 @@
     int new_routing_id,
     service_manager::mojom::InterfaceProviderRequest
         new_interface_provider_provider_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_content_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_blink_request,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content_receiver,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_blink_receiver,
     mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker_receiver,
     blink::WebTreeScopeType scope,
@@ -2038,8 +2038,8 @@
   // TODO(lukasza): Call ReceivedBadMessage when |frame_unique_name| is empty.
   DCHECK(!frame_unique_name.empty());
   DCHECK(new_interface_provider_provider_request.is_pending());
-  DCHECK(document_interface_broker_content_request.is_pending());
-  DCHECK(document_interface_broker_blink_request.is_pending());
+  DCHECK(document_interface_broker_content_receiver.is_valid());
+  DCHECK(document_interface_broker_blink_receiver.is_valid());
   DCHECK(browser_interface_broker_receiver.is_valid());
   if (owner_type == blink::FrameOwnerElementType::kNone) {
     // Any child frame must have a HTMLFrameOwnerElement in its parent document
@@ -2057,15 +2057,15 @@
     return;
 
   // |new_routing_id|, |new_interface_provider_provider_request|,
-  // |document_interface_broker_content_request|,
-  // |document_interface_broker_blink_request|,
+  // |document_interface_broker_content_receiver|,
+  // |document_interface_broker_blink_receiver|,
   // |browser_interface_broker_receiver| and |devtools_frame_token| were
   // generated on the browser's IO thread and not taken from the renderer
   // process.
   frame_tree_->AddFrame(frame_tree_node_, GetProcess()->GetID(), new_routing_id,
                         std::move(new_interface_provider_provider_request),
-                        std::move(document_interface_broker_content_request),
-                        std::move(document_interface_broker_blink_request),
+                        std::move(document_interface_broker_content_receiver),
+                        std::move(document_interface_broker_blink_receiver),
                         std::move(browser_interface_broker_receiver), scope,
                         frame_name, frame_unique_name, is_created_by_script,
                         devtools_frame_token, frame_policy,
@@ -3856,15 +3856,17 @@
                                       std::move(interface_provider_request)));
 }
 
-void RenderFrameHostImpl::BindDocumentInterfaceBrokerRequest(
-    blink::mojom::DocumentInterfaceBrokerRequest content_request,
-    blink::mojom::DocumentInterfaceBrokerRequest blink_request) {
-  DCHECK(!document_interface_broker_content_binding_.is_bound());
-  DCHECK(content_request.is_pending());
-  document_interface_broker_content_binding_.Bind(std::move(content_request));
-  DCHECK(!document_interface_broker_blink_binding_.is_bound());
-  DCHECK(blink_request.is_pending());
-  document_interface_broker_blink_binding_.Bind(std::move(blink_request));
+void RenderFrameHostImpl::BindDocumentInterfaceBrokerReceiver(
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        content_receiver,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        blink_receiver) {
+  DCHECK(!document_interface_broker_content_receiver_.is_bound());
+  DCHECK(content_receiver.is_valid());
+  document_interface_broker_content_receiver_.Bind(std::move(content_receiver));
+  DCHECK(!document_interface_broker_blink_receiver_.is_bound());
+  DCHECK(blink_receiver.is_valid());
+  document_interface_broker_blink_receiver_.Bind(std::move(blink_receiver));
 }
 
 void RenderFrameHostImpl::BindBrowserInterfaceBrokerReceiver(
@@ -4071,14 +4073,14 @@
   rfh->BindInterfaceProviderRequest(
       mojo::MakeRequest(&main_frame_interface_provider_info));
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
-      document_interface_broker_content_info;
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content;
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
-      document_interface_broker_blink_info;
-  rfh->BindDocumentInterfaceBrokerRequest(
-      mojo::MakeRequest(&document_interface_broker_content_info),
-      mojo::MakeRequest(&document_interface_broker_blink_info));
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink;
+  rfh->BindDocumentInterfaceBrokerReceiver(
+      document_interface_broker_content.InitWithNewPipeAndPassReceiver(),
+      document_interface_broker_blink.InitWithNewPipeAndPassReceiver());
 
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker;
@@ -4089,8 +4091,8 @@
       render_view_route_id, main_frame_route_id, main_frame_widget_route_id,
       mojom::DocumentScopedInterfaceBundle::New(
           std::move(main_frame_interface_provider_info),
-          std::move(document_interface_broker_content_info),
-          std::move(document_interface_broker_blink_info),
+          std::move(document_interface_broker_content),
+          std::move(document_interface_broker_blink),
           std::move(browser_interface_broker)),
       cloned_namespace->id(), rfh->GetDevToolsFrameToken());
   std::move(callback).Run(mojom::CreateNewWindowStatus::kSuccess,
@@ -7129,12 +7131,12 @@
     BindInterfaceProviderRequest(
         std::move(interface_params->interface_provider_request));
 
-    document_interface_broker_content_binding_.Close();
-    document_interface_broker_blink_binding_.Close();
+    document_interface_broker_content_receiver_.reset();
+    document_interface_broker_blink_receiver_.reset();
     broker_receiver_.reset();
-    BindDocumentInterfaceBrokerRequest(
-        std::move(interface_params->document_interface_broker_content_request),
-        std::move(interface_params->document_interface_broker_blink_request));
+    BindDocumentInterfaceBrokerReceiver(
+        std::move(interface_params->document_interface_broker_content_receiver),
+        std::move(interface_params->document_interface_broker_blink_receiver));
     BindBrowserInterfaceBrokerReceiver(
         std::move(interface_params->browser_interface_broker_receiver));
   } else {
@@ -7147,8 +7149,8 @@
     // possibly from a different security origin, will no longer be dispatched.
     if (frame_tree_node_->has_committed_real_load()) {
       document_scoped_interface_provider_binding_.Close();
-      document_interface_broker_content_binding_.Close();
-      document_interface_broker_blink_binding_.Close();
+      document_interface_broker_content_receiver_.reset();
+      document_interface_broker_blink_receiver_.reset();
       broker_receiver_.reset();
       bad_message::ReceivedBadMessage(
           process, bad_message::RFH_INTERFACE_PROVIDER_MISSING);
@@ -7353,6 +7355,23 @@
         "can review cookies in developer tools under "
         "Application>Storage>Cookies and see more details at "
         "https://www.chromestatus.com/feature/5633521622188032.";
+  } else if (warning ==
+             net::CanonicalCookie::CookieInclusionStatus::WarningReason::
+                 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE) {
+    if (!ShouldAddCookieSameSiteDeprecationMessage(
+            cookie_url, &cookie_lax_allow_unsafe_deprecation_url_hashes_)) {
+      return;
+    }
+    deprecation_message =
+        "A cookie associated with a resource at " + cookie_url +
+        " set without a `SameSite` attribute was sent with a non-idempotent "
+        "top-level cross-site request because it was less than " +
+        base::NumberToString(net::kLaxAllowUnsafeMaxAge.InMinutes()) +
+        " minutes old. A future release of Chrome will treat such cookies as "
+        "if they were set with `SameSite=Lax` and will only allow them to be "
+        "sent with top-level cross-site requests if the HTTP method is safe. "
+        "See more details at "
+        "https://www.chromestatus.com/feature/5088147346030592.";
   }
 
   if (deprecation_message.empty())
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index c21321f..dae9f89 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -403,10 +403,10 @@
       int new_routing_id,
       service_manager::mojom::InterfaceProviderRequest
           interface_provider_request,
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_content_request,
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_blink_request,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_content_receiver,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_blink_receiver,
       mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
           browser_interface_broker_receiver,
       blink::WebTreeScopeType scope,
@@ -842,13 +842,15 @@
       service_manager::mojom::InterfaceProviderRequest
           interface_provider_request);
 
-  // Binds content and blink request ends of the DocumentInterfaceProvider
+  // Binds content and blink receiver ends of the DocumentInterfaceProvider
   // interface through which services provided by this RenderFrameHost are
   // exposed to the corresponding RenderFrame. The caller is responsible for
   // plumbing the client ends to the the renderer process.
-  void BindDocumentInterfaceBrokerRequest(
-      blink::mojom::DocumentInterfaceBrokerRequest content_request,
-      blink::mojom::DocumentInterfaceBrokerRequest blink_request);
+  void BindDocumentInterfaceBrokerReceiver(
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          content_receiver,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          blink_receiver);
 
   // Binds the receiver end of the BrowserInterfaceBroker interface through
   // which services provided by this RenderFrameHost are exposed to the
@@ -2207,14 +2209,14 @@
   mojo::Binding<service_manager::mojom::InterfaceProvider>
       document_scoped_interface_provider_binding_;
 
-  // Bindings for the DocumentInterfaceBroker through which this
+  // Receivers for the DocumentInterfaceBroker through which this
   // RenderFrameHostImpl exposes document-scoped Mojo services to the currently
   // active document in the corresponding RenderFrame. Because of the type
   // difference between content and blink, two separate pipes are used.
-  mojo::Binding<blink::mojom::DocumentInterfaceBroker>
-      document_interface_broker_content_binding_;
-  mojo::Binding<blink::mojom::DocumentInterfaceBroker>
-      document_interface_broker_blink_binding_;
+  mojo::Receiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content_receiver_{this};
+  mojo::Receiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink_receiver_{this};
 
   // BrowserInterfaceBroker implementation through which this
   // RenderFrameHostImpl exposes document-scoped Mojo services to the currently
@@ -2339,6 +2341,7 @@
   base::circular_deque<size_t> cookie_no_samesite_deprecation_url_hashes_;
   base::circular_deque<size_t>
       cookie_samesite_none_insecure_deprecation_url_hashes_;
+  base::circular_deque<size_t> cookie_lax_allow_unsafe_deprecation_url_hashes_;
 
   // The lifecycle state of the frame.
   blink::mojom::FrameLifecycleState frame_lifecycle_state_ =
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 2fe9951..8ee0c31 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -46,7 +46,9 @@
 #include "content/test/did_commit_navigation_interceptor.h"
 #include "content/test/frame_host_test_interface.mojom.h"
 #include "content/test/test_content_browser_client.h"
+#include "net/base/features.h"
 #include "net/base/net_errors.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -2474,7 +2476,7 @@
 // Test deduplication of SameSite cookie deprecation messages.
 // TODO(crbug.com/976475): This test is flaky.
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
-                       DISABLED_SameSiteCookieDeprecationMessages) {
+                       DISABLED_DeduplicateSameSiteCookieDeprecationMessages) {
 #if defined(OS_ANDROID)
   // TODO(crbug.com/974701): This test is broken on Android that is
   // Marshmallow or older.
@@ -2519,6 +2521,72 @@
   EXPECT_EQ(console_observer.messages()[1], console_observer.messages()[2]);
 }
 
+// Enable SameSiteByDefaultCookies to test deprecation messages for
+// Lax-allow-unsafe.
+class RenderFrameHostImplSameSiteByDefaultCookiesBrowserTest
+    : public RenderFrameHostImplBrowserTest {
+ public:
+  void SetUp() override {
+    feature_list_.InitWithFeatures({features::kCookieDeprecationMessages,
+                                    net::features::kSameSiteByDefaultCookies},
+                                   {});
+    RenderFrameHostImplBrowserTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplSameSiteByDefaultCookiesBrowserTest,
+                       DisplaySameSiteCookieDeprecationMessages) {
+  WebContentsImpl* web_contents =
+      static_cast<WebContentsImpl*>(shell()->web_contents());
+  ConsoleObserverDelegate console_observer(web_contents, "*");
+  web_contents->SetDelegate(&console_observer);
+
+  // Test deprecation messages for SameSiteByDefault.
+  // Set a cookie without SameSite on b.com, then access it in a cross-site
+  // context.
+  base::Time set_cookie_time = base::Time::Now();
+  GURL url =
+      embedded_test_server()->GetURL("x.com", "/set-cookie?nosamesite=1");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  // Message does not appear in same-site context (main frame is x).
+  ASSERT_EQ(0u, console_observer.messages().size());
+  url = embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(x())");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  // Message appears in cross-site context (a framing x).
+  EXPECT_EQ(1u, console_observer.messages().size());
+
+  // Test deprecation messages for CookiesWithoutSameSiteMustBeSecure.
+  // Set a cookie with SameSite=None but without Secure.
+  url = embedded_test_server()->GetURL(
+      "c.com", "/set-cookie?samesitenoneinsecure=1;SameSite=None");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  // The 1 message from before, plus the (different) message for setting the
+  // SameSite=None insecure cookie.
+  EXPECT_EQ(2u, console_observer.messages().size());
+
+  // Test deprecation messages for Lax-allow-unsafe.
+  url = embedded_test_server()->GetURL("a.com",
+                                       "/form_that_posts_cross_site.html");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  // Submit the form to make a cross-site POST request to x.com.
+  TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
+  EXPECT_TRUE(ExecJs(shell(), "document.getElementById('text-form').submit()"));
+  form_post_observer.Wait();
+
+  // The test should not take more than 2 minutes.
+  ASSERT_LT(base::Time::Now() - set_cookie_time, net::kLaxAllowUnsafeMaxAge);
+  EXPECT_EQ(3u, console_observer.messages().size());
+
+  // Check that the messages were all distinct.
+  EXPECT_NE(console_observer.messages()[0], console_observer.messages()[1]);
+  EXPECT_NE(console_observer.messages()[0], console_observer.messages()[2]);
+  EXPECT_NE(console_observer.messages()[1], console_observer.messages()[2]);
+}
+
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
                        SchedulerTrackedFeatures) {
   EXPECT_TRUE(
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 026b5e8..e6194f9b 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -1868,8 +1868,8 @@
   contents()->GetMainFrame()->OnCreateChildFrame(
       contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -1877,8 +1877,8 @@
   contents()->GetMainFrame()->OnCreateChildFrame(
       contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2025,8 +2025,8 @@
   contents1->GetMainFrame()->OnCreateChildFrame(
       contents1->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2080,8 +2080,8 @@
   main_rfh->OnCreateChildFrame(
       main_rfh->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2250,8 +2250,8 @@
   tree1->AddFrame(
       root1, process_id, 12,
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2259,8 +2259,8 @@
   tree1->AddFrame(
       root1, process_id, 13,
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2275,8 +2275,8 @@
   tree2->AddFrame(
       root2, process_id, 22,
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2284,8 +2284,8 @@
   tree2->AddFrame(
       root2, process_id, 23,
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2305,8 +2305,8 @@
   tree4->AddFrame(
       root4, process_id, 42,
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName4", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2360,8 +2360,8 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2369,8 +2369,8 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame2", "uniqueName2", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2378,8 +2378,8 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame3", "uniqueName3", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -2478,8 +2478,8 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -3067,8 +3067,8 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1", false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index a742f4d..1202e49 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -42,6 +42,8 @@
 #include "content/public/common/content_features.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ppapi/buildflags/buildflags.h"
@@ -94,9 +96,9 @@
         new_routing_id,
         service_manager::mojom::InterfaceProviderRequest(
             std::move(interface_provider_request_handle)),
-        blink::mojom::DocumentInterfaceBrokerRequest(
+        mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>(
             std::move(document_interface_broker_content_handle)),
-        blink::mojom::DocumentInterfaceBrokerRequest(
+        mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>(
             std::move(document_interface_broker_blink_handle)),
         mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>(
             std::move(browser_interface_broker_handle)),
@@ -388,18 +390,19 @@
   params_reply->new_interface_provider =
       interface_provider.PassInterface().PassHandle().release();
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
       document_interface_broker_content;
-  auto document_interface_broker_request_content(
-      mojo::MakeRequest(&document_interface_broker_content));
+  auto document_interface_broker_receiver_content =
+      document_interface_broker_content.InitWithNewPipeAndPassReceiver();
   params_reply->document_interface_broker_content_handle =
-      document_interface_broker_content.PassHandle().release();
+      document_interface_broker_content.PassPipe().release();
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker_blink;
-  auto document_interface_broker_request_blink(
-      mojo::MakeRequest(&document_interface_broker_blink));
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink;
+  auto document_interface_broker_receiver_blink =
+      document_interface_broker_blink.InitWithNewPipeAndPassReceiver();
   params_reply->document_interface_broker_blink_handle =
-      document_interface_broker_blink.PassHandle().release();
+      document_interface_broker_blink.PassPipe().release();
 
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker;
@@ -419,8 +422,8 @@
           params.frame_policy, params.frame_owner_properties,
           params.frame_owner_element_type, params_reply->child_routing_id,
           interface_provider_request.PassMessagePipe(),
-          document_interface_broker_request_content.PassMessagePipe(),
-          document_interface_broker_request_blink.PassMessagePipe(),
+          document_interface_broker_receiver_content.PassPipe(),
+          document_interface_broker_receiver_blink.PassPipe(),
           browser_interface_broker_receiver.PassPipe()));
 }
 
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index 739a50b5..af01bec 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -70,39 +70,39 @@
   DISALLOW_COPY_AND_ASSIGN(PrefetchBrowserTest);
 };
 
-class PrefetchBrowserTestRedirectMode
+class PrefetchBrowserTestPrivacyChanges
     : public PrefetchBrowserTestBase,
       public testing::WithParamInterface<bool> {
  public:
-  PrefetchBrowserTestRedirectMode()
-      : redirect_mode_is_error_(GetParam()),
+  PrefetchBrowserTestPrivacyChanges()
+      : privacy_changes_enabled_(GetParam()),
         cross_origin_server_(std::make_unique<net::EmbeddedTestServer>(
             net::EmbeddedTestServer::TYPE_HTTPS)) {}
-  ~PrefetchBrowserTestRedirectMode() override = default;
+  ~PrefetchBrowserTestPrivacyChanges() override = default;
 
   void SetUp() override {
     std::vector<base::Feature> enable_features;
     std::vector<base::Feature> disabled_features;
-    if (redirect_mode_is_error_) {
-      enable_features.push_back(blink::features::kPrefetchRedirectError);
+    if (privacy_changes_enabled_) {
+      enable_features.push_back(blink::features::kPrefetchPrivacyChanges);
     } else {
-      disabled_features.push_back(blink::features::kPrefetchRedirectError);
+      disabled_features.push_back(blink::features::kPrefetchPrivacyChanges);
     }
     feature_list_.InitWithFeatures(enable_features, disabled_features);
     PrefetchBrowserTestBase::SetUp();
   }
 
  protected:
-  const bool redirect_mode_is_error_;
+  const bool privacy_changes_enabled_;
   std::unique_ptr<net::EmbeddedTestServer> cross_origin_server_;
 
  private:
   base::test::ScopedFeatureList feature_list_;
 
-  DISALLOW_COPY_AND_ASSIGN(PrefetchBrowserTestRedirectMode);
+  DISALLOW_COPY_AND_ASSIGN(PrefetchBrowserTestPrivacyChanges);
 };
 
-IN_PROC_BROWSER_TEST_P(PrefetchBrowserTestRedirectMode, RedirectNotFollowed) {
+IN_PROC_BROWSER_TEST_P(PrefetchBrowserTestPrivacyChanges, RedirectNotFollowed) {
   const char* prefetch_path = "/prefetch.html";
   const char* redirect_path = "/redirect.html";
   const char* destination_path = "/destination.html";
@@ -138,7 +138,7 @@
   EXPECT_EQ(1, main_page_counter->GetRequestCount());
 
   NavigateToURLAndWaitTitle(destination_url, "Prefetch Target");
-  EXPECT_EQ(redirect_mode_is_error_ ? 1 : 2,
+  EXPECT_EQ(privacy_changes_enabled_ ? 1 : 2,
             destination_counter->GetRequestCount());
   EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
 }
@@ -832,8 +832,8 @@
                          PrefetchBrowserTest,
                          testing::Combine(testing::Bool(), testing::Bool()));
 
-INSTANTIATE_TEST_SUITE_P(PrefetchBrowserTestRedirectMode,
-                         PrefetchBrowserTestRedirectMode,
+INSTANTIATE_TEST_SUITE_P(PrefetchBrowserTestPrivacyChanges,
+                         PrefetchBrowserTestPrivacyChanges,
                          testing::Values(false, true));
 
 }  // namespace content
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index 269945e..494929aa 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -87,7 +87,7 @@
     PrefetchRedirect event) {
   // We only want to record prefetch vs prefetch redirects when we're not
   // experimenting with a request's redirect mode.
-  if (base::FeatureList::IsEnabled(blink::features::kPrefetchRedirectError))
+  if (base::FeatureList::IsEnabled(blink::features::kPrefetchPrivacyChanges))
     return;
 
   base::UmaHistogramEnumeration("Prefetch.Redirect", event);
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index 3cb3acd..17989d54 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -194,9 +194,9 @@
     return false;
   }
 
-  // If the PrefetchRedirectError feature is enabled, the request's redirect
+  // If the PrefetchPrivacyChanges feature is enabled, the request's redirect
   // mode must be |kError|.
-  if (base::FeatureList::IsEnabled(blink::features::kPrefetchRedirectError) &&
+  if (base::FeatureList::IsEnabled(blink::features::kPrefetchPrivacyChanges) &&
       resource_request.redirect_mode != network::mojom::RedirectMode::kError) {
     return false;
   }
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 2ca3cf0a..6bdbeee 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -55,6 +55,7 @@
 #include "content/test/content_browser_test_utils_internal.h"
 #include "content/test/did_commit_navigation_interceptor.h"
 #include "ipc/ipc_security_test_util.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/features.h"
 #include "net/base/filename_util.h"
@@ -99,14 +100,14 @@
     return intercepted_requests_;
   }
 
-  std::vector<blink::mojom::DocumentInterfaceBrokerRequest>&
-  intercepted_broker_content_requests() {
-    return intercepted_broker_content_requests_;
+  std::vector<mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>>&
+  intercepted_broker_content_receivers() {
+    return intercepted_broker_content_receivers_;
   }
 
-  std::vector<blink::mojom::DocumentInterfaceBrokerRequest>&
-  intercepted_broker_blink_requests() {
-    return intercepted_broker_blink_requests_;
+  std::vector<mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>>&
+  intercepted_broker_blink_receivers() {
+    return intercepted_broker_blink_receivers_;
   }
 
  protected:
@@ -122,16 +123,16 @@
         *interface_params
             ? std::move((*interface_params)->interface_provider_request)
             : nullptr);
-    intercepted_broker_content_requests_.push_back(
+    intercepted_broker_content_receivers_.push_back(
         *interface_params
             ? std::move((*interface_params)
-                            ->document_interface_broker_content_request)
-            : nullptr);
-    intercepted_broker_blink_requests_.push_back(
+                            ->document_interface_broker_content_receiver)
+            : mojo::NullReceiver());
+    intercepted_broker_blink_receivers_.push_back(
         *interface_params
             ? std::move(
-                  (*interface_params)->document_interface_broker_blink_request)
-            : nullptr);
+                  (*interface_params)->document_interface_broker_blink_receiver)
+            : mojo::NullReceiver());
     if (loop_)
       loop_->Quit();
     // Do not send the message to the RenderFrameHostImpl.
@@ -145,10 +146,10 @@
       intercepted_messages_;
   std::vector<::service_manager::mojom::InterfaceProviderRequest>
       intercepted_requests_;
-  std::vector<blink::mojom::DocumentInterfaceBrokerRequest>
-      intercepted_broker_content_requests_;
-  std::vector<blink::mojom::DocumentInterfaceBrokerRequest>
-      intercepted_broker_blink_requests_;
+  std::vector<mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>>
+      intercepted_broker_content_receivers_;
+  std::vector<mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>>
+      intercepted_broker_blink_receivers_;
   std::unique_ptr<base::RunLoop> loop_;
 };
 
diff --git a/content/browser/payments/payment_app_content_unittest_base.cc b/content/browser/payments/payment_app_content_unittest_base.cc
index 3491031..d0df2e50 100644
--- a/content/browser/payments/payment_app_content_unittest_base.cc
+++ b/content/browser/payments/payment_app_content_unittest_base.cc
@@ -95,7 +95,8 @@
 
     void DispatchCanMakePaymentEvent(
         payments::mojom::CanMakePaymentEventDataPtr event_data,
-        payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+        mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+            pending_response_callback,
         DispatchCanMakePaymentEventCallback callback) override {
       bool can_make_payment = false;
       for (const auto& method_data : event_data->method_data) {
@@ -104,6 +105,9 @@
           break;
         }
       }
+
+      mojo::Remote<payments::mojom::PaymentHandlerResponseCallback>
+          response_callback(std::move(pending_response_callback));
       response_callback->OnResponseForCanMakePayment(can_make_payment);
       std::move(callback).Run(
           blink::mojom::ServiceWorkerEventStatus::COMPLETED);
@@ -111,17 +115,18 @@
 
     void DispatchPaymentRequestEvent(
         payments::mojom::PaymentRequestEventDataPtr event_data,
-        payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+        mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+            pending_response_callback,
         DispatchPaymentRequestEventCallback callback) override {
       if (!worker_helper_)
         return;
       if (worker_helper_->respond_payment_request_immediately_) {
         FakeServiceWorker::DispatchPaymentRequestEvent(
-            std::move(event_data), std::move(response_callback),
+            std::move(event_data), std::move(pending_response_callback),
             std::move(callback));
       } else {
-        worker_helper_->pending_response_callback_ =
-            std::move(response_callback);
+        worker_helper_->response_callback_.Bind(
+            std::move(pending_response_callback));
         std::move(callback).Run(
             blink::mojom::ServiceWorkerEventStatus::COMPLETED);
       }
@@ -147,7 +152,8 @@
 
   // Variables to delay payment request response.
   bool respond_payment_request_immediately_ = true;
-  payments::mojom::PaymentHandlerResponseCallbackPtr pending_response_callback_;
+  mojo::Remote<payments::mojom::PaymentHandlerResponseCallback>
+      response_callback_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PaymentAppForWorkerTestHelper);
@@ -214,11 +220,10 @@
   }
 
   // Create a new payment manager.
-  payments::mojom::PaymentManagerPtr manager;
-  mojo::InterfaceRequest<payments::mojom::PaymentManager> request =
-      mojo::MakeRequest(&manager);
+  mojo::Remote<payments::mojom::PaymentManager> manager;
+  payment_app_context()->CreatePaymentManager(
+      manager.BindNewPipeAndPassReceiver());
   payment_managers_.push_back(std::move(manager));
-  payment_app_context()->CreatePaymentManager(std::move(request));
   base::RunLoop().RunUntilIdle();
 
   // Find a last registered payment manager.
@@ -250,7 +255,7 @@
 }
 
 void PaymentAppContentUnitTestBase::RespondPendingPaymentRequest() {
-  std::move(worker_helper_->pending_response_callback_)
+  std::move(worker_helper_->response_callback_)
       ->OnResponseForPaymentRequest(
           payments::mojom::PaymentHandlerResponse::New());
 }
diff --git a/content/browser/payments/payment_app_content_unittest_base.h b/content/browser/payments/payment_app_content_unittest_base.h
index 18b014d..c811110 100644
--- a/content/browser/payments/payment_app_content_unittest_base.h
+++ b/content/browser/payments/payment_app_content_unittest_base.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "content/browser/payments/payment_manager.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
 #include "url/gurl.h"
@@ -48,7 +49,7 @@
 
   std::unique_ptr<BrowserTaskEnvironment> task_environment_;
   std::unique_ptr<PaymentAppForWorkerTestHelper> worker_helper_;
-  std::vector<payments::mojom::PaymentManagerPtr> payment_managers_;
+  std::vector<mojo::Remote<payments::mojom::PaymentManager>> payment_managers_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentAppContentUnitTestBase);
 };
diff --git a/content/browser/payments/payment_app_context_impl.cc b/content/browser/payments/payment_app_context_impl.cc
index 2ef8ef38..c67b2416 100644
--- a/content/browser/payments/payment_app_context_impl.cc
+++ b/content/browser/payments/payment_app_context_impl.cc
@@ -45,13 +45,13 @@
 }
 
 void PaymentAppContextImpl::CreatePaymentManager(
-    payments::mojom::PaymentManagerRequest request) {
+    mojo::PendingReceiver<payments::mojom::PaymentManager> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   RunOrPostTaskOnThread(
       FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
       base::BindOnce(&PaymentAppContextImpl::CreatePaymentManagerOnCoreThread,
-                     this, std::move(request)));
+                     this, std::move(receiver)));
 }
 
 void PaymentAppContextImpl::PaymentManagerHadConnectionError(
@@ -82,10 +82,10 @@
 }
 
 void PaymentAppContextImpl::CreatePaymentManagerOnCoreThread(
-    mojo::InterfaceRequest<payments::mojom::PaymentManager> request) {
+    mojo::PendingReceiver<payments::mojom::PaymentManager> receiver) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   auto payment_manager =
-      std::make_unique<PaymentManager>(this, std::move(request));
+      std::make_unique<PaymentManager>(this, std::move(receiver));
   payment_managers_[payment_manager.get()] = std::move(payment_manager);
 }
 
diff --git a/content/browser/payments/payment_app_context_impl.h b/content/browser/payments/payment_app_context_impl.h
index be9f387..239c083 100644
--- a/content/browser/payments/payment_app_context_impl.h
+++ b/content/browser/payments/payment_app_context_impl.h
@@ -15,6 +15,7 @@
 #include "content/browser/payments/payment_app_database.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
 
 namespace content {
@@ -61,7 +62,8 @@
 
   // Create a PaymentManager that is owned by this. Call on the UI
   // thread.
-  void CreatePaymentManager(payments::mojom::PaymentManagerRequest request);
+  void CreatePaymentManager(
+      mojo::PendingReceiver<payments::mojom::PaymentManager> receiver);
 
   // Called by PaymentManager objects so that they can
   // be deleted. Call on the core thread.
@@ -81,7 +83,7 @@
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
 
   void CreatePaymentManagerOnCoreThread(
-      mojo::InterfaceRequest<payments::mojom::PaymentManager> request);
+      mojo::PendingReceiver<payments::mojom::PaymentManager> receiver);
 
   void ShutdownOnCoreThread();
 
diff --git a/content/browser/payments/payment_app_provider_impl.cc b/content/browser/payments/payment_app_provider_impl.cc
index d56259ac..9a84066 100644
--- a/content/browser/payments/payment_app_provider_impl.cc
+++ b/content/browser/payments/payment_app_provider_impl.cc
@@ -104,8 +104,7 @@
       : browser_context_(browser_context),
         event_type_(event_type),
         service_worker_version_(service_worker_version),
-        invoke_payment_app_callback_(std::move(callback)),
-        binding_(this) {
+        invoke_payment_app_callback_(std::move(callback)) {
     request_id_ = service_worker_version->StartRequest(
         event_type, base::BindOnce(&RespondWithCallbacks::OnErrorStatus,
                                    weak_ptr_factory_.GetWeakPtr()));
@@ -121,18 +120,15 @@
       : browser_context_(browser_context),
         event_type_(event_type),
         service_worker_version_(service_worker_version),
-        payment_event_result_callback_(std::move(callback)),
-        binding_(this) {
+        payment_event_result_callback_(std::move(callback)) {
     request_id_ = service_worker_version->StartRequest(
         event_type, base::BindOnce(&RespondWithCallbacks::OnErrorStatus,
                                    weak_ptr_factory_.GetWeakPtr()));
   }
 
-  payments::mojom::PaymentHandlerResponseCallbackPtr
-  CreateInterfacePtrAndBind() {
-    payments::mojom::PaymentHandlerResponseCallbackPtr callback_proxy;
-    binding_.Bind(mojo::MakeRequest(&callback_proxy));
-    return callback_proxy;
+  mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+  BindNewPipeAndPassRemote() {
+    return receiver_.BindNewPipeAndPassRemote();
   }
 
   void OnResponseForPaymentRequest(
@@ -247,7 +243,8 @@
   scoped_refptr<ServiceWorkerVersion> service_worker_version_;
   PaymentAppProvider::InvokePaymentAppCallback invoke_payment_app_callback_;
   PaymentAppProvider::PaymentEventResultCallback payment_event_result_callback_;
-  mojo::Binding<payments::mojom::PaymentHandlerResponseCallback> binding_;
+  mojo::Receiver<payments::mojom::PaymentHandlerResponseCallback> receiver_{
+      this};
 
   base::WeakPtrFactory<RespondWithCallbacks> weak_ptr_factory_{this};
 
@@ -294,7 +291,7 @@
       active_version, std::move(callback));
 
   active_version->endpoint()->DispatchAbortPaymentEvent(
-      invocation_callbacks->CreateInterfacePtrAndBind(),
+      invocation_callbacks->BindNewPipeAndPassRemote(),
       active_version->CreateSimpleEventCallback(event_finish_id));
 }
 
@@ -323,7 +320,7 @@
       active_version, std::move(callback));
 
   active_version->endpoint()->DispatchCanMakePaymentEvent(
-      std::move(event_data), invocation_callbacks->CreateInterfacePtrAndBind(),
+      std::move(event_data), invocation_callbacks->BindNewPipeAndPassRemote(),
       active_version->CreateSimpleEventCallback(event_finish_id));
 }
 
@@ -357,7 +354,7 @@
       active_version, std::move(callback));
 
   active_version->endpoint()->DispatchPaymentRequestEvent(
-      std::move(event_data), invocation_callbacks->CreateInterfacePtrAndBind(),
+      std::move(event_data), invocation_callbacks->BindNewPipeAndPassRemote(),
       active_version->CreateSimpleEventCallback(event_finish_id));
 }
 
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index fe4c3362..4be98c3 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/referrer_type_converters.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom.h"
 #include "third_party/blink/public/common/features.h"
@@ -125,10 +126,6 @@
   service_manager::mojom::InterfaceProviderPtr interface_provider;
   auto interface_provider_request(mojo::MakeRequest(&interface_provider));
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
-      document_interface_broker_content;
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker_blink;
-
   // Create a FrameTreeNode in the outer WebContents to host the portal, in
   // response to the creation of a portal in the renderer process.
   FrameTreeNode* outer_node = outer_contents_impl->GetFrameTree()->AddFrame(
@@ -136,8 +133,10 @@
       owner_render_frame_host_->GetProcess()->GetID(),
       owner_render_frame_host_->GetProcess()->GetNextRoutingID(),
       std::move(interface_provider_request),
-      mojo::MakeRequest(&document_interface_broker_content),
-      mojo::MakeRequest(&document_interface_broker_blink),
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver(),
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver(),
       mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
           .InitWithNewPipeAndPassReceiver(),
       blink::WebTreeScopeType::kDocument, "", "", true,
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index 7537eadf..42aaf77 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -133,8 +133,8 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(),
       TestRenderFrameHost::CreateStubInterfaceProviderRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
-      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
+      TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver(),
       TestRenderFrameHost::CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, std::string(), unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 7c3c2bbd..b55ee85 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -344,11 +344,11 @@
         mojom::DocumentScopedInterfaceBundle::New();
     main_rfh->BindInterfaceProviderRequest(mojo::MakeRequest(
         &params->main_frame_interface_bundle->interface_provider));
-    main_rfh->BindDocumentInterfaceBrokerRequest(
-        mojo::MakeRequest(&params->main_frame_interface_bundle
-                               ->document_interface_broker_content),
-        mojo::MakeRequest(&params->main_frame_interface_bundle
-                               ->document_interface_broker_blink));
+    main_rfh->BindDocumentInterfaceBrokerReceiver(
+        params->main_frame_interface_bundle->document_interface_broker_content
+            .InitWithNewPipeAndPassReceiver(),
+        params->main_frame_interface_bundle->document_interface_broker_blink
+            .InitWithNewPipeAndPassReceiver());
     main_rfh->BindBrowserInterfaceBrokerReceiver(
         params->main_frame_interface_bundle->browser_interface_broker
             .InitWithNewPipeAndPassReceiver());
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc
index c413b93..8f30cab8 100644
--- a/content/browser/renderer_interface_binders.cc
+++ b/content/browser/renderer_interface_binders.cc
@@ -180,12 +180,12 @@
   parameterized_binder_registry_.AddInterface(
       base::BindRepeating(CreateWebSocketConnector));
 
-  parameterized_binder_registry_.AddInterface(
-      base::Bind([](payments::mojom::PaymentManagerRequest request,
-                    RenderProcessHost* host, const url::Origin& origin) {
+  parameterized_binder_registry_.AddInterface(base::Bind(
+      [](mojo::PendingReceiver<payments::mojom::PaymentManager> receiver,
+         RenderProcessHost* host, const url::Origin& origin) {
         static_cast<StoragePartitionImpl*>(host->GetStoragePartition())
             ->GetPaymentAppContext()
-            ->CreatePaymentManager(std::move(request));
+            ->CreatePaymentManager(std::move(receiver));
       }));
   parameterized_binder_registry_.AddInterface(base::BindRepeating(
       [](mojo::PendingReceiver<blink::mojom::CacheStorage> receiver,
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index b365188..fe765dd 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -781,17 +781,15 @@
   params->origin = url::Origin::Create(GURL("about:blank"));
 
   service_manager::mojom::InterfaceProviderPtr isolated_interface_provider;
-  blink::mojom::DocumentInterfaceBrokerPtr
-      isolated_document_interface_broker_content;
-  blink::mojom::DocumentInterfaceBrokerPtr
-      isolated_document_interface_broker_blink;
   static_cast<mojom::FrameHost*>(child0_0->current_frame_host())
       ->DidCommitProvisionalLoad(
           std::move(params),
           mojom::DidCommitProvisionalLoadInterfaceParams::New(
               mojo::MakeRequest(&isolated_interface_provider),
-              mojo::MakeRequest(&isolated_document_interface_broker_content),
-              mojo::MakeRequest(&isolated_document_interface_broker_blink),
+              mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+                  .InitWithNewPipeAndPassReceiver(),
+              mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+                  .InitWithNewPipeAndPassReceiver(),
               mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
                   .InitWithNewPipeAndPassReceiver()));
 
diff --git a/content/browser/service_worker/fake_service_worker.cc b/content/browser/service_worker/fake_service_worker.cc
index 54ee0b7b..090e8f08 100644
--- a/content/browser/service_worker/fake_service_worker.cc
+++ b/content/browser/service_worker/fake_service_worker.cc
@@ -168,24 +168,33 @@
 }
 
 void FakeServiceWorker::DispatchAbortPaymentEvent(
-    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+        pending_response_callback,
     DispatchAbortPaymentEventCallback callback) {
+  mojo::Remote<payments::mojom::PaymentHandlerResponseCallback>
+      response_callback(std::move(pending_response_callback));
   response_callback->OnResponseForAbortPayment(true);
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
 }
 
 void FakeServiceWorker::DispatchCanMakePaymentEvent(
     payments::mojom::CanMakePaymentEventDataPtr event_data,
-    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+        pending_response_callback,
     DispatchCanMakePaymentEventCallback callback) {
+  mojo::Remote<payments::mojom::PaymentHandlerResponseCallback>
+      response_callback(std::move(pending_response_callback));
   response_callback->OnResponseForCanMakePayment(true);
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
 }
 
 void FakeServiceWorker::DispatchPaymentRequestEvent(
     payments::mojom::PaymentRequestEventDataPtr event_data,
-    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+        pending_response_callback,
     DispatchPaymentRequestEventCallback callback) {
+  mojo::Remote<payments::mojom::PaymentHandlerResponseCallback>
+      response_callback(std::move(pending_response_callback));
   response_callback->OnResponseForPaymentRequest(
       payments::mojom::PaymentHandlerResponse::New());
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
diff --git a/content/browser/service_worker/fake_service_worker.h b/content/browser/service_worker/fake_service_worker.h
index c631ff9..8689c40 100644
--- a/content/browser/service_worker/fake_service_worker.h
+++ b/content/browser/service_worker/fake_service_worker.h
@@ -103,15 +103,18 @@
       base::TimeDelta timeout,
       DispatchPeriodicSyncEventCallback callback) override;
   void DispatchAbortPaymentEvent(
-      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+          pending_response_callback,
       DispatchAbortPaymentEventCallback callback) override;
   void DispatchCanMakePaymentEvent(
       payments::mojom::CanMakePaymentEventDataPtr event_data,
-      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+          pending_response_callback,
       DispatchCanMakePaymentEventCallback callback) override;
   void DispatchPaymentRequestEvent(
       payments::mojom::PaymentRequestEventDataPtr event_data,
-      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      mojo::PendingRemote<payments::mojom::PaymentHandlerResponseCallback>
+          pending_response_callback,
       DispatchPaymentRequestEventCallback callback) override;
   void DispatchExtendableMessageEvent(
       blink::mojom::ExtendableMessageEventPtr event,
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index f884bb4c..d173e55 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -1225,6 +1225,7 @@
 
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetUncommittedResourceIds(
     std::set<int64_t>* ids) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   return ReadResourceIds(service_worker_internals::kUncommittedResIdKeyPrefix,
                          ids);
 }
@@ -1232,6 +1233,7 @@
 ServiceWorkerDatabase::Status
 ServiceWorkerDatabase::WriteUncommittedResourceIds(
     const std::set<int64_t>& ids) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   leveldb::WriteBatch batch;
   Status status = WriteResourceIdsInBatch(
       service_worker_internals::kUncommittedResIdKeyPrefix, ids, &batch);
@@ -1242,12 +1244,14 @@
 
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetPurgeableResourceIds(
     std::set<int64_t>* ids) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   return ReadResourceIds(service_worker_internals::kPurgeableResIdKeyPrefix,
                          ids);
 }
 
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ClearPurgeableResourceIds(
     const std::set<int64_t>& ids) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   Status status = LazyOpen(false);
   if (IsNewOrNonexistentDatabase(status))
     return STATUS_OK;
@@ -1263,6 +1267,7 @@
 ServiceWorkerDatabase::Status
 ServiceWorkerDatabase::PurgeUncommittedResourceIds(
     const std::set<int64_t>& ids) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   Status status = LazyOpen(false);
   if (IsNewOrNonexistentDatabase(status))
     return STATUS_OK;
@@ -1400,6 +1405,7 @@
 
 bool ServiceWorkerDatabase::IsNewOrNonexistentDatabase(
     ServiceWorkerDatabase::Status status) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   if (status == STATUS_ERROR_NOT_FOUND)
     return true;
   if (status == STATUS_OK && state_ == DATABASE_STATE_UNINITIALIZED)
@@ -1410,6 +1416,7 @@
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadNextAvailableId(
     const char* id_key,
     int64_t* next_avail_id) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(id_key);
   DCHECK(next_avail_id);
 
@@ -1435,6 +1442,7 @@
     int64_t registration_id,
     const GURL& origin,
     RegistrationData* registration) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(registration);
 
   const std::string key = CreateRegistrationKey(registration_id, origin);
@@ -1456,6 +1464,7 @@
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ParseRegistrationData(
     const std::string& serialized,
     RegistrationData* out) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(out);
   ServiceWorkerRegistrationData data;
   if (!data.ParseFromString(serialized))
@@ -1550,6 +1559,7 @@
 void ServiceWorkerDatabase::WriteRegistrationDataInBatch(
     const RegistrationData& registration,
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
 
   // The registration id and version id should be bumped before this.
@@ -1605,6 +1615,7 @@
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceRecords(
     const RegistrationData& registration,
     std::vector<ResourceRecord>* resources) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(resources->empty());
 
   Status status = STATUS_OK;
@@ -1653,6 +1664,7 @@
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ParseResourceRecord(
     const std::string& serialized,
     ServiceWorkerDatabase::ResourceRecord* out) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(out);
   ServiceWorkerResourceRecord record;
   if (!record.ParseFromString(serialized))
@@ -1707,6 +1719,7 @@
     int64_t version_id,
     std::vector<int64_t>* newly_purgeable_resources,
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
 
   Status status = STATUS_OK;
@@ -1830,6 +1843,7 @@
 ServiceWorkerDatabase::DeleteUserDataForRegistration(
     int64_t registration_id,
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
   Status status = STATUS_OK;
   const std::string prefix = CreateUserDataKeyPrefix(registration_id);
@@ -1857,6 +1871,7 @@
 
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadDatabaseVersion(
     int64_t* db_version) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   std::string value;
   Status status = LevelDBStatusToServiceWorkerDBStatus(
       db_->Get(leveldb::ReadOptions(),
@@ -1889,6 +1904,7 @@
 
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteBatch(
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
   DCHECK_NE(DATABASE_STATE_DISABLED, state_);
 
@@ -1909,6 +1925,7 @@
 void ServiceWorkerDatabase::BumpNextRegistrationIdIfNeeded(
     int64_t used_id,
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
   if (next_avail_registration_id_ <= used_id) {
     next_avail_registration_id_ = used_id + 1;
@@ -1920,6 +1937,7 @@
 void ServiceWorkerDatabase::BumpNextResourceIdIfNeeded(
     int64_t used_id,
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
   if (next_avail_resource_id_ <= used_id) {
     next_avail_resource_id_ = used_id + 1;
@@ -1931,6 +1949,7 @@
 void ServiceWorkerDatabase::BumpNextVersionIdIfNeeded(
     int64_t used_id,
     leveldb::WriteBatch* batch) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   DCHECK(batch);
   if (next_avail_version_id_ <= used_id) {
     next_avail_version_id_ = used_id + 1;
@@ -1940,11 +1959,13 @@
 }
 
 bool ServiceWorkerDatabase::IsOpen() {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   return db_ != nullptr;
 }
 
 void ServiceWorkerDatabase::Disable(const base::Location& from_here,
                                     Status status) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   if (status != STATUS_OK) {
     DLOG(ERROR) << "Failed at: " << from_here.ToString()
                 << " with error: " << StatusToString(status);
@@ -1956,6 +1977,7 @@
 
 void ServiceWorkerDatabase::HandleOpenResult(const base::Location& from_here,
                                              Status status) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   if (status != STATUS_OK)
     Disable(from_here, status);
   ServiceWorkerMetrics::CountOpenDatabaseResult(status);
@@ -1963,6 +1985,7 @@
 
 void ServiceWorkerDatabase::HandleReadResult(const base::Location& from_here,
                                              Status status) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   if (status != STATUS_OK)
     Disable(from_here, status);
   ServiceWorkerMetrics::CountReadDatabaseResult(status);
@@ -1970,12 +1993,14 @@
 
 void ServiceWorkerDatabase::HandleWriteResult(const base::Location& from_here,
                                               Status status) {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   if (status != STATUS_OK)
     Disable(from_here, status);
   ServiceWorkerMetrics::CountWriteDatabaseResult(status);
 }
 
 bool ServiceWorkerDatabase::IsDatabaseInMemory() const {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
   return path_.empty();
 }
 
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index 1bd93e6..6bac1506 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -821,8 +821,13 @@
       registration()->last_update_check().is_null()) {
     registration()->set_last_update_check(base::Time::Now());
 
-    if (registration()->newest_installed_version())
-      context_->storage()->UpdateLastUpdateCheckTime(registration());
+    if (registration()->newest_installed_version()) {
+      context_->storage()->UpdateLastUpdateCheckTime(
+          registration(),
+          base::BindOnce([](blink::ServiceWorkerStatusCode status) {
+            // Ignore errors; bumping the update check time is just best-effort.
+          }));
+    }
   }
 }
 
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index f0c566b8..e8926a4 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -500,21 +500,30 @@
 }
 
 void ServiceWorkerStorage::UpdateLastUpdateCheckTime(
-    ServiceWorkerRegistration* registration) {
+    ServiceWorkerRegistration* registration,
+    StatusCallback callback) {
   DCHECK(registration);
   DCHECK(state_ == STORAGE_STATE_INITIALIZED ||
          state_ == STORAGE_STATE_DISABLED)
       << state_;
-  if (IsDisabled())
+  if (IsDisabled()) {
+    RunSoon(FROM_HERE,
+            base::BindOnce(std::move(callback),
+                           blink::ServiceWorkerStatusCode::kErrorAbort));
     return;
+  }
 
-  database_task_runner_->PostTask(
-      FROM_HERE,
+  base::PostTaskAndReplyWithResult(
+      database_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&ServiceWorkerDatabase::UpdateLastCheckTime,
+                     base::Unretained(database_.get()), registration->id(),
+                     registration->scope().GetOrigin(),
+                     registration->last_update_check()),
       base::BindOnce(
-          base::IgnoreResult(&ServiceWorkerDatabase::UpdateLastCheckTime),
-          base::Unretained(database_.get()), registration->id(),
-          registration->scope().GetOrigin(),
-          registration->last_update_check()));
+          [](StatusCallback callback, ServiceWorkerDatabase::Status status) {
+            std::move(callback).Run(DatabaseStatusToStatusCode(status));
+          },
+          std::move(callback)));
 }
 
 void ServiceWorkerStorage::UpdateNavigationPreloadEnabled(
@@ -1185,6 +1194,11 @@
   loop.Run();
 }
 
+void ServiceWorkerStorage::SetPurgingCompleteCallbackForTest(
+    base::OnceClosure callback) {
+  purging_complete_callback_for_test_ = std::move(callback);
+}
+
 void ServiceWorkerStorage::LazyInitialize(base::OnceClosure callback) {
   DCHECK(state_ == STORAGE_STATE_UNINITIALIZED ||
          state_ == STORAGE_STATE_INITIALIZING)
@@ -1766,8 +1780,13 @@
 }
 
 void ServiceWorkerStorage::ContinuePurgingResources() {
-  if (purgeable_resource_ids_.empty() || is_purge_pending_)
+  if (is_purge_pending_)
     return;
+  if (purgeable_resource_ids_.empty()) {
+    if (purging_complete_callback_for_test_)
+      std::move(purging_complete_callback_for_test_).Run();
+    return;
+  }
 
   // Do one at a time until we're done, use RunSoon to avoid recursion when
   // DoomEntry returns immediately.
diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h
index fad0cd8..2712a4d 100644
--- a/content/browser/service_worker/service_worker_storage.h
+++ b/content/browser/service_worker/service_worker_storage.h
@@ -153,7 +153,8 @@
 
   // Updates the stored time to match the value of
   // registration->last_update_check().
-  void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration);
+  void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration,
+                                 StatusCallback callback);
 
   // Updates the specified registration's navigation preload state in storage.
   // The caller is responsible for mutating the live registration's state.
@@ -289,6 +290,8 @@
 
   void LazyInitializeForTest();
 
+  void SetPurgingCompleteCallbackForTest(base::OnceClosure callback);
+
  private:
   friend class service_worker_storage_unittest::ServiceWorkerStorageTest;
   friend class service_worker_storage_unittest::
@@ -614,6 +617,7 @@
   base::circular_deque<int64_t> purgeable_resource_ids_;
   bool is_purge_pending_;
   bool has_checked_for_stale_resources_;
+  base::OnceClosure purging_complete_callback_for_test_;
 
   base::WeakPtrFactory<ServiceWorkerStorage> weak_factory_{this};
 
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index 0876568..306420b0 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -30,6 +31,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/origin_util.h"
 #include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_utils.h"
 #include "ipc/ipc_message.h"
 #include "net/base/io_buffer.h"
@@ -71,100 +73,32 @@
     0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0,
 };
 
-void StatusAndQuitCallback(blink::ServiceWorkerStatusCode* result,
-                           base::OnceClosure quit_closure,
-                           blink::ServiceWorkerStatusCode status) {
+void StatusCallback(base::OnceClosure quit_closure,
+                    base::Optional<blink::ServiceWorkerStatusCode>* result,
+                    blink::ServiceWorkerStatusCode status) {
   *result = status;
   std::move(quit_closure).Run();
 }
 
-void StatusCallback(bool* was_called,
-                    base::Optional<blink::ServiceWorkerStatusCode>* result,
-                    blink::ServiceWorkerStatusCode status) {
-  *was_called = true;
-  *result = status;
-}
-
-ServiceWorkerStorage::StatusCallback MakeStatusCallback(
-    bool* was_called,
-    base::Optional<blink::ServiceWorkerStatusCode>* result) {
-  return base::BindOnce(&StatusCallback, was_called, result);
-}
-
-void FindCallback(bool* was_called,
+void FindCallback(base::OnceClosure quit_closure,
                   base::Optional<blink::ServiceWorkerStatusCode>* result,
                   scoped_refptr<ServiceWorkerRegistration>* found,
                   blink::ServiceWorkerStatusCode status,
                   scoped_refptr<ServiceWorkerRegistration> registration) {
-  *was_called = true;
   *result = status;
   *found = std::move(registration);
+  std::move(quit_closure).Run();
 }
 
-ServiceWorkerStorage::FindRegistrationCallback MakeFindCallback(
-    bool* was_called,
-    base::Optional<blink::ServiceWorkerStatusCode>* result,
-    scoped_refptr<ServiceWorkerRegistration>* found) {
-  return base::BindOnce(&FindCallback, was_called, result, found);
-}
-
-void GetAllCallback(
-    bool* was_called,
-    base::Optional<blink::ServiceWorkerStatusCode>* result,
-    std::vector<scoped_refptr<ServiceWorkerRegistration>>* all_out,
-    blink::ServiceWorkerStatusCode status,
-    const std::vector<scoped_refptr<ServiceWorkerRegistration>>& all) {
-  *was_called = true;
-  *result = status;
-  *all_out = all;
-}
-
-void GetAllInfosCallback(
-    bool* was_called,
-    base::Optional<blink::ServiceWorkerStatusCode>* result,
-    std::vector<ServiceWorkerRegistrationInfo>* all_out,
-    blink::ServiceWorkerStatusCode status,
-    const std::vector<ServiceWorkerRegistrationInfo>& all) {
-  *was_called = true;
-  *result = status;
-  *all_out = all;
-}
-
-ServiceWorkerStorage::GetRegistrationsCallback MakeGetRegistrationsCallback(
-    bool* was_called,
-    base::Optional<blink::ServiceWorkerStatusCode>* status,
-    std::vector<scoped_refptr<ServiceWorkerRegistration>>* all) {
-  return base::BindOnce(&GetAllCallback, was_called, status, all);
-}
-
-ServiceWorkerStorage::GetRegistrationsInfosCallback
-MakeGetRegistrationsInfosCallback(
-    bool* was_called,
-    base::Optional<blink::ServiceWorkerStatusCode>* status,
-    std::vector<ServiceWorkerRegistrationInfo>* all) {
-  return base::BindOnce(&GetAllInfosCallback, was_called, status, all);
-}
-
-void GetUserDataCallback(
-    bool* was_called,
+void UserDataCallback(
+    base::OnceClosure quit,
     std::vector<std::string>* data_out,
     base::Optional<blink::ServiceWorkerStatusCode>* status_out,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  *was_called = true;
   *data_out = data;
   *status_out = status;
-}
-
-void GetUserDataForAllRegistrationsCallback(
-    bool* was_called,
-    std::vector<std::pair<int64_t, std::string>>* data_out,
-    base::Optional<blink::ServiceWorkerStatusCode>* status_out,
-    const std::vector<std::pair<int64_t, std::string>>& data,
-    blink::ServiceWorkerStatusCode status) {
-  *was_called = true;
-  *data_out = data;
-  *status_out = status;
+  std::move(quit).Run();
 }
 
 int WriteResponse(ServiceWorkerStorage* storage,
@@ -334,6 +268,7 @@
 
   void InitializeTestHelper() {
     helper_.reset(new EmbeddedWorkerTestHelper(user_data_directory_path_));
+    // TODO(falken): Figure out why RunUntilIdle is needed.
     base::RunLoop().RunUntilIdle();
   }
 
@@ -341,19 +276,6 @@
   ServiceWorkerStorage* storage() { return context()->storage(); }
   ServiceWorkerDatabase* database() { return storage()->database_.get(); }
 
-  // A static class method for friendliness.
-  static void VerifyPurgeableListStatusCallback(
-      ServiceWorkerDatabase* database,
-      std::set<int64_t>* purgeable_ids,
-      bool* was_called,
-      blink::ServiceWorkerStatusCode* result,
-      blink::ServiceWorkerStatusCode status) {
-    *was_called = true;
-    *result = status;
-    EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-              database->GetPurgeableResourceIds(purgeable_ids));
-  }
-
  protected:
   const std::set<GURL>& registered_origins() {
     return storage()->registered_origins_;
@@ -364,53 +286,65 @@
   blink::ServiceWorkerStatusCode StoreRegistration(
       scoped_refptr<ServiceWorkerRegistration> registration,
       scoped_refptr<ServiceWorkerVersion> version) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
-    storage()->StoreRegistration(registration.get(),
-                                 version.get(),
-                                 MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+    base::RunLoop loop;
+    storage()->StoreRegistration(
+        registration.get(), version.get(),
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode DeleteRegistration(
       scoped_refptr<ServiceWorkerRegistration> registration,
       const GURL& origin) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
-    storage()->DeleteRegistration(registration, origin,
-                                  MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+    base::RunLoop loop;
+    storage()->DeleteRegistration(
+        registration, origin,
+        base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) {
+          result = status;
+          loop.Quit();
+        }));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode GetAllRegistrationsInfos(
       std::vector<ServiceWorkerRegistrationInfo>* registrations) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
-    storage()->GetAllRegistrationsInfos(
-        MakeGetRegistrationsInfosCallback(&was_called, &result, registrations));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+    base::RunLoop loop;
+    storage()->GetAllRegistrationsInfos(base::BindLambdaForTesting(
+        [&](blink::ServiceWorkerStatusCode status,
+            const std::vector<ServiceWorkerRegistrationInfo>& infos) {
+          result = status;
+          *registrations = infos;
+          loop.Quit();
+        }));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode GetRegistrationsForOrigin(
       const GURL& origin,
       std::vector<scoped_refptr<ServiceWorkerRegistration>>* registrations) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
+    base::RunLoop loop;
     storage()->GetRegistrationsForOrigin(
         origin,
-        MakeGetRegistrationsCallback(&was_called, &result, registrations));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        base::BindLambdaForTesting(
+            [&](blink::ServiceWorkerStatusCode status,
+                const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
+                    found_registrations) {
+              result = status;
+              *registrations = found_registrations;
+              loop.Quit();
+            }));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
@@ -418,14 +352,13 @@
       int64_t registration_id,
       const std::vector<std::string>& keys,
       std::vector<std::string>* data) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
     storage()->GetUserData(
         registration_id, keys,
-        base::BindOnce(&GetUserDataCallback, &was_called, data, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        base::BindOnce(&UserDataCallback, loop.QuitClosure(), data, &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
@@ -433,14 +366,13 @@
       int64_t registration_id,
       const std::string& key_prefix,
       std::vector<std::string>* data) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
     storage()->GetUserDataByKeyPrefix(
         registration_id, key_prefix,
-        base::BindOnce(&GetUserDataCallback, &was_called, data, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        base::BindOnce(&UserDataCallback, loop.QuitClosure(), data, &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
@@ -448,109 +380,118 @@
       int64_t registration_id,
       const GURL& origin,
       const std::vector<std::pair<std::string, std::string>>& key_value_pairs) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
-    storage()->StoreUserData(registration_id, origin, key_value_pairs,
-                             MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+    storage()->StoreUserData(
+        registration_id, origin, key_value_pairs,
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode ClearUserData(
       int64_t registration_id,
       const std::vector<std::string>& keys) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
-    storage()->ClearUserData(registration_id, keys,
-                             MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+    storage()->ClearUserData(
+        registration_id, keys,
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    EXPECT_FALSE(result);  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode ClearUserDataByKeyPrefixes(
       int64_t registration_id,
       const std::vector<std::string>& key_prefixes) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
     storage()->ClearUserDataByKeyPrefixes(
         registration_id, key_prefixes,
-        MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode GetUserDataForAllRegistrations(
       const std::string& key,
       std::vector<std::pair<int64_t, std::string>>* data) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
     storage()->GetUserDataForAllRegistrations(
-        key, base::BindOnce(&GetUserDataForAllRegistrationsCallback,
-                            &was_called, data, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        key,
+        base::BindLambdaForTesting(
+            [&](const std::vector<std::pair<int64_t, std::string>>& user_data,
+                blink::ServiceWorkerStatusCode status) {
+              result = status;
+              *data = user_data;
+              loop.Quit();
+            }));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode ClearUserDataForAllRegistrationsByKeyPrefix(
       const std::string& key_prefix) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
     storage()->ClearUserDataForAllRegistrationsByKeyPrefix(
-        key_prefix, MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        key_prefix,
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode UpdateToActiveState(
       scoped_refptr<ServiceWorkerRegistration> registration) {
-    bool was_called = false;
+    base::RunLoop loop;
     base::Optional<blink::ServiceWorkerStatusCode> result;
-    storage()->UpdateToActiveState(registration.get(),
-                                   MakeStatusCallback(&was_called, &result));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+    storage()->UpdateToActiveState(
+        registration.get(),
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    EXPECT_FALSE(result.has_value());  // always async
+    loop.Run();
     return result.value();
   }
 
-  void UpdateLastUpdateCheckTime(
+  blink::ServiceWorkerStatusCode UpdateLastUpdateCheckTime(
       scoped_refptr<ServiceWorkerRegistration> registration) {
-    storage()->UpdateLastUpdateCheckTime(registration.get());
-    base::RunLoop().RunUntilIdle();
+    base::RunLoop loop;
+    base::Optional<blink::ServiceWorkerStatusCode> result;
+    storage()->UpdateLastUpdateCheckTime(
+        registration.get(),
+        base::BindOnce(&StatusCallback, loop.QuitClosure(), &result));
+    loop.Run();
+    return result.value();
   }
 
   blink::ServiceWorkerStatusCode FindRegistrationForDocument(
       const GURL& document_url,
       scoped_refptr<ServiceWorkerRegistration>* registration) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
+    base::RunLoop loop;
     storage()->FindRegistrationForDocument(
-        document_url, MakeFindCallback(&was_called, &result, registration));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        document_url, base::BindOnce(&FindCallback, loop.QuitClosure(), &result,
+                                     registration));
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode FindRegistrationForScope(
       const GURL& scope,
       scoped_refptr<ServiceWorkerRegistration>* registration) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
+    base::RunLoop loop;
     storage()->FindRegistrationForScope(
-        scope, MakeFindCallback(&was_called, &result, registration));
-    EXPECT_FALSE(was_called);  // always async
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        scope, base::BindOnce(&FindCallback, loop.QuitClosure(), &result,
+                              registration));
+    EXPECT_FALSE(result);  // always async
+    loop.Run();
     return result.value();
   }
 
@@ -558,41 +499,79 @@
       int64_t registration_id,
       const GURL& origin,
       scoped_refptr<ServiceWorkerRegistration>* registration) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
+    base::RunLoop loop;
     storage()->FindRegistrationForId(
         registration_id, origin,
-        MakeFindCallback(&was_called, &result, registration));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        base::BindOnce(&FindCallback, loop.QuitClosure(), &result,
+                       registration));
+    loop.Run();
     return result.value();
   }
 
   blink::ServiceWorkerStatusCode FindRegistrationForIdOnly(
       int64_t registration_id,
       scoped_refptr<ServiceWorkerRegistration>* registration) {
-    bool was_called = false;
     base::Optional<blink::ServiceWorkerStatusCode> result;
+    base::RunLoop loop;
     storage()->FindRegistrationForIdOnly(
-        registration_id, MakeFindCallback(&was_called, &result, registration));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(was_called);
+        registration_id, base::BindOnce(&FindCallback, loop.QuitClosure(),
+                                        &result, registration));
+    loop.Run();
     return result.value();
   }
 
+  base::circular_deque<int64_t> GetPurgingResources() {
+    return storage()->purgeable_resource_ids_;
+  }
+
   // Directly writes a registration using
   // ServiceWorkerDatabase::WriteRegistration rather than
   // ServiceWorkerStorage::StoreRegistration. Useful for simulating a
   // registration written by an earlier version of Chrome.
-  void WriteRegistration(const RegistrationData& registration,
-                         const std::vector<ResourceRecord>& resources) {
-    RegistrationData deleted_version;
-    std::vector<int64_t> newly_purgeable_resources;
+  void WriteRegistrationToDB(const RegistrationData& registration,
+                             const std::vector<ResourceRecord>& resources) {
+    ServiceWorkerDatabase* database_raw = database();
+    base::RunLoop loop;
+    storage()->database_task_runner_->PostTask(
+        FROM_HERE, base::BindLambdaForTesting([&]() {
+          RegistrationData deleted_version;
+          std::vector<int64_t> newly_purgeable_resources;
+          ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
+                    database_raw->WriteRegistration(
+                        registration, resources, &deleted_version,
+                        &newly_purgeable_resources));
+          loop.Quit();
+        }));
+    loop.Run();
+  }
 
-    ASSERT_EQ(
-        ServiceWorkerDatabase::STATUS_OK,
-        database()->WriteRegistration(registration, resources, &deleted_version,
-                                      &newly_purgeable_resources));
+  std::set<int64_t> GetPurgeableResourceIdsFromDB() {
+    std::set<int64_t> ids;
+    base::RunLoop loop;
+    ServiceWorkerDatabase* database_raw = database();
+    storage()->database_task_runner_->PostTask(
+        FROM_HERE, base::BindLambdaForTesting([&]() {
+          EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+                    database_raw->GetPurgeableResourceIds(&ids));
+          loop.Quit();
+        }));
+    loop.Run();
+    return ids;
+  }
+
+  std::set<int64_t> GetUncommittedResourceIdsFromDB() {
+    std::set<int64_t> ids;
+    base::RunLoop loop;
+    ServiceWorkerDatabase* database_raw = database();
+    storage()->database_task_runner_->PostTask(
+        FROM_HERE, base::BindLambdaForTesting([&]() {
+          EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+                    database_raw->GetUncommittedResourceIds(&ids));
+          loop.Quit();
+        }));
+    loop.Run();
+    return ids;
   }
 
   // user_data_directory_ must be declared first to preserve destructor order.
@@ -1246,10 +1225,8 @@
     // Add the resources ids to the uncommitted list.
     storage()->StoreUncommittedResourceId(resource_id1_);
     storage()->StoreUncommittedResourceId(resource_id2_);
-    base::RunLoop().RunUntilIdle();
-    std::set<int64_t> verify_ids;
-    EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-              database()->GetUncommittedResourceIds(&verify_ids));
+
+    std::set<int64_t> verify_ids = GetUncommittedResourceIdsFromDB();
     EXPECT_EQ(2u, verify_ids.size());
 
     // And dump something in the disk cache for them.
@@ -1263,9 +1240,7 @@
     EXPECT_EQ(
         blink::ServiceWorkerStatusCode::kOk,
         StoreRegistration(registration_, registration_->waiting_version()));
-    verify_ids.clear();
-    EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-              database()->GetUncommittedResourceIds(&verify_ids));
+    verify_ids = GetUncommittedResourceIdsFromDB();
     EXPECT_TRUE(verify_ids.empty());
   }
 
@@ -1352,67 +1327,40 @@
 }
 
 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) {
-  bool was_called = false;
-  blink::ServiceWorkerStatusCode result =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
-  std::set<int64_t> verify_ids;
-
   registration_->SetWaitingVersion(nullptr);
 
   // Deleting the registration should result in the resources being added to the
   // purgeable list and then doomed in the disk cache and removed from that
   // list.
-  storage()->DeleteRegistration(
-      registration_, scope_.GetOrigin(),
-      base::BindOnce(&VerifyPurgeableListStatusCallback,
-                     base::Unretained(database()), &verify_ids, &was_called,
-                     &result));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(was_called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, result);
-  EXPECT_EQ(2u, verify_ids.size());
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_TRUE(verify_ids.empty());
+  base::RunLoop loop;
+  storage()->SetPurgingCompleteCallbackForTest(loop.QuitClosure());
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            DeleteRegistration(registration_, scope_.GetOrigin()));
+  EXPECT_EQ(2u, GetPurgeableResourceIdsFromDB().size());
+  loop.Run();
 
+  EXPECT_TRUE(GetPurgeableResourceIdsFromDB().empty());
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
 }
 
 TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_WaitingVersion) {
-  bool was_called = false;
-  blink::ServiceWorkerStatusCode result =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
-  std::set<int64_t> verify_ids;
-
   // Deleting the registration should result in the resources being added to the
   // purgeable list and then doomed in the disk cache and removed from that
   // list.
-  storage()->DeleteRegistration(
-      registration_, scope_.GetOrigin(),
-      base::BindOnce(&VerifyPurgeableListStatusCallback,
-                     base::Unretained(database()), &verify_ids, &was_called,
-                     &result));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(was_called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, result);
-  EXPECT_EQ(2u, verify_ids.size());
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_EQ(2u, verify_ids.size());
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            DeleteRegistration(registration_, scope_.GetOrigin()));
+  EXPECT_EQ(2u, GetPurgeableResourceIdsFromDB().size());
 
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
 
   // Doom the version. The resources should be purged.
+  base::RunLoop loop;
+  storage()->SetPurgingCompleteCallbackForTest(loop.QuitClosure());
   registration_->waiting_version()->Doom();
-  base::RunLoop().RunUntilIdle();
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_TRUE(verify_ids.empty());
+  loop.Run();
+  EXPECT_TRUE(GetPurgeableResourceIdsFromDB().empty());
 
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
@@ -1429,39 +1377,22 @@
       context()->AsWeakPtr(), &remote_endpoint);
   registration_->active_version()->AddControllee(host.get());
 
-  bool was_called = false;
-  blink::ServiceWorkerStatusCode result =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
-  std::set<int64_t> verify_ids;
-
   // Deleting the registration should move the resources to the purgeable list
   // but keep them available.
-  storage()->DeleteRegistration(
-      registration_, scope_.GetOrigin(),
-      base::BindOnce(&VerifyPurgeableListStatusCallback,
-                     base::Unretained(database()), &verify_ids, &was_called,
-                     &result));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(was_called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, result);
-  EXPECT_EQ(2u, verify_ids.size());
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_EQ(2u, verify_ids.size());
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            DeleteRegistration(registration_, scope_.GetOrigin()));
+  EXPECT_EQ(2u, GetPurgeableResourceIdsFromDB().size());
 
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
 
   // Dooming the version should cause the resources to be deleted.
+  base::RunLoop loop;
+  storage()->SetPurgingCompleteCallbackForTest(loop.QuitClosure());
   registration_->active_version()->RemoveControllee(host->client_uuid());
   registration_->active_version()->Doom();
-  base::RunLoop().RunUntilIdle();
-
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_TRUE(verify_ids.empty());
+  loop.Run();
+  EXPECT_TRUE(GetPurgeableResourceIdsFromDB().empty());
 
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
@@ -1479,25 +1410,11 @@
       context()->AsWeakPtr(), &remote_endpoint);
   registration_->active_version()->AddControllee(host.get());
 
-  bool was_called = false;
-  blink::ServiceWorkerStatusCode result =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
-  std::set<int64_t> verify_ids;
-
   // Deleting the registration should move the resources to the purgeable list
   // but keep them available.
-  storage()->DeleteRegistration(
-      registration_, scope_.GetOrigin(),
-      base::BindOnce(&VerifyPurgeableListStatusCallback,
-                     base::Unretained(database()), &verify_ids, &was_called,
-                     &result));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(was_called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, result);
-  EXPECT_EQ(2u, verify_ids.size());
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            DeleteRegistration(registration_, scope_.GetOrigin()));
+  std::set<int64_t> verify_ids = GetPurgeableResourceIdsFromDB();
   EXPECT_EQ(2u, verify_ids.size());
 
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
@@ -1506,10 +1423,7 @@
   // Also add an uncommitted resource.
   int64_t kStaleUncommittedResourceId = storage()->NewResourceId();
   storage()->StoreUncommittedResourceId(kStaleUncommittedResourceId);
-  base::RunLoop().RunUntilIdle();
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetUncommittedResourceIds(&verify_ids));
+  verify_ids = GetUncommittedResourceIdsFromDB();
   EXPECT_EQ(1u, verify_ids.size());
   WriteBasicResponse(storage(), kStaleUncommittedResourceId);
   EXPECT_TRUE(
@@ -1521,26 +1435,19 @@
   LazyInitialize();
 
   // Store a new uncommitted resource. This triggers stale resource cleanup.
+  base::RunLoop loop;
+  storage()->SetPurgingCompleteCallbackForTest(loop.QuitClosure());
   int64_t kNewResourceId = storage()->NewResourceId();
   WriteBasicResponse(storage(), kNewResourceId);
   storage()->StoreUncommittedResourceId(kNewResourceId);
-  base::RunLoop().RunUntilIdle();
+  loop.Run();
 
   // The stale resources should be purged, but the new resource should persist.
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetUncommittedResourceIds(&verify_ids));
+  verify_ids = GetUncommittedResourceIdsFromDB();
   ASSERT_EQ(1u, verify_ids.size());
   EXPECT_EQ(kNewResourceId, *verify_ids.begin());
 
-  // Purging resources needs interactions with SimpleCache's worker thread,
-  // so single RunUntilIdle() call may not be sufficient.
-  while (storage()->is_purge_pending_)
-    base::RunLoop().RunUntilIdle();
-
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
+  verify_ids = GetPurgeableResourceIdsFromDB();
   EXPECT_TRUE(verify_ids.empty());
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
@@ -1555,13 +1462,12 @@
   ASSERT_TRUE(base::DirectoryExists(storage()->GetDatabasePath()));
 
   base::RunLoop run_loop;
-  blink::ServiceWorkerStatusCode status =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
+  base::Optional<blink::ServiceWorkerStatusCode> status;
   storage()->DeleteAndStartOver(
-      base::BindOnce(&StatusAndQuitCallback, &status, run_loop.QuitClosure()));
+      base::BindOnce(&StatusCallback, run_loop.QuitClosure(), &status));
   run_loop.Run();
 
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, *status);
   EXPECT_TRUE(storage()->IsDisabled());
   EXPECT_FALSE(base::DirectoryExists(storage()->GetDiskCachePath()));
   EXPECT_FALSE(base::DirectoryExists(storage()->GetDatabasePath()));
@@ -1581,13 +1487,12 @@
   ASSERT_TRUE(base::PathExists(file_path));
 
   base::RunLoop run_loop;
-  blink::ServiceWorkerStatusCode status =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
+  base::Optional<blink::ServiceWorkerStatusCode> status;
   storage()->DeleteAndStartOver(
-      base::BindOnce(&StatusAndQuitCallback, &status, run_loop.QuitClosure()));
+      base::BindOnce(&StatusCallback, run_loop.QuitClosure(), &status));
   run_loop.Run();
 
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, *status);
   EXPECT_TRUE(storage()->IsDisabled());
   EXPECT_FALSE(base::DirectoryExists(storage()->GetDiskCachePath()));
   EXPECT_FALSE(base::DirectoryExists(storage()->GetDatabasePath()));
@@ -1608,20 +1513,19 @@
   ASSERT_TRUE(base::PathExists(file_path));
 
   base::RunLoop run_loop;
-  blink::ServiceWorkerStatusCode status =
-      blink::ServiceWorkerStatusCode::kErrorNotFound;
+  base::Optional<blink::ServiceWorkerStatusCode> status;
   storage()->DeleteAndStartOver(
-      base::BindOnce(&StatusAndQuitCallback, &status, run_loop.QuitClosure()));
+      base::BindOnce(&StatusCallback, run_loop.QuitClosure(), &status));
   run_loop.Run();
 
 #if defined(OS_WIN)
   // On Windows, deleting the directory containing an opened file should fail.
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorFailed, status);
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorFailed, *status);
   EXPECT_TRUE(storage()->IsDisabled());
   EXPECT_TRUE(base::DirectoryExists(storage()->GetDiskCachePath()));
   EXPECT_TRUE(base::DirectoryExists(storage()->GetDatabasePath()));
 #else
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, *status);
   EXPECT_TRUE(storage()->IsDisabled());
   EXPECT_FALSE(base::DirectoryExists(storage()->GetDiskCachePath()));
   EXPECT_FALSE(base::DirectoryExists(storage()->GetDatabasePath()));
@@ -1639,11 +1543,6 @@
       helper_->context()->AsWeakPtr(), &remote_endpoint);
   registration_->active_version()->AddControllee(host.get());
 
-  bool was_called = false;
-  blink::ServiceWorkerStatusCode result =
-      blink::ServiceWorkerStatusCode::kErrorFailed;
-  std::set<int64_t> verify_ids;
-
   // Make an updated registration.
   scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
       registration_.get(), script_, blink::mojom::ScriptType::kClassic,
@@ -1658,25 +1557,19 @@
 
   // Writing the registration should move the old version's resources to the
   // purgeable list but keep them available.
-  storage()->StoreRegistration(
-      registration_.get(), registration_->waiting_version(),
-      base::BindOnce(&VerifyPurgeableListStatusCallback,
-                     base::Unretained(database()), &verify_ids, &was_called,
-                     &result));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(was_called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, result);
-  EXPECT_EQ(2u, verify_ids.size());
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_EQ(2u, verify_ids.size());
+  EXPECT_EQ(
+      blink::ServiceWorkerStatusCode::kOk,
+      StoreRegistration(registration_.get(), registration_->waiting_version()));
+  EXPECT_EQ(2u, GetPurgeableResourceIdsFromDB().size());
+  EXPECT_TRUE(GetPurgingResources().empty());
 
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
 
   // Remove the controllee to allow the new version to become active, making the
   // old version redundant.
+  base::RunLoop loop;
+  storage()->SetPurgingCompleteCallbackForTest(loop.QuitClosure());
   scoped_refptr<ServiceWorkerVersion> old_version(
       registration_->active_version());
   old_version->RemoveControllee(host->client_uuid());
@@ -1684,12 +1577,8 @@
   EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
 
   // Its resources should be purged.
-  base::RunLoop().RunUntilIdle();
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_TRUE(verify_ids.empty());
-
+  loop.Run();
+  EXPECT_TRUE(GetPurgeableResourceIdsFromDB().empty());
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
 }
@@ -1716,26 +1605,16 @@
 
   // Writing the registration should purge the old version's resources,
   // since it's not live.
-  std::set<int64_t> verify_ids;
-  bool was_called = false;
-  auto result = blink::ServiceWorkerStatusCode::kErrorFailed;
-  storage()->StoreRegistration(
-      registration_.get(), registration_->waiting_version(),
-      base::BindOnce(&VerifyPurgeableListStatusCallback,
-                     base::Unretained(database()), &verify_ids, &was_called,
-                     &result));
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop loop;
+  storage()->SetPurgingCompleteCallbackForTest(loop.QuitClosure());
+  EXPECT_EQ(
+      blink::ServiceWorkerStatusCode::kOk,
+      StoreRegistration(registration_.get(), registration_->waiting_version()));
+  EXPECT_EQ(2u, GetPurgeableResourceIdsFromDB().size());
 
-  // The StoreRegistration callback was called with the purgeable list.
-  ASSERT_TRUE(was_called);
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, result);
-  EXPECT_EQ(2u, verify_ids.size());
-
-  // The resources have already been purged.
-  verify_ids.clear();
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database()->GetPurgeableResourceIds(&verify_ids));
-  EXPECT_TRUE(verify_ids.empty());
+  // The resources should be purged.
+  loop.Run();
+  EXPECT_TRUE(GetPurgeableResourceIdsFromDB().empty());
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
   EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
 }
@@ -1822,7 +1701,7 @@
   // Don't set origin_trial_tokens to simulate old database entry.
   std::vector<ResourceRecord> resources1;
   resources1.push_back(ResourceRecord(1, data1.script, 100));
-  WriteRegistration(data1, resources1);
+  WriteRegistrationToDB(data1, resources1);
 
   const GURL origin2("http://www2.example.com");
   const GURL scope2("http://www2.example.com/foo/");
@@ -1837,7 +1716,7 @@
   data2.origin_trial_tokens = blink::TrialTokenValidator::FeatureToTokensMap();
   std::vector<ResourceRecord> resources2;
   resources2.push_back(ResourceRecord(2, data2.script, 200));
-  WriteRegistration(data2, resources2);
+  WriteRegistrationToDB(data2, resources2);
 
   scoped_refptr<ServiceWorkerRegistration> found_registration;
 
@@ -1998,7 +1877,7 @@
   // Don't set navigation preload state to simulate old database entry.
   std::vector<ResourceRecord> resources1;
   resources1.push_back(ResourceRecord(1, data1.script, 100));
-  WriteRegistration(data1, resources1);
+  WriteRegistrationToDB(data1, resources1);
 
   scoped_refptr<ServiceWorkerRegistration> found_registration;
   EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 4b61841..dee467e 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -109,6 +109,7 @@
 #include "ipc/constants.mojom.h"
 #include "ipc/ipc_security_test_util.h"
 #include "media/base/media_switches.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -6201,10 +6202,10 @@
     params->routing_id = frame_routing_id;
     params->interface_bundle = mojom::DocumentScopedInterfaceBundle::New();
     mojo::MakeRequest(&params->interface_bundle->interface_provider);
-    mojo::MakeRequest(
-        &params->interface_bundle->document_interface_broker_content);
-    mojo::MakeRequest(
-        &params->interface_bundle->document_interface_broker_blink);
+    ignore_result(params->interface_bundle->document_interface_broker_content
+                      .InitWithNewPipeAndPassReceiver());
+    ignore_result(params->interface_bundle->document_interface_broker_blink
+                      .InitWithNewPipeAndPassReceiver());
     ignore_result(params->interface_bundle->browser_interface_broker
                       .InitWithNewPipeAndPassReceiver());
     params->previous_routing_id = previous_routing_id;
@@ -6273,10 +6274,10 @@
     params->routing_id = frame_routing_id;
     params->interface_bundle = mojom::DocumentScopedInterfaceBundle::New();
     mojo::MakeRequest(&params->interface_bundle->interface_provider);
-    mojo::MakeRequest(
-        &params->interface_bundle->document_interface_broker_content);
-    mojo::MakeRequest(
-        &params->interface_bundle->document_interface_broker_blink);
+    ignore_result(params->interface_bundle->document_interface_broker_content
+                      .InitWithNewPipeAndPassReceiver());
+    ignore_result(params->interface_bundle->document_interface_broker_blink
+                      .InitWithNewPipeAndPassReceiver());
     ignore_result(params->interface_bundle->browser_interface_broker
                       .InitWithNewPipeAndPassReceiver());
     params->previous_routing_id = IPC::mojom::kRoutingIdNone;
@@ -14426,16 +14427,15 @@
 
   // Simulate a commit IPC.
   service_manager::mojom::InterfaceProviderPtr interface_provider;
-  blink::mojom::DocumentInterfaceBrokerPtrInfo
-      document_interface_broker_content;
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker_blink;
   static_cast<mojom::FrameHost*>(root->current_frame_host())
       ->DidCommitProvisionalLoad(
           std::move(params),
           mojom::DidCommitProvisionalLoadInterfaceParams::New(
               mojo::MakeRequest(&interface_provider),
-              mojo::MakeRequest(&document_interface_broker_content),
-              mojo::MakeRequest(&document_interface_broker_blink),
+              mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+                  .InitWithNewPipeAndPassReceiver(),
+              mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+                  .InitWithNewPipeAndPassReceiver(),
               mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
                   .InitWithNewPipeAndPassReceiver()));
 
diff --git a/content/browser/speech/tts_android.cc b/content/browser/speech/tts_android.cc
index 0c6c2a6..7dc3e23 100644
--- a/content/browser/speech/tts_android.cc
+++ b/content/browser/speech/tts_android.cc
@@ -109,6 +109,11 @@
   }
 }
 
+void TtsPlatformImplAndroid::RequestTtsStop(JNIEnv* env,
+                                            const JavaParamRef<jobject>& obj) {
+  TtsController::GetInstance()->Stop();
+}
+
 void TtsPlatformImplAndroid::VoicesChanged(JNIEnv* env,
                                            const JavaParamRef<jobject>& obj) {
   TtsController::GetInstance()->VoicesChanged();
diff --git a/content/browser/speech/tts_android.h b/content/browser/speech/tts_android.h
index 544aad08..bb2c05e 100644
--- a/content/browser/speech/tts_android.h
+++ b/content/browser/speech/tts_android.h
@@ -28,6 +28,8 @@
   void GetVoices(std::vector<VoiceData>* out_voices) override;
 
   // Methods called from Java via JNI.
+  void RequestTtsStop(JNIEnv* env,
+                      const base::android::JavaParamRef<jobject>& obj);
   void VoicesChanged(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& obj);
   void OnEndEvent(JNIEnv* env,
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 37cfd36..c626801 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -359,13 +359,14 @@
     switch (warning) {
       case net::CanonicalCookie::CookieInclusionStatus::
           WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT:
+      case net::CanonicalCookie::CookieInclusionStatus::
+          WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE:
         samesite_treated_as_lax_cookies = true;
         break;
       case net::CanonicalCookie::CookieInclusionStatus::
           WARN_SAMESITE_NONE_INSECURE:
         samesite_none_insecure_cookies = true;
         break;
-      // TODO(crbug.com/990439): Add messages for Lax-Allow-Unsafe intervention.
       default:
         break;
     }
@@ -375,6 +376,8 @@
     }
   }
 
+  // TODO(crbug.com/990439): Do we need separate UseCounter metrics for
+  // Lax-allow-unsafe? We already have histograms in CanonicalCookie.
   if (samesite_treated_as_lax_cookies) {
     GetContentClient()->browser()->LogWebFeatureForCurrentPage(
         frame, blink::mojom::WebFeature::kCookieNoSameSite);
@@ -1109,7 +1112,6 @@
       relative_partition_path_(relative_partition_path),
       partition_domain_(partition_domain),
       special_storage_policy_(special_storage_policy),
-      network_context_client_binding_(this),
       deletion_helpers_running_(0) {}
 
 StoragePartitionImpl::~StoragePartitionImpl() {
@@ -2279,10 +2281,9 @@
       browser_context_, is_in_memory_, relative_partition_path_);
   DCHECK(network_context_);
 
-  network::mojom::NetworkContextClientPtr client_ptr;
-  network_context_client_binding_.Close();
-  network_context_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
-  network_context_->SetClient(std::move(client_ptr));
+  network_context_client_receiver_.reset();
+  network_context_->SetClient(
+      network_context_client_receiver_.BindNewPipeAndPassRemote());
   network_context_.set_connection_error_handler(base::BindOnce(
       &StoragePartitionImpl::InitNetworkContext, weak_factory_.GetWeakPtr()));
 }
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index b716567..5f8bcfb0 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -38,6 +38,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/public/mojom/network_context.mojom.h"
@@ -463,8 +464,8 @@
   // by |network_context_owner_|.
   network::mojom::NetworkContextPtr network_context_;
 
-  mojo::Binding<network::mojom::NetworkContextClient>
-      network_context_client_binding_;
+  mojo::Receiver<network::mojom::NetworkContextClient>
+      network_context_client_receiver_{this};
 
   scoped_refptr<URLLoaderFactoryForBrowserProcess>
       shared_url_loader_factory_for_browser_process_;
diff --git a/content/browser/web_package/bundled_exchanges_browsertest.cc b/content/browser/web_package/bundled_exchanges_browsertest.cc
new file mode 100644
index 0000000..982d0db
--- /dev/null
+++ b/content/browser/web_package/bundled_exchanges_browsertest.cc
@@ -0,0 +1,84 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
+#include "net/base/filename_util.h"
+
+namespace content {
+namespace {
+
+class TestBrowserClient : public ContentBrowserClient {
+ public:
+  TestBrowserClient() = default;
+  ~TestBrowserClient() override = default;
+  bool CanAcceptUntrustedExchangesIfNeeded() override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestBrowserClient);
+};
+
+}  // namespace
+
+class BundledExchangesTrustableFileBrowserTest : public ContentBrowserTest {
+ protected:
+  BundledExchangesTrustableFileBrowserTest()
+      : test_data_path_(GetTestDataPath()) {}
+  ~BundledExchangesTrustableFileBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    original_client_ = SetBrowserClientForTesting(&browser_client_);
+    ContentBrowserTest::SetUpOnMainThread();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitchPath(switches::kTrustableBundledExchangesFile,
+                                   test_data_path());
+  }
+
+  void TearDownOnMainThread() override {
+    ContentBrowserTest::TearDownOnMainThread();
+    if (original_client_)
+      SetBrowserClientForTesting(original_client_);
+  }
+
+  const base::FilePath& test_data_path() const { return test_data_path_; }
+
+ private:
+  base::FilePath GetTestDataPath() {
+    base::FilePath test_data_dir;
+    CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+    return test_data_dir.AppendASCII("services")
+        .AppendASCII("test")
+        .AppendASCII("data")
+        .AppendASCII("bundled_exchanges")
+        .AppendASCII("hello.wbn");
+  }
+
+  TestBrowserClient browser_client_;
+  ContentBrowserClient* original_client_;
+  const base::FilePath test_data_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(BundledExchangesTrustableFileBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(BundledExchangesTrustableFileBrowserTest,
+                       TrustableBundledExchangesFile) {
+  base::string16 expected_title = base::ASCIIToUTF16("Done");
+  TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+  EXPECT_TRUE(NavigateToURL(shell()->web_contents(),
+                            net::FilePathToFileURL(test_data_path()),
+                            GURL("https://test.example.org/")));
+  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+}
+
+}  // namespace content
diff --git a/content/browser/web_package/bundled_exchanges_handle.h b/content/browser/web_package/bundled_exchanges_handle.h
index e0a08a98..baf53ad 100644
--- a/content/browser/web_package/bundled_exchanges_handle.h
+++ b/content/browser/web_package/bundled_exchanges_handle.h
@@ -26,8 +26,6 @@
 
 // A class to provide interfaces to communicate with a BundledExchanges for
 // loading. Running on the UI thread.
-// TODO(crbug.com/966753): Add browser tests once core parts are submitted and
-// basic sequence can pass.
 class BundledExchangesHandle final {
  public:
   BundledExchangesHandle();
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 52a850f..ee1860ef 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -102,6 +102,14 @@
     // Attempt to notify the worker before disconnecting.
     if (worker_)
       worker_->Terminate();
+
+    // Notify the service that each client still connected will be removed and
+    // that the worker will terminate.
+    for (const auto& client : clients_) {
+      service_->NotifyClientRemoved(instance_, client.client_process_id,
+                                    client.frame_id);
+    }
+    service_->NotifyWorkerTerminating(instance_);
   } else {
     // Tell clients that this worker failed to start.
     for (const ClientInfo& info : clients_)
@@ -237,6 +245,15 @@
   // Monitor the lifetime of the worker.
   worker_.set_disconnect_handler(base::BindOnce(
       &SharedWorkerHost::OnWorkerConnectionLost, weak_factory_.GetWeakPtr()));
+
+  // Notify the service that the worker was started and that some clients were
+  // already connected.
+  service_->NotifyWorkerStarted(instance_, worker_process_id_,
+                                devtools_worker_token);
+  for (const auto& client : clients_) {
+    service_->NotifyClientAdded(instance_, client.client_process_id,
+                                client.frame_id);
+  }
 }
 
 //  This is similar to
@@ -425,6 +442,12 @@
       &SharedWorkerHost::OnClientConnectionLost, weak_factory_.GetWeakPtr()));
 
   worker_->Connect(info.connection_request_id, port.ReleaseHandle());
+
+  // Notify that a new client was added now. If the worker is not started, the
+  // Start() function will handle sending a notification for each existing
+  // client.
+  if (started_)
+    service_->NotifyClientAdded(instance_, client_process_id, frame_id);
 }
 
 void SharedWorkerHost::SetAppCacheHandle(
@@ -456,6 +479,12 @@
   // We'll get a notification for each dropped connection.
   for (auto it = clients_.begin(); it != clients_.end(); ++it) {
     if (!it->client.is_connected()) {
+      // Notify the service that a client was removed while the worker was
+      // running.
+      if (started_) {
+        service_->NotifyClientRemoved(instance_, it->client_process_id,
+                                      it->frame_id);
+      }
       clients_.erase(it);
       break;
     }
diff --git a/content/browser/worker_host/shared_worker_host.h b/content/browser/worker_host/shared_worker_host.h
index c94de24..1cb5ccfd 100644
--- a/content/browser/worker_host/shared_worker_host.h
+++ b/content/browser/worker_host/shared_worker_host.h
@@ -16,10 +16,10 @@
 #include "base/strings/string16.h"
 #include "base/unguessable_token.h"
 #include "content/browser/browser_interface_broker_impl.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/shared_worker_instance.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index 38997bc..97a0f1e 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -17,8 +17,8 @@
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/browser/worker_host/mock_shared_worker.h"
 #include "content/browser/worker_host/shared_worker_connector_impl.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/browser/worker_host/shared_worker_service_impl.h"
+#include "content/public/browser/shared_worker_instance.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_context.h"
diff --git a/content/browser/worker_host/shared_worker_instance_unittest.cc b/content/browser/worker_host/shared_worker_instance_unittest.cc
index 657cb8b..92dbd7c 100644
--- a/content/browser/worker_host/shared_worker_instance_unittest.cc
+++ b/content/browser/worker_host/shared_worker_instance_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/worker_host/shared_worker_instance.h"
+#include "content/public/browser/shared_worker_instance.h"
 
 #include <memory>
 
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index 059e9af..1c2a28b 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -23,7 +23,6 @@
 #include "content/browser/url_loader_factory_getter.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/worker_host/shared_worker_host.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/browser/worker_host/worker_script_fetch_initiator.h"
 #include "content/common/content_constants_internal.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -31,6 +30,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/shared_worker_instance.h"
 #include "content/public/common/bind_interface_helpers.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -67,6 +67,14 @@
   worker_hosts_.clear();
 }
 
+void SharedWorkerServiceImpl::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void SharedWorkerServiceImpl::RemoveObserver(const Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 bool SharedWorkerServiceImpl::TerminateWorker(
     const GURL& url,
     const std::string& name,
@@ -79,6 +87,7 @@
     DestroyHost(worker_host);
     return true;
   }
+
   return false;
 }
 
@@ -169,9 +178,40 @@
 
 void SharedWorkerServiceImpl::DestroyHost(SharedWorkerHost* host) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   worker_hosts_.erase(worker_hosts_.find(host));
 }
 
+void SharedWorkerServiceImpl::NotifyWorkerStarted(
+    const SharedWorkerInstance& instance,
+    int worker_process_id,
+    const base::UnguessableToken& dev_tools_token) {
+  for (Observer& observer : observers_)
+    observer.OnWorkerStarted(instance, worker_process_id, dev_tools_token);
+}
+
+void SharedWorkerServiceImpl::NotifyWorkerTerminating(
+    const SharedWorkerInstance& instance) {
+  for (Observer& observer : observers_)
+    observer.OnBeforeWorkerTerminated(instance);
+}
+
+void SharedWorkerServiceImpl::NotifyClientAdded(
+    const SharedWorkerInstance& instance,
+    int client_process_id,
+    int frame_id) {
+  for (Observer& observer : observers_)
+    observer.OnClientAdded(instance, client_process_id, frame_id);
+}
+
+void SharedWorkerServiceImpl::NotifyClientRemoved(
+    const SharedWorkerInstance& instance,
+    int client_process_id,
+    int frame_id) {
+  for (Observer& observer : observers_)
+    observer.OnClientRemoved(instance, client_process_id, frame_id);
+}
+
 void SharedWorkerServiceImpl::CreateWorker(
     const SharedWorkerInstance& instance,
     blink::mojom::FetchClientSettingsObjectPtr
diff --git a/content/browser/worker_host/shared_worker_service_impl.h b/content/browser/worker_host/shared_worker_service_impl.h
index f6352e8..d1f0234 100644
--- a/content/browser/worker_host/shared_worker_service_impl.h
+++ b/content/browser/worker_host/shared_worker_service_impl.h
@@ -13,6 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/worker_host/shared_worker_host.h"
 #include "content/public/browser/shared_worker_service.h"
@@ -48,6 +49,8 @@
   ~SharedWorkerServiceImpl() override;
 
   // SharedWorkerService implementation.
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(const Observer* observer) override;
   bool TerminateWorker(const GURL& url,
                        const std::string& name,
                        const url::Origin& constructor_origin) override;
@@ -72,6 +75,17 @@
   // Virtual for testing.
   virtual void DestroyHost(SharedWorkerHost* host);
 
+  void NotifyWorkerStarted(const SharedWorkerInstance& instance,
+                           int worker_process_id,
+                           const base::UnguessableToken& dev_tools_token);
+  void NotifyWorkerTerminating(const SharedWorkerInstance& instance);
+  void NotifyClientAdded(const SharedWorkerInstance& instance,
+                         int client_process_id,
+                         int frame_id);
+  void NotifyClientRemoved(const SharedWorkerInstance& instance,
+                           int client_process_id,
+                           int frame_id);
+
   StoragePartitionImpl* storage_partition() { return storage_partition_; }
 
  private:
@@ -137,6 +151,8 @@
   scoped_refptr<ChromeAppCacheService> appcache_service_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override_;
 
+  base::ObserverList<Observer> observers_;
+
   base::WeakPtrFactory<SharedWorkerServiceImpl> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImpl);
diff --git a/content/browser/worker_host/shared_worker_service_impl_unittest.cc b/content/browser/worker_host/shared_worker_service_impl_unittest.cc
index b7dfa38..43083a7 100644
--- a/content/browser/worker_host/shared_worker_service_impl_unittest.cc
+++ b/content/browser/worker_host/shared_worker_service_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/scoped_observer.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/worker_host/mock_shared_worker.h"
 #include "content/browser/worker_host/shared_worker_connector_impl.h"
@@ -1227,4 +1228,108 @@
   EXPECT_TRUE(worker.CheckReceivedTerminate());
 }
 
+class TestSharedWorkerServiceObserver : public SharedWorkerService::Observer {
+ public:
+  TestSharedWorkerServiceObserver() = default;
+  ~TestSharedWorkerServiceObserver() override = default;
+
+  // SharedWorkerService::Observer:
+  void OnWorkerStarted(const SharedWorkerInstance& instance,
+                       int worker_process_id,
+                       const base::UnguessableToken& dev_tools_token) override {
+    EXPECT_TRUE(running_workers_.insert({instance, {}}).second);
+  }
+  void OnBeforeWorkerTerminated(const SharedWorkerInstance& instance) override {
+    EXPECT_EQ(1u, running_workers_.erase(instance));
+  }
+  void OnClientAdded(const SharedWorkerInstance& instance,
+                     int client_process_id,
+                     int frame_id) override {
+    auto it = running_workers_.find(instance);
+    EXPECT_TRUE(it != running_workers_.end());
+    std::set<ClientInfo>& clients = it->second;
+    EXPECT_TRUE(clients.insert({client_process_id, frame_id}).second);
+  }
+  void OnClientRemoved(const SharedWorkerInstance& instance,
+                       int client_process_id,
+                       int frame_id) override {
+    auto it = running_workers_.find(instance);
+    EXPECT_TRUE(it != running_workers_.end());
+    std::set<ClientInfo>& clients = it->second;
+    EXPECT_EQ(1u, clients.erase({client_process_id, frame_id}));
+  }
+
+  size_t GetWorkerCount() { return running_workers_.size(); }
+
+  size_t GetClientCount() {
+    size_t client_count = 0;
+    for (const auto& worker : running_workers_)
+      client_count += worker.second.size();
+    return client_count;
+  }
+
+ private:
+  using ClientInfo = std::pair<int, int>;
+
+  base::flat_map<SharedWorkerInstance, std::set<ClientInfo>> running_workers_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSharedWorkerServiceObserver);
+};
+
+TEST_F(SharedWorkerServiceImplTest, Observer) {
+  TestSharedWorkerServiceObserver observer;
+
+  ScopedObserver<SharedWorkerService, SharedWorkerService::Observer>
+      scoped_observer(&observer);
+  scoped_observer.Add(content::BrowserContext::GetDefaultStoragePartition(
+                          browser_context_.get())
+                          ->GetSharedWorkerService());
+
+  std::unique_ptr<TestWebContents> web_contents =
+      CreateWebContents(GURL("http://example.com/"));
+  TestRenderFrameHost* render_frame_host = web_contents->GetMainFrame();
+  MockRenderProcessHost* renderer_host = render_frame_host->GetProcess();
+  const int process_id = renderer_host->GetID();
+  renderer_host->OverrideBinderForTesting(
+      blink::mojom::SharedWorkerFactory::Name_,
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id));
+
+  MockSharedWorkerClient client;
+  MessagePortChannel local_port;
+  const GURL kUrl("http://example.com/w.js");
+  ConnectToSharedWorker(MakeSharedWorkerConnector(
+                            renderer_host, render_frame_host->GetRoutingID()),
+                        kUrl, "name", &client, &local_port);
+
+  mojo::PendingReceiver<blink::mojom::SharedWorkerFactory> factory_receiver =
+      WaitForFactoryReceiver(process_id);
+  MockSharedWorkerFactory factory(std::move(factory_receiver));
+  base::RunLoop().RunUntilIdle();
+
+  mojo::Remote<blink::mojom::SharedWorkerHost> worker_host;
+  mojo::PendingReceiver<blink::mojom::SharedWorker> worker_receiver;
+  EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
+      kUrl, "name", blink::mojom::ContentSecurityPolicyType::kReport,
+      &worker_host, &worker_receiver));
+  MockSharedWorker worker(std::move(worker_receiver));
+  base::RunLoop().RunUntilIdle();
+
+  int connection_request_id;
+  MessagePortChannel port;
+  EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id, &port));
+
+  EXPECT_TRUE(client.CheckReceivedOnCreated());
+
+  EXPECT_EQ(1u, observer.GetWorkerCount());
+  EXPECT_EQ(1u, observer.GetClientCount());
+
+  // Tear down the worker host.
+  worker_host->OnContextClosed();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0u, observer.GetWorkerCount());
+  EXPECT_EQ(0u, observer.GetClientCount());
+}
+
 }  // namespace content
diff --git a/content/common/document_scoped_interface_bundle.mojom b/content/common/document_scoped_interface_bundle.mojom
index 5305d879..63f816b9 100644
--- a/content/common/document_scoped_interface_bundle.mojom
+++ b/content/common/document_scoped_interface_bundle.mojom
@@ -15,8 +15,10 @@
 
   // The DocumentInterfaceBroker through which the RenderFrame can access
   // interfaces exposed by its RenderFrameHost
-  blink.mojom.DocumentInterfaceBroker document_interface_broker_content;
-  blink.mojom.DocumentInterfaceBroker document_interface_broker_blink;
+  pending_remote<blink.mojom.DocumentInterfaceBroker>
+      document_interface_broker_content;
+  pending_remote<blink.mojom.DocumentInterfaceBroker>
+      document_interface_broker_blink;
 
   // The BrowserInterfaceBroker through which the RenderFrame can access
   // interfaces exposed by its RenderFrameHost
diff --git a/content/common/frame_messages.mojom b/content/common/frame_messages.mojom
index 9d45fd7..0ad8ece 100644
--- a/content/common/frame_messages.mojom
+++ b/content/common/frame_messages.mojom
@@ -13,9 +13,10 @@
 
 struct DidCommitProvisionalLoadInterfaceParams {
   service_manager.mojom.InterfaceProvider& interface_provider_request;
-  blink.mojom.DocumentInterfaceBroker&
-      document_interface_broker_content_request;
-  blink.mojom.DocumentInterfaceBroker& document_interface_broker_blink_request;
+  pending_receiver<blink.mojom.DocumentInterfaceBroker>
+      document_interface_broker_content_receiver;
+  pending_receiver<blink.mojom.DocumentInterfaceBroker>
+      document_interface_broker_blink_receiver;
   pending_receiver<blink.mojom.BrowserInterfaceBroker>
       browser_interface_broker_receiver;
 };
diff --git a/content/public/android/java/src/org/chromium/content/browser/TtsPlatformImpl.java b/content/public/android/java/src/org/chromium/content/browser/TtsPlatformImpl.java
index ab8ba7b..033d3f1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/TtsPlatformImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/TtsPlatformImpl.java
@@ -4,10 +4,14 @@
 
 package org.chromium.content.browser;
 
+import android.app.Activity;
 import android.os.Build;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.UtteranceProgressListener;
 
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.ApplicationStatus.ActivityStateListener;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.annotations.CalledByNative;
@@ -32,7 +36,7 @@
  * use PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, ...)  when calling back to C++.
  */
 @JNINamespace("content")
-class TtsPlatformImpl {
+class TtsPlatformImpl implements ActivityStateListener {
     private static class TtsVoice {
         private TtsVoice(String name, String language) {
             mName = name;
@@ -83,6 +87,8 @@
             }
         });
         addOnUtteranceProgressListener();
+
+        ApplicationStatus.registerStateListenerForAllActivities(this);
     }
 
     /**
@@ -106,6 +112,7 @@
      */
     @CalledByNative
     private void destroy() {
+        ApplicationStatus.unregisterActivityStateListener(this);
         mNativeTtsPlatformImplAndroid = 0;
     }
 
@@ -161,6 +168,9 @@
     @CalledByNative
     private boolean speak(
             int utteranceId, String text, String lang, float rate, float pitch, float volume) {
+        // Don't speak when in the background.
+        if (!ApplicationStatus.hasVisibleActivities()) return false;
+
         if (!mInitialized) {
             mPendingUtterance =
                     new PendingUtterance(this, utteranceId, text, lang, rate, pitch, volume);
@@ -318,8 +328,18 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
+    @Override
+    public void onActivityStateChange(Activity activity, @ActivityState int newState) {
+        // Stop speech if all browser windows are no longer visible.
+        if (!ApplicationStatus.hasVisibleActivities()) {
+            TtsPlatformImplJni.get().requestTtsStop(
+                    mNativeTtsPlatformImplAndroid, TtsPlatformImpl.this);
+        }
+    }
+
     @NativeMethods
     interface Natives {
+        void requestTtsStop(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller);
         void voicesChanged(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller);
         void onEndEvent(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller, int utteranceId);
         void onStartEvent(
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 27c2623..acdb1d3c 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -304,6 +304,8 @@
     "session_storage_namespace.h",
     "session_storage_usage_info.h",
     "shared_cors_origin_access_list.h",
+    "shared_worker_instance.cc",
+    "shared_worker_instance.h",
     "shared_worker_service.h",
     "site_instance.h",
     "site_isolation_policy.cc",
diff --git a/content/public/browser/content_index_provider.cc b/content/public/browser/content_index_provider.cc
index da8d7770..4339ff81 100644
--- a/content/public/browser/content_index_provider.cc
+++ b/content/public/browser/content_index_provider.cc
@@ -18,6 +18,14 @@
 
 ContentIndexEntry::ContentIndexEntry(ContentIndexEntry&& other) = default;
 
+ContentIndexEntry& ContentIndexEntry::operator=(ContentIndexEntry&& other) {
+  service_worker_registration_id = other.service_worker_registration_id;
+  description = std::move(other.description);
+  launch_url = std::move(other.launch_url);
+  registration_time = other.registration_time;
+  return *this;
+}
+
 ContentIndexEntry::~ContentIndexEntry() = default;
 
 ContentIndexProvider::ContentIndexProvider() = default;
diff --git a/content/public/browser/content_index_provider.h b/content/public/browser/content_index_provider.h
index 3d5a793..b980beb 100644
--- a/content/public/browser/content_index_provider.h
+++ b/content/public/browser/content_index_provider.h
@@ -29,6 +29,7 @@
                     const GURL& launch_url,
                     base::Time registration_time);
   ContentIndexEntry(ContentIndexEntry&& other);
+  ContentIndexEntry& operator=(ContentIndexEntry&& other);
   ~ContentIndexEntry();
 
   // Part of the key for an entry since different service workers can use the
diff --git a/content/browser/worker_host/shared_worker_instance.cc b/content/public/browser/shared_worker_instance.cc
similarity index 77%
rename from content/browser/worker_host/shared_worker_instance.cc
rename to content/public/browser/shared_worker_instance.cc
index 6c9321a..2d20614 100644
--- a/content/browser/worker_host/shared_worker_instance.cc
+++ b/content/public/browser/shared_worker_instance.cc
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/worker_host/shared_worker_instance.h"
+#include "content/public/browser/shared_worker_instance.h"
+
+#include <tuple>
 
 #include "base/logging.h"
 
@@ -27,6 +29,15 @@
 SharedWorkerInstance::SharedWorkerInstance(const SharedWorkerInstance& other) =
     default;
 
+SharedWorkerInstance::SharedWorkerInstance(SharedWorkerInstance&& other) =
+    default;
+
+SharedWorkerInstance& SharedWorkerInstance::operator=(
+    const SharedWorkerInstance& other) = default;
+
+SharedWorkerInstance& SharedWorkerInstance::operator=(
+    SharedWorkerInstance&& other) = default;
+
 SharedWorkerInstance::~SharedWorkerInstance() = default;
 
 bool SharedWorkerInstance::Matches(
@@ -59,4 +70,13 @@
   return Matches(other.url(), other.name(), other.constructor_origin());
 }
 
+bool operator<(const SharedWorkerInstance& lhs,
+               const SharedWorkerInstance& rhs) {
+  if (lhs.Matches(rhs))
+    return false;
+
+  return std::tie(lhs.url(), lhs.name(), lhs.constructor_origin()) <
+         std::tie(rhs.url(), rhs.name(), rhs.constructor_origin());
+}
+
 }  // namespace content
diff --git a/content/browser/worker_host/shared_worker_instance.h b/content/public/browser/shared_worker_instance.h
similarity index 72%
rename from content/browser/worker_host/shared_worker_instance.h
rename to content/public/browser/shared_worker_instance.h
index c7a7305..49cb4ccb 100644
--- a/content/browser/worker_host/shared_worker_instance.h
+++ b/content/public/browser/shared_worker_instance.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_WORKER_HOST_SHARED_WORKER_INSTANCE_H_
-#define CONTENT_BROWSER_WORKER_HOST_SHARED_WORKER_INSTANCE_H_
+#ifndef CONTENT_PUBLIC_BROWSER_SHARED_WORKER_INSTANCE_H_
+#define CONTENT_PUBLIC_BROWSER_SHARED_WORKER_INSTANCE_H_
 
 #include <string>
 
@@ -16,8 +16,8 @@
 
 namespace content {
 
-// SharedWorkerInstance is copyable value-type data type. It could be passed to
-// the UI thread and be used for comparison in SharedWorkerDevToolsManager.
+// SharedWorkerInstance is a value-type class that is the browser-side
+// representation of one instance of a shared worker.
 class CONTENT_EXPORT SharedWorkerInstance {
  public:
   SharedWorkerInstance(
@@ -29,6 +29,9 @@
       network::mojom::IPAddressSpace creation_address_space,
       blink::mojom::SharedWorkerCreationContextType creation_context_type);
   SharedWorkerInstance(const SharedWorkerInstance& other);
+  SharedWorkerInstance(SharedWorkerInstance&& other);
+  SharedWorkerInstance& operator=(const SharedWorkerInstance& other);
+  SharedWorkerInstance& operator=(SharedWorkerInstance&& other);
   ~SharedWorkerInstance();
 
   // Checks if this SharedWorkerInstance matches the passed url, name, and
@@ -58,20 +61,23 @@
   }
 
  private:
-  const GURL url_;
-  const std::string name_;
+  GURL url_;
+  std::string name_;
 
   // The origin of the document that created this shared worker instance. Used
   // for security checks. See Matches() for details.
   // https://html.spec.whatwg.org/multipage/workers.html#concept-sharedworkerglobalscope-constructor-origin
-  const url::Origin constructor_origin_;
+  url::Origin constructor_origin_;
 
-  const std::string content_security_policy_;
-  const blink::mojom::ContentSecurityPolicyType content_security_policy_type_;
-  const network::mojom::IPAddressSpace creation_address_space_;
-  const blink::mojom::SharedWorkerCreationContextType creation_context_type_;
+  std::string content_security_policy_;
+  blink::mojom::ContentSecurityPolicyType content_security_policy_type_;
+  network::mojom::IPAddressSpace creation_address_space_;
+  blink::mojom::SharedWorkerCreationContextType creation_context_type_;
 };
 
+CONTENT_EXPORT bool operator<(const SharedWorkerInstance& lhs,
+                              const SharedWorkerInstance& rhs);
+
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_WORKER_HOST_SHARED_WORKER_INSTANCE_H_
+#endif  // CONTENT_PUBLIC_BROWSER_SHARED_WORKER_INSTANCE_H_
diff --git a/content/public/browser/shared_worker_service.h b/content/public/browser/shared_worker_service.h
index f36eb14..62bc467f 100644
--- a/content/public/browser/shared_worker_service.h
+++ b/content/public/browser/shared_worker_service.h
@@ -7,17 +7,53 @@
 
 #include <string>
 
+#include "base/observer_list_types.h"
+#include "content/common/content_export.h"
+
+class GURL;
+
 namespace url {
 class Origin;
 }  // namespace url
 
 namespace content {
 
+class SharedWorkerInstance;
+
 // An interface for managing shared workers. These may be run in a separate
 // process, since multiple renderer processes can be talking to a single shared
 // worker. All the methods below can only be called on the UI thread.
 class CONTENT_EXPORT SharedWorkerService {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Called when a shared worker has started/stopped. This means that Start()
+    // was called for that worker and it got assigned its DevTools token. Note
+    // that it may still be evaluating the script and thus it could not be yet
+    // running in the renderer. This differs a bit from the "started" state of
+    // the embedded worker.
+    virtual void OnWorkerStarted(
+        const SharedWorkerInstance& instance,
+        int worker_process_id,
+        const base::UnguessableToken& dev_tools_token) = 0;
+    virtual void OnBeforeWorkerTerminated(
+        const SharedWorkerInstance& instance) = 0;
+
+    // Called when a frame starts/stop being a client of a shared worker. It is
+    // guaranteed that OnWorkerStarted() is called before receiving these
+    // notifications.
+    virtual void OnClientAdded(const SharedWorkerInstance& instance,
+                               int client_process_id,
+                               int frame_id) = 0;
+    virtual void OnClientRemoved(const SharedWorkerInstance& instance,
+                                 int client_process_id,
+                                 int frame_id) = 0;
+  };
+
+  // Adds/removes an observer.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(const Observer* observer) = 0;
+
   // Terminates the given shared worker identified by its name, the URL of
   // its main script resource, and the constructor origin. Returns true on
   // success.
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 815d139..338f176 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -20,6 +20,7 @@
 #include "ipc/ipc_message_utils.h"
 #include "ipc/ipc_sync_message.h"
 #include "ipc/message_filter.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
@@ -285,16 +286,16 @@
   return interface_provider_request;
 }
 
-blink::mojom::DocumentInterfaceBrokerRequest
-MockRenderThread::TakeInitialDocumentInterfaceBrokerRequestForFrame(
+mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+MockRenderThread::TakeInitialDocumentInterfaceBrokerReceiverForFrame(
     int32_t routing_id) {
   auto it =
-      frame_routing_id_to_initial_document_broker_requests_.find(routing_id);
-  if (it == frame_routing_id_to_initial_document_broker_requests_.end())
-    return nullptr;
-  auto document_broker_request = std::move(it->second);
-  frame_routing_id_to_initial_document_broker_requests_.erase(it);
-  return document_broker_request;
+      frame_routing_id_to_initial_document_broker_receivers_.find(routing_id);
+  if (it == frame_routing_id_to_initial_document_broker_receivers_.end())
+    return mojo::NullReceiver();
+  auto document_broker_receiver = std::move(it->second);
+  frame_routing_id_to_initial_document_broker_receivers_.erase(it);
+  return document_broker_receiver;
 }
 
 mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
@@ -331,17 +332,20 @@
   params_reply->new_interface_provider =
       interface_provider.PassInterface().PassHandle().release();
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker;
-  frame_routing_id_to_initial_document_broker_requests_.emplace(
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker;
+  frame_routing_id_to_initial_document_broker_receivers_.emplace(
       params_reply->child_routing_id,
-      mojo::MakeRequest(&document_interface_broker));
+      document_interface_broker.InitWithNewPipeAndPassReceiver());
   params_reply->document_interface_broker_content_handle =
-      document_interface_broker.PassInterface().PassHandle().release();
+      document_interface_broker.PassPipe().release();
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink;
-  mojo::MakeRequest(&document_interface_broker_blink);
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink;
+  ignore_result(
+      document_interface_broker_blink.InitWithNewPipeAndPassReceiver());
   params_reply->document_interface_broker_blink_handle =
-      document_interface_broker_blink.PassInterface().PassHandle().release();
+      document_interface_broker_blink.PassPipe().release();
 
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker;
@@ -397,10 +401,11 @@
       mojo::MakeRequest(
           &reply->main_frame_interface_bundle->interface_provider));
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo document_interface_broker;
-  frame_routing_id_to_initial_document_broker_requests_.emplace(
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker;
+  frame_routing_id_to_initial_document_broker_receivers_.emplace(
       reply->main_frame_route_id,
-      mojo::MakeRequest(&document_interface_broker));
+      document_interface_broker.InitWithNewPipeAndPassReceiver());
 
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker;
@@ -410,7 +415,7 @@
   reply->main_frame_interface_bundle->document_interface_broker_content =
       std::move(document_interface_broker);
 
-  mojo::MakeRequest(&document_interface_broker);
+  ignore_result(document_interface_broker.InitWithNewPipeAndPassReceiver());
   reply->main_frame_interface_bundle->document_interface_broker_blink =
       std::move(document_interface_broker);
 
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index 5b55f5bf..c19dcc0d 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -17,6 +17,7 @@
 #include "content/public/renderer/render_thread.h"
 #include "ipc/ipc_test_sink.h"
 #include "ipc/message_filter.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/service_manager/public/mojom/connector.mojom.h"
 #include "third_party/blink/public/mojom/browser_interface_broker.mojom.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
@@ -120,12 +121,12 @@
   service_manager::mojom::InterfaceProviderRequest
   TakeInitialInterfaceProviderRequestForFrame(int32_t routing_id);
 
-  // Returns the request end of the DocumentInterfaceBroker interface whose
+  // Returns the receiver end of the DocumentInterfaceBroker interface whose
   // client end was passed in to construct RenderFrame with |routing_id|; if
   // any. The client end will be used by the RenderFrame to service interface
   // requests originating from the initial empty document.
-  blink::mojom::DocumentInterfaceBrokerRequest
-  TakeInitialDocumentInterfaceBrokerRequestForFrame(int32_t routing_id);
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+  TakeInitialDocumentInterfaceBrokerReceiverForFrame(int32_t routing_id);
 
   // Returns the receiver end of the BrowserInterfaceBroker interface whose
   // client end was passed in to construct RenderFrame with |routing_id|; if
@@ -165,8 +166,9 @@
   std::map<int32_t, service_manager::mojom::InterfaceProviderRequest>
       frame_routing_id_to_initial_interface_provider_requests_;
 
-  std::map<int32_t, blink::mojom::DocumentInterfaceBrokerRequest>
-      frame_routing_id_to_initial_document_broker_requests_;
+  std::map<int32_t,
+           mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>>
+      frame_routing_id_to_initial_document_broker_receivers_;
 
   std::map<int32_t, mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>>
       frame_routing_id_to_initial_browser_broker_receivers_;
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 0137955..77334181 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -39,6 +39,7 @@
 #include "content/test/mock_render_process.h"
 #include "content/test/test_content_client.h"
 #include "content/test/test_render_frame.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/escape.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -426,13 +427,14 @@
       mojo::MakeRequest(
           &view_params->main_frame_interface_bundle->interface_provider));
 
-  blink::mojom::DocumentInterfaceBrokerPtrInfo info;
-  mojo::MakeRequest(&info);
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker;
+  ignore_result(document_interface_broker.InitWithNewPipeAndPassReceiver());
   view_params->main_frame_interface_bundle->document_interface_broker_content =
-      std::move(info);
-  mojo::MakeRequest(&info);
+      std::move(document_interface_broker);
+  ignore_result(document_interface_broker.InitWithNewPipeAndPassReceiver());
   view_params->main_frame_interface_bundle->document_interface_broker_blink =
-      std::move(info);
+      std::move(document_interface_broker);
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker;
   // Ignoring the returned PendingReceiver because it is not bound to anything
diff --git a/content/renderer/media/webrtc/video_codec_factory.cc b/content/renderer/media/webrtc/video_codec_factory.cc
index 1fd03d9..22ceef1 100644
--- a/content/renderer/media/webrtc/video_codec_factory.cc
+++ b/content/renderer/media/webrtc/video_codec_factory.cc
@@ -10,8 +10,8 @@
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/media_switches.h"
-#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory.h"
-#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory.h"
+#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory_util.h"
+#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory_util.h"
 #include "third_party/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.h"
 #include "third_party/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.h"
 #include "third_party/webrtc/media/base/codec.h"
@@ -181,7 +181,7 @@
   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (gpu_factories && gpu_factories->IsGpuVideoAcceleratorEnabled() &&
       !cmd_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
-    encoder_factory.reset(new blink::RTCVideoEncoderFactory(gpu_factories));
+    encoder_factory = blink::CreateRTCVideoEncoderFactory(gpu_factories);
   }
 
 #if defined(OS_ANDROID)
@@ -199,7 +199,7 @@
   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (gpu_factories && gpu_factories->IsGpuVideoAcceleratorEnabled() &&
       !cmd_line->HasSwitch(switches::kDisableWebRtcHWDecoding)) {
-    decoder_factory.reset(new blink::RTCVideoDecoderFactory(gpu_factories));
+    decoder_factory = blink::CreateRTCVideoDecoderFactory(gpu_factories);
   }
 
   return std::make_unique<DecoderAdapter>(std::move(decoder_factory));
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 59c2d2e..4e37ab3 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1386,7 +1386,8 @@
     RenderViewImpl* render_view,
     int32_t routing_id,
     service_manager::mojom::InterfaceProviderPtr interface_provider,
-    blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content,
+    mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content,
     mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker,
     const base::UnguessableToken& devtools_frame_token) {
@@ -1432,9 +1433,10 @@
   service_manager::mojom::InterfaceProviderPtr main_frame_interface_provider(
       std::move(params->main_frame_interface_bundle->interface_provider));
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content(
-      std::move(params->main_frame_interface_bundle
-                    ->document_interface_broker_content));
+  mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content(
+          std::move(params->main_frame_interface_bundle
+                        ->document_interface_broker_content));
   RenderFrameImpl* render_frame = RenderFrameImpl::Create(
       render_view, params->main_frame_routing_id,
       std::move(main_frame_interface_provider),
@@ -1443,13 +1445,14 @@
       params->devtools_main_frame_token);
   render_frame->InitializeBlameContext(nullptr);
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink(
-      std::move(params->main_frame_interface_bundle
-                    ->document_interface_broker_blink));
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink(
+          std::move(params->main_frame_interface_bundle
+                        ->document_interface_broker_blink));
   WebLocalFrame* web_frame = WebLocalFrame::CreateMainFrame(
       render_view->webview(), render_frame,
       render_frame->blink_interface_registry_.get(),
-      document_interface_broker_blink.PassInterface().PassHandle(), opener,
+      document_interface_broker_blink.PassPipe(), opener,
       // This conversion is a little sad, as this often comes from a
       // WebString...
       WebString::FromUTF8(params->replicated_frame_state.name),
@@ -1501,8 +1504,10 @@
 void RenderFrameImpl::CreateFrame(
     int routing_id,
     service_manager::mojom::InterfaceProviderPtr interface_provider,
-    blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content,
-    blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink,
+    mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content,
+    mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_blink,
     mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker,
     int previous_routing_id,
@@ -1546,7 +1551,8 @@
     // Create the RenderFrame and WebLocalFrame, linking the two.
     render_frame = RenderFrameImpl::Create(
         parent_proxy->render_view(), routing_id, std::move(interface_provider),
-        std::move(document_interface_broker_content),
+        mojo::Remote<blink::mojom::DocumentInterfaceBroker>(
+            std::move(document_interface_broker_content)),
         std::move(browser_interface_broker), devtools_frame_token);
     render_frame->InitializeBlameContext(FromRoutingID(parent_routing_id));
     render_frame->unique_name_helper_.set_propagated_name(
@@ -1555,8 +1561,7 @@
         replicated_state.scope, WebString::FromUTF8(replicated_state.name),
         replicated_state.frame_policy, render_frame,
         render_frame->blink_interface_registry_.get(),
-        document_interface_broker_blink.PassInterface().PassHandle(),
-        previous_sibling_web_frame,
+        document_interface_broker_blink.PassPipe(), previous_sibling_web_frame,
         ConvertFrameOwnerPropertiesToWebFrameOwnerProperties(
             frame_owner_properties),
         replicated_state.frame_owner_element_type,
@@ -1585,15 +1590,16 @@
     render_view = proxy->render_view();
     render_frame = RenderFrameImpl::Create(
         render_view, routing_id, std::move(interface_provider),
-        std::move(document_interface_broker_content),
+        mojo::Remote<blink::mojom::DocumentInterfaceBroker>(
+            std::move(document_interface_broker_content)),
         std::move(browser_interface_broker), devtools_frame_token);
     render_frame->InitializeBlameContext(nullptr);
     render_frame->previous_routing_id_ = previous_routing_id;
     proxy->set_provisional_frame_routing_id(routing_id);
     web_frame = blink::WebLocalFrame::CreateProvisional(
         render_frame, render_frame->blink_interface_registry_.get(),
-        document_interface_broker_blink.PassInterface().PassHandle(),
-        proxy->web_frame(), replicated_state.frame_policy);
+        document_interface_broker_blink.PassPipe(), proxy->web_frame(),
+        replicated_state.frame_policy);
     // The new |web_frame| is a main frame iff the proxy's frame was.
     DCHECK_EQ(proxy_is_main_frame, !web_frame->Parent());
   }
@@ -1834,7 +1840,8 @@
     RenderViewImpl* render_view,
     int32_t routing_id,
     service_manager::mojom::InterfaceProviderPtr interface_provider,
-    blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content,
+    mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content,
     mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker,
     const base::UnguessableToken& devtools_frame_token)
@@ -3190,9 +3197,9 @@
 }
 
 void RenderFrameImpl::SetDocumentInterfaceBrokerForTesting(
-    blink::mojom::DocumentInterfaceBrokerPtr test_broker) {
-  document_interface_broker_.FlushForTesting();
-  document_interface_broker_ = std::move(test_broker);
+    mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker> test_broker) {
+  document_interface_broker_.reset();
+  document_interface_broker_.Bind(std::move(test_broker));
 }
 
 blink::AssociatedInterfaceRegistry*
@@ -4400,17 +4407,19 @@
   DCHECK(params_reply.document_interface_broker_blink_handle.is_valid());
   DCHECK(params_reply.browser_interface_broker_handle.is_valid());
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content;
+  mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content;
   document_interface_broker_content.Bind(
-      blink::mojom::DocumentInterfaceBrokerPtrInfo(
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>(
           mojo::ScopedMessagePipeHandle(
               params_reply.document_interface_broker_content_handle),
           blink::mojom::DocumentInterfaceBroker::Version_),
       GetTaskRunner(blink::TaskType::kInternalIPC));
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink;
+  mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink;
   document_interface_broker_blink.Bind(
-      blink::mojom::DocumentInterfaceBrokerPtrInfo(
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>(
           mojo::ScopedMessagePipeHandle(
               params_reply.document_interface_broker_blink_handle),
           blink::mojom::DocumentInterfaceBroker::Version_),
@@ -4441,7 +4450,7 @@
   blink::WebLocalFrame* web_frame = parent->CreateLocalChild(
       scope, child_render_frame,
       child_render_frame->blink_interface_registry_.get(),
-      document_interface_broker_blink.PassInterface().PassHandle());
+      document_interface_broker_blink.Unbind().PassPipe());
 
   child_render_frame->in_frame_tree_ = true;
   child_render_frame->Initialize();
@@ -4806,8 +4815,8 @@
 
   service_manager::mojom::InterfaceProviderRequest
       remote_interface_provider_request;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_request;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_receiver;
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker_receiver;
 
@@ -4831,19 +4840,20 @@
     remote_interfaces_.Bind(std::move(interfaces_provider));
 
     // If we're navigating to a new document, bind |document_interface_broker_|
-    // to a new message pipe. The request end of the new DocumentInterfaceBroker
-    // interface will be sent over as part of DidCommitProvisionalLoad. After
-    // the RFHI receives the commit confirmation, it will immediately close the
-    // old message pipe to avoid Get<interface> calls racing with navigation
-    // commit, and bind the request end of the message pipe created here. Must
-    // initialize |document_interface_broker_| with a new working pipe *before*
-    // observers receive DidCommitProvisionalLoad, so they can already request
-    // remote interfaces. The interface requests will be serviced once the
-    // DocumentInterfaceBroker interface request is bound by the
+    // to a new message pipe. The receiver end of the new
+    // DocumentInterfaceBroker interface will be sent over as part of
+    // DidCommitProvisionalLoad. After the RFHI receives the commit
+    // confirmation, it will immediately close the old message pipe to avoid
+    // Get<interface> calls racing with navigation commit, and bind the receiver
+    // end of the message pipe created here. Must initialize
+    // |document_interface_broker_| with a new working pipe *before* observers
+    // receive DidCommitProvisionalLoad, so they can already receive remote
+    // interfaces. The interface receivers will be serviced once the
+    // DocumentInterfaceBroker interface receiver is bound by the
     // RenderFrameHostImpl.
     document_interface_broker_.reset();
-    document_interface_broker_request =
-        mojo::MakeRequest(&document_interface_broker_);
+    document_interface_broker_receiver =
+        document_interface_broker_.BindNewPipeAndPassReceiver();
 
     // If we're navigating to a new document, bind
     // |browser_interface_broker_proxy_| to a new browser interface broker. The
@@ -4899,8 +4909,8 @@
       document_interface_broker_blink_handle.is_valid()
           ? mojom::DidCommitProvisionalLoadInterfaceParams::New(
                 std::move(remote_interface_provider_request),
-                std::move(document_interface_broker_request),
-                blink::mojom::DocumentInterfaceBrokerRequest(
+                std::move(document_interface_broker_receiver),
+                mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>(
                     std::move(document_interface_broker_blink_handle)),
                 std::move(browser_interface_broker_receiver))
           : nullptr);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 2849a38b..960c6b7 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -64,6 +64,7 @@
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "ppapi/buildflags/buildflags.h"
@@ -218,9 +219,10 @@
   static void CreateFrame(
       int routing_id,
       service_manager::mojom::InterfaceProviderPtr interface_provider,
-      blink::mojom::DocumentInterfaceBrokerPtr
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
           document_interface_broker_content,
-      blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink,
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_blink,
       mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
           browser_interface_broker,
       int previous_routing_id,
@@ -246,7 +248,7 @@
         RenderViewImpl* render_view,
         int32_t routing_id,
         service_manager::mojom::InterfaceProviderPtr interface_provider,
-        blink::mojom::DocumentInterfaceBrokerPtr
+        mojo::Remote<blink::mojom::DocumentInterfaceBroker>
             document_interface_broker_content,
         mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
             browser_interface_broker,
@@ -259,7 +261,8 @@
     RenderViewImpl* render_view;
     int32_t routing_id;
     service_manager::mojom::InterfaceProviderPtr interface_provider;
-    blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content;
+    mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content;
     mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker;
     base::UnguessableToken devtools_frame_token;
@@ -991,7 +994,7 @@
 
   // Used in tests to override DocumentInterfaceBroker's methods
   void SetDocumentInterfaceBrokerForTesting(
-      blink::mojom::DocumentInterfaceBrokerPtr test_broker);
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker> test_broker);
 
   // Used in tests to install a fake WebURLLoaderFactory via
   // RenderViewTest::CreateFakeWebURLLoaderFactory().
@@ -1085,7 +1088,7 @@
       RenderViewImpl* render_view,
       int32_t routing_id,
       service_manager::mojom::InterfaceProviderPtr interface_provider,
-      blink::mojom::DocumentInterfaceBrokerPtr
+      mojo::Remote<blink::mojom::DocumentInterfaceBroker>
           document_interface_broker_content,
       mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
           browser_interface_broker,
@@ -1608,7 +1611,8 @@
   service_manager::InterfaceProvider remote_interfaces_;
   std::unique_ptr<BlinkInterfaceRegistryImpl> blink_interface_registry_;
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_;
+  mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_;
   blink::BrowserInterfaceBrokerProxy browser_interface_broker_proxy_;
 
   service_manager::BindSourceInfo local_info_;
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 3f266bc..44ef1f1 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -41,6 +41,7 @@
 #include "content/test/test_document_interface_broker.h"
 #include "content/test/test_render_frame.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -112,13 +113,15 @@
     service_manager::mojom::InterfaceProviderPtr stub_interface_provider;
     mojo::MakeRequest(&stub_interface_provider);
 
-    blink::mojom::DocumentInterfaceBrokerPtr
+    mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
         stub_document_interface_broker_content;
-    mojo::MakeRequest(&stub_document_interface_broker_content);
+    ignore_result(stub_document_interface_broker_content
+                      .InitWithNewPipeAndPassReceiver());
 
-    blink::mojom::DocumentInterfaceBrokerPtr
+    mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
         stub_document_interface_broker_blink;
-    mojo::MakeRequest(&stub_document_interface_broker_blink);
+    ignore_result(
+        stub_document_interface_broker_blink.InitWithNewPipeAndPassReceiver());
 
     mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
         stub_browser_interface_broker;
@@ -260,8 +263,9 @@
   service_manager::mojom::InterfaceProviderPtr stub_interface_provider;
   mojo::MakeRequest(&stub_interface_provider);
 
-  blink::mojom::DocumentInterfaceBrokerPtr stub_document_interface_broker;
-  mojo::MakeRequest(&stub_document_interface_broker);
+  mojo::Remote<blink::mojom::DocumentInterfaceBroker>
+      stub_document_interface_broker;
+  ignore_result(stub_document_interface_broker.BindNewPipeAndPassReceiver());
 
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       stub_browser_interface_broker;
@@ -280,7 +284,7 @@
   parent_web_frame->CreateLocalChild(
       blink::WebTreeScopeType::kDocument, grandchild,
       grandchild->blink_interface_registry_.get(),
-      mojo::MakeRequest(&stub_document_interface_broker).PassMessagePipe());
+      stub_document_interface_broker.BindNewPipeAndPassReceiver().PassPipe());
   grandchild->in_frame_tree_ = true;
   grandchild->Initialize();
 
@@ -337,10 +341,12 @@
         frame()->GetWebFrame()->GetDocumentLoader());
     navigation_state->set_was_within_same_document(false);
 
-    blink::mojom::DocumentInterfaceBrokerPtr stub_document_interface_broker;
+    mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+        stub_document_interface_broker;
     frame()->DidCommitProvisionalLoad(
         item, blink::kWebStandardCommit,
-        mojo::MakeRequest(&stub_document_interface_broker).PassMessagePipe());
+        stub_document_interface_broker.InitWithNewPipeAndPassReceiver()
+            .PassPipe());
     EXPECT_EQ(tests[i].type, frame()->GetEffectiveConnectionType());
 
     // The main frame's effective connection type should be reset on commit.
@@ -348,9 +354,11 @@
         GetMainRenderFrame()->GetWebFrame()->GetDocumentLoader());
     navigation_state->set_was_within_same_document(false);
 
+    stub_document_interface_broker.reset();
     GetMainRenderFrame()->DidCommitProvisionalLoad(
         item, blink::kWebStandardCommit,
-        mojo::MakeRequest(&stub_document_interface_broker).PassMessagePipe());
+        stub_document_interface_broker.InitWithNewPipeAndPassReceiver()
+            .PassPipe());
     EXPECT_EQ(blink::WebEffectiveConnectionType::kTypeUnknown,
               GetMainRenderFrame()->GetEffectiveConnectionType());
 
@@ -660,9 +668,9 @@
  public:
   FrameHostTestDocumentInterfaceBroker(
       blink::mojom::DocumentInterfaceBroker* document_interface_broker,
-      blink::mojom::DocumentInterfaceBrokerRequest request)
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker> receiver)
       : TestDocumentInterfaceBroker(document_interface_broker,
-                                    std::move(request)) {}
+                                    std::move(receiver)) {}
 
   void GetFrameHostTestInterface(
       mojo::PendingReceiver<blink::mojom::FrameHostTestInterface> receiver)
@@ -673,9 +681,10 @@
 };
 
 TEST_F(RenderFrameImplTest, TestDocumentInterfaceBrokerOverride) {
-  blink::mojom::DocumentInterfaceBrokerPtr doc;
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker> doc;
   FrameHostTestDocumentInterfaceBroker frame_interface_broker(
-      frame()->GetDocumentInterfaceBroker(), mojo::MakeRequest(&doc));
+      frame()->GetDocumentInterfaceBroker(),
+      doc.InitWithNewPipeAndPassReceiver());
   frame()->SetDocumentInterfaceBrokerForTesting(std::move(doc));
 
   mojo::Remote<blink::mojom::FrameHostTestInterface> frame_test;
@@ -780,11 +789,12 @@
   using BinderCallback = base::RepeatingCallback<void(
       mojo::PendingReceiver<blink::mojom::FrameHostTestInterface>)>;
   TestSimpleDocumentInterfaceBrokerImpl(BinderCallback binder_callback)
-      : binding_(this), binder_callback_(binder_callback) {}
-  void BindAndFlush(blink::mojom::DocumentInterfaceBrokerRequest request) {
-    ASSERT_FALSE(binding_.is_bound());
-    binding_.Bind(std::move(request));
-    binding_.FlushForTesting();
+      : binder_callback_(binder_callback) {}
+  void BindAndFlush(
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker> receiver) {
+    ASSERT_FALSE(receiver_.is_bound());
+    receiver_.Bind(std::move(receiver));
+    receiver_.FlushForTesting();
   }
 
  private:
@@ -804,7 +814,7 @@
       mojo::PendingReceiver<blink::test::mojom::VirtualAuthenticatorManager>
           receiver) override {}
 
-  mojo::Binding<blink::mojom::DocumentInterfaceBroker> binding_;
+  mojo::Receiver<blink::mojom::DocumentInterfaceBroker> receiver_{this};
   BinderCallback binder_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(TestSimpleDocumentInterfaceBrokerImpl);
@@ -1023,8 +1033,8 @@
     interface_request_for_first_document_ =
         frame_->TakeLastInterfaceProviderRequest();
 
-    document_interface_broker_request_for_first_document_ =
-        frame_->TakeLastDocumentInterfaceBrokerRequest();
+    document_interface_broker_receiver_for_first_document_ =
+        frame_->TakeLastDocumentInterfaceBrokerReceiver();
 
     browser_interface_broker_receiver_for_first_document_ =
         frame_->TakeLastBrowserInterfaceBrokerReceiver();
@@ -1035,10 +1045,10 @@
     return std::move(interface_request_for_initial_empty_document_);
   }
 
-  blink::mojom::DocumentInterfaceBrokerRequest
-  document_interface_broker_request_for_initial_empty_document() {
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+  document_interface_broker_receiver_for_initial_empty_document() {
     return std::move(
-        document_interface_broker_request_for_initial_empty_document_);
+        document_interface_broker_receiver_for_initial_empty_document_);
   }
 
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
@@ -1052,9 +1062,9 @@
     return std::move(interface_request_for_first_document_);
   }
 
-  blink::mojom::DocumentInterfaceBrokerRequest
-  document_interface_broker_request_for_first_document() {
-    return std::move(document_interface_broker_request_for_first_document_);
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+  document_interface_broker_receiver_for_first_document() {
+    return std::move(document_interface_broker_receiver_for_first_document_);
   }
 
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
@@ -1082,8 +1092,8 @@
 
     interface_request_for_initial_empty_document_ =
         frame->TakeLastInterfaceProviderRequest();
-    document_interface_broker_request_for_initial_empty_document_ =
-        frame->TakeLastDocumentInterfaceBrokerRequest();
+    document_interface_broker_receiver_for_initial_empty_document_ =
+        frame->TakeLastDocumentInterfaceBrokerReceiver();
     browser_interface_broker_receiver_for_initial_empty_document_ =
         frame_->TakeLastBrowserInterfaceBrokerReceiver();
     EXPECT_TRUE(frame->current_history_item().IsNull());
@@ -1102,10 +1112,10 @@
   service_manager::mojom::InterfaceProviderRequest
       interface_request_for_first_document_;
 
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_request_for_initial_empty_document_;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_request_for_first_document_;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_receiver_for_initial_empty_document_;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_receiver_for_first_document_;
 
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker_receiver_for_initial_empty_document_;
@@ -1121,8 +1131,8 @@
 // FrameHostTestInterface requests.
 void ExpectPendingInterfaceRequestsFromSources(
     service_manager::mojom::InterfaceProviderRequest interface_provider_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_request,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_receiver,
     mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker_receiver,
     std::vector<SourceAnnotation> expected_sources) {
@@ -1143,7 +1153,7 @@
   EXPECT_THAT(sources, ::testing::ElementsAreArray(expected_sources));
 
   std::vector<SourceAnnotation> document_interface_broker_sources;
-  ASSERT_TRUE(document_interface_broker_request.is_pending());
+  ASSERT_TRUE(document_interface_broker_receiver.is_valid());
   TestSimpleDocumentInterfaceBrokerImpl broker(base::BindLambdaForTesting(
       [&document_interface_broker_sources](
           mojo::PendingReceiver<blink::mojom::FrameHostTestInterface>
@@ -1153,7 +1163,7 @@
         ASSERT_TRUE(impl.ping_source().has_value());
         document_interface_broker_sources.push_back(impl.ping_source().value());
       }));
-  broker.BindAndFlush(std::move(document_interface_broker_request));
+  broker.BindAndFlush(std::move(document_interface_broker_receiver));
   EXPECT_THAT(document_interface_broker_sources,
               ::testing::ElementsAreArray(expected_sources));
 
@@ -1239,7 +1249,7 @@
   ExpectPendingInterfaceRequestsFromSources(
       child_frame_exerciser.interface_request_for_initial_empty_document(),
       child_frame_exerciser
-          .document_interface_broker_request_for_initial_empty_document(),
+          .document_interface_broker_receiver_for_initial_empty_document(),
       child_frame_exerciser
           .browser_interface_broker_receiver_for_initial_empty_document(),
       {{GURL(kNoDocumentMarkerURL), kFrameEventDidCreateNewFrame},
@@ -1253,7 +1263,7 @@
   ExpectPendingInterfaceRequestsFromSources(
       child_frame_exerciser.interface_request_for_first_document(),
       child_frame_exerciser
-          .document_interface_broker_request_for_first_document(),
+          .document_interface_broker_receiver_for_first_document(),
       child_frame_exerciser
           .browser_interface_broker_receiver_for_first_document(),
       {{child_frame_url, kFrameEventDidCommitProvisionalLoad},
@@ -1295,7 +1305,7 @@
   ExpectPendingInterfaceRequestsFromSources(
       main_frame_exerciser.interface_request_for_initial_empty_document(),
       main_frame_exerciser
-          .document_interface_broker_request_for_initial_empty_document(),
+          .document_interface_broker_receiver_for_initial_empty_document(),
       main_frame_exerciser
           .browser_interface_broker_receiver_for_initial_empty_document(),
       {{initial_empty_url, kFrameEventDidCreateNewFrame},
@@ -1304,7 +1314,7 @@
   ExpectPendingInterfaceRequestsFromSources(
       main_frame_exerciser.interface_request_for_first_document(),
       main_frame_exerciser
-          .document_interface_broker_request_for_first_document(),
+          .document_interface_broker_receiver_for_first_document(),
       main_frame_exerciser
           .browser_interface_broker_receiver_for_first_document(),
       {{new_window_url, kFrameEventDidCommitProvisionalLoad},
@@ -1361,7 +1371,7 @@
     ExpectPendingInterfaceRequestsFromSources(
         child_frame_exerciser.interface_request_for_initial_empty_document(),
         child_frame_exerciser
-            .document_interface_broker_request_for_initial_empty_document(),
+            .document_interface_broker_receiver_for_initial_empty_document(),
         child_frame_exerciser
             .browser_interface_broker_receiver_for_initial_empty_document(),
         {{GURL(kNoDocumentMarkerURL), kFrameEventDidCreateNewFrame},
@@ -1374,10 +1384,10 @@
 
     auto request = child_frame_exerciser.interface_request_for_first_document();
     ASSERT_FALSE(request.is_pending());
-    auto document_interface_broker_request =
+    auto document_interface_broker_receiver =
         child_frame_exerciser
-            .document_interface_broker_request_for_first_document();
-    ASSERT_FALSE(document_interface_broker_request.is_pending());
+            .document_interface_broker_receiver_for_first_document();
+    ASSERT_FALSE(document_interface_broker_receiver.is_valid());
     auto browser_interface_broker_receiver =
         child_frame_exerciser
             .browser_interface_broker_receiver_for_first_document();
@@ -1396,8 +1406,8 @@
   auto interface_provider_request_for_first_document =
       GetMainRenderFrame()->TakeLastInterfaceProviderRequest();
 
-  auto document_interface_broker_request_for_first_document =
-      GetMainRenderFrame()->TakeLastDocumentInterfaceBrokerRequest();
+  auto document_interface_broker_receiver_for_first_document =
+      GetMainRenderFrame()->TakeLastDocumentInterfaceBrokerReceiver();
 
   auto browser_interface_broker_receiver_for_first_document =
       GetMainRenderFrame()->TakeLastBrowserInterfaceBrokerReceiver();
@@ -1411,27 +1421,25 @@
       GetMainRenderFrame()->TakeLastInterfaceProviderRequest();
 
   auto document_interface_broker_request_for_second_document =
-      GetMainRenderFrame()->TakeLastDocumentInterfaceBrokerRequest();
+      GetMainRenderFrame()->TakeLastDocumentInterfaceBrokerReceiver();
 
   auto browser_interface_broker_receiver_for_second_document =
       GetMainRenderFrame()->TakeLastBrowserInterfaceBrokerReceiver();
 
   ASSERT_TRUE(interface_provider_request_for_first_document.is_pending());
-  ASSERT_TRUE(
-      document_interface_broker_request_for_first_document.is_pending());
+  ASSERT_TRUE(document_interface_broker_receiver_for_first_document.is_valid());
   ASSERT_TRUE(browser_interface_broker_receiver_for_first_document.is_valid());
 
   ExpectPendingInterfaceRequestsFromSources(
       std::move(interface_provider_request_for_first_document),
-      std::move(document_interface_broker_request_for_first_document),
+      std::move(document_interface_broker_receiver_for_first_document),
       std::move(browser_interface_broker_receiver_for_first_document),
       {{GURL(kTestFirstURL), kFrameEventAfterCommit},
        {GURL(kTestFirstURL), kFrameEventReadyToCommitNavigation},
        {GURL(kTestSecondURL), kFrameEventDidCreateNewDocument}});
 
   ASSERT_TRUE(interface_provider_request_for_second_document.is_pending());
-  ASSERT_TRUE(
-      document_interface_broker_request_for_second_document.is_pending());
+  ASSERT_TRUE(document_interface_broker_request_for_second_document.is_valid());
   ASSERT_TRUE(browser_interface_broker_receiver_for_second_document.is_valid());
 
   ExpectPendingInterfaceRequestsFromSources(
@@ -1455,7 +1463,7 @@
       GetMainRenderFrame()->TakeLastInterfaceProviderRequest();
 
   auto document_interface_broker =
-      GetMainRenderFrame()->TakeLastDocumentInterfaceBrokerRequest();
+      GetMainRenderFrame()->TakeLastDocumentInterfaceBrokerReceiver();
 
   auto browser_interface_broker_receiver =
       GetMainRenderFrame()->TakeLastBrowserInterfaceBrokerReceiver();
@@ -1467,11 +1475,11 @@
       GetMainRenderFrame()->TakeLastInterfaceProviderRequest().is_pending());
 
   EXPECT_FALSE(GetMainRenderFrame()
-                   ->TakeLastDocumentInterfaceBrokerRequest()
-                   .is_pending());
+                   ->TakeLastDocumentInterfaceBrokerReceiver()
+                   .is_valid());
 
   ASSERT_TRUE(interface_provider_request.is_pending());
-  ASSERT_TRUE(document_interface_broker.is_pending());
+  ASSERT_TRUE(document_interface_broker.is_valid());
   ASSERT_TRUE(browser_interface_broker_receiver.is_valid());
 
   ExpectPendingInterfaceRequestsFromSources(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 7554f7e..089e1b4 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -122,6 +122,7 @@
 #include "media/base/media_switches.h"
 #include "media/media_buildflags.h"
 #include "media/video/gpu_video_accelerator_factories.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "net/base/net_errors.h"
@@ -2031,10 +2032,12 @@
   CompositorDependencies* compositor_deps = this;
   service_manager::mojom::InterfaceProviderPtr interface_provider(
       std::move(params->interface_bundle->interface_provider));
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content(
-      std::move(params->interface_bundle->document_interface_broker_content));
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink(
-      std::move(params->interface_bundle->document_interface_broker_blink));
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content(std::move(
+          params->interface_bundle->document_interface_broker_content));
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink(
+          std::move(params->interface_bundle->document_interface_broker_blink));
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker(
           std::move(params->interface_bundle->browser_interface_broker));
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 89ba1247..bd871e1 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -61,6 +61,7 @@
 #include "content/test/fake_compositor_dependencies.h"
 #include "content/test/mock_keyboard.h"
 #include "content/test/test_render_frame.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/http/http_util.h"
@@ -1036,11 +1037,14 @@
   int routing_id = kProxyRoutingId + 1;
   service_manager::mojom::InterfaceProviderPtr stub_interface_provider;
   mojo::MakeRequest(&stub_interface_provider);
-  blink::mojom::DocumentInterfaceBrokerPtr
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
       stub_document_interface_broker_content;
-  mojo::MakeRequest(&stub_document_interface_broker_content);
-  blink::mojom::DocumentInterfaceBrokerPtr stub_document_interface_broker_blink;
-  mojo::MakeRequest(&stub_document_interface_broker_blink);
+  ignore_result(
+      stub_document_interface_broker_content.InitWithNewPipeAndPassReceiver());
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      stub_document_interface_broker_blink;
+  ignore_result(
+      stub_document_interface_broker_blink.InitWithNewPipeAndPassReceiver());
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       stub_browser_interface_broker;
   ignore_result(stub_browser_interface_broker.InitWithNewPipeAndPassReceiver());
@@ -1108,11 +1112,14 @@
   int routing_id = kProxyRoutingId + 1;
   service_manager::mojom::InterfaceProviderPtr stub_interface_provider;
   mojo::MakeRequest(&stub_interface_provider);
-  blink::mojom::DocumentInterfaceBrokerPtr
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
       stub_document_interface_broker_content;
-  mojo::MakeRequest(&stub_document_interface_broker_content);
-  blink::mojom::DocumentInterfaceBrokerPtr stub_document_interface_broker_blink;
-  mojo::MakeRequest(&stub_document_interface_broker_blink);
+  ignore_result(
+      stub_document_interface_broker_content.InitWithNewPipeAndPassReceiver());
+  mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>
+      stub_document_interface_broker_blink;
+  ignore_result(
+      stub_document_interface_broker_blink.InitWithNewPipeAndPassReceiver());
   mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
       stub_browser_interface_broker;
   ignore_result(stub_browser_interface_broker.InitWithNewPipeAndPassReceiver());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 5b056c72..f505e43 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1039,6 +1039,7 @@
     "../browser/web_contents/web_contents_impl_browsertest.cc",
     "../browser/web_contents/web_contents_view_aura_browsertest.cc",
     "../browser/web_contents_binding_set_browsertest.cc",
+    "../browser/web_package/bundled_exchanges_browsertest.cc",
     "../browser/web_package/signed_exchange_request_handler_browsertest.cc",
     "../browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc",
     "../browser/webkit_browsertest.cc",
@@ -1229,6 +1230,7 @@
       "$root_out_dir/content_shell.pak",
       "data/",
       "//media/test/data/",
+      "//services/test/data/",
     ]
   }
 
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index 008c4ea6..7fab994 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -345,13 +345,12 @@
   service_manager::mojom::InterfaceProviderPtr stub_interface_provider;
   interface_provider_request_ = mojo::MakeRequest(&stub_interface_provider);
 
-  blink::mojom::DocumentInterfaceBrokerPtr
-      stub_document_interface_broker_content;
-  document_interface_broker_content_request_ =
-      mojo::MakeRequest(&stub_document_interface_broker_content);
-  blink::mojom::DocumentInterfaceBrokerPtr stub_document_interface_broker_blink;
-  document_interface_broker_blink_request_ =
-      mojo::MakeRequest(&stub_document_interface_broker_blink);
+  document_interface_broker_content_receiver_ =
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver();
+  document_interface_broker_blink_receiver_ =
+      mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver();
   browser_interface_broker_receiver_ =
       mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
           .InitWithNewPipeAndPassReceiver();
@@ -601,8 +600,8 @@
 
   if (same_document_) {
     interface_provider_request_ = nullptr;
-    document_interface_broker_content_request_ = nullptr;
-    document_interface_broker_blink_request_ = nullptr;
+    document_interface_broker_content_receiver_.reset();
+    document_interface_broker_blink_receiver_.reset();
     browser_interface_broker_receiver_.reset();
   }
 
@@ -621,8 +620,8 @@
       false /* same_document */, false /* failed_navigation */);
   render_frame_host_->SimulateCommitProcessed(
       request_, std::move(params), std::move(interface_provider_request_),
-      std::move(document_interface_broker_content_request_),
-      std::move(document_interface_broker_blink_request_),
+      std::move(document_interface_broker_content_receiver_),
+      std::move(document_interface_broker_blink_receiver_),
       std::move(browser_interface_broker_receiver_), same_document_);
 
   // Simulate the UnloadACK in the old RenderFrameHost if it was swapped out at
@@ -750,8 +749,8 @@
       false /* same_document */, true /* failed_navigation */);
   render_frame_host_->SimulateCommitProcessed(
       request_, std::move(params), std::move(interface_provider_request_),
-      std::move(document_interface_broker_content_request_),
-      std::move(document_interface_broker_blink_request_),
+      std::move(document_interface_broker_content_receiver_),
+      std::move(document_interface_broker_blink_receiver_),
       std::move(browser_interface_broker_receiver_), false /* same_document */);
 
   // Simulate the UnloadACK in the old RenderFrameHost if it was swapped out at
@@ -782,17 +781,15 @@
       true /* same_document */, false /* failed_navigation */);
 
   interface_provider_request_ = nullptr;
-  document_interface_broker_content_request_ = nullptr;
-  document_interface_broker_blink_request_ = nullptr;
+  document_interface_broker_content_receiver_.reset();
+  document_interface_broker_blink_receiver_.reset();
   browser_interface_broker_receiver_.reset();
 
   render_frame_host_->SimulateCommitProcessed(
       request_, std::move(params), nullptr /* interface_provider_request_ */,
-      nullptr /* document_interface_broker_content_handle */,
-      nullptr /* document_interface_broker_blink_handle */,
-      mojo::PendingReceiver<
-          blink::mojom::
-              BrowserInterfaceBroker>() /* browser_interface_broker_receiver */,
+      mojo::NullReceiver() /* document_interface_broker_content_receiver */,
+      mojo::NullReceiver() /* document_interface_broker_blink_receiver */,
+      mojo::NullReceiver() /* browser_interface_broker_receiver */,
       true /* same_document */);
 
   // Same-document commits should never hit network-related stages of committing
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h
index 1f590bb..d37b057 100644
--- a/content/test/navigation_simulator_impl.h
+++ b/content/test/navigation_simulator_impl.h
@@ -17,6 +17,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/navigation_simulator.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_endpoint.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -280,10 +281,10 @@
   int session_history_offset_ = 0;
   bool has_user_gesture_ = true;
   service_manager::mojom::InterfaceProviderRequest interface_provider_request_;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_content_request_;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_blink_request_;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content_receiver_;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink_receiver_;
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker_receiver_;
   std::string contents_mime_type_;
diff --git a/content/test/test_document_interface_broker.cc b/content/test/test_document_interface_broker.cc
index 7b7b009..564bcfd 100644
--- a/content/test/test_document_interface_broker.cc
+++ b/content/test/test_document_interface_broker.cc
@@ -8,9 +8,9 @@
 
 TestDocumentInterfaceBroker::TestDocumentInterfaceBroker(
     blink::mojom::DocumentInterfaceBroker* document_interface_broker,
-    blink::mojom::DocumentInterfaceBrokerRequest request)
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker> receiver)
     : real_broker_(document_interface_broker),
-      binding_(this, std::move(request)) {}
+      receiver_(this, std::move(receiver)) {}
 
 TestDocumentInterfaceBroker::~TestDocumentInterfaceBroker() {}
 
@@ -20,7 +20,7 @@
 }
 
 void TestDocumentInterfaceBroker::Flush() {
-  binding_.FlushForTesting();
+  receiver_.FlushForTesting();
 }
 
 }  // namespace content
\ No newline at end of file
diff --git a/content/test/test_document_interface_broker.h b/content/test/test_document_interface_broker.h
index 9b467891..e78c3296 100644
--- a/content/test/test_document_interface_broker.h
+++ b/content/test/test_document_interface_broker.h
@@ -7,7 +7,8 @@
 
 #include <utility>
 
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-test-utils.h"
 
 namespace content {
@@ -20,14 +21,14 @@
  public:
   TestDocumentInterfaceBroker(
       blink::mojom::DocumentInterfaceBroker* document_interface_broker,
-      blink::mojom::DocumentInterfaceBrokerRequest request);
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker> receiver);
   ~TestDocumentInterfaceBroker() override;
   blink::mojom::DocumentInterfaceBroker* GetForwardingInterface() override;
   void Flush();
 
  private:
   blink::mojom::DocumentInterfaceBroker* real_broker_;
-  mojo::Binding<DocumentInterfaceBroker> binding_;
+  mojo::Receiver<DocumentInterfaceBroker> receiver_;
 };
 
 }  // namespace content
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 630388f..3519af61 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -43,9 +43,9 @@
     return std::move(last_interface_provider_request_);
   }
 
-  blink::mojom::DocumentInterfaceBrokerRequest
-  TakeLastDocumentInterfaceBrokerRequest() {
-    return std::move(last_document_interface_broker_request_);
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+  TakeLastDocumentInterfaceBrokerReceiver() {
+    return std::move(last_document_interface_broker_receiver_);
   }
 
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
@@ -68,15 +68,15 @@
     last_interface_provider_request_ = std::move(interface_provider_request);
   }
 
-  // Holds on to the request end of the DocumentInterfaceBroker interface whose
+  // Holds on to the receiver end of the DocumentInterfaceBroker interface whose
   // client end is bound to the corresponding RenderFrame's
   // |document_interface_broker_| to facilitate retrieving the most recent
-  // |document_interface_broker_request| in tests.
-  void PassLastDocumentInterfaceBrokerRequest(
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_request) {
-    last_document_interface_broker_request_ =
-        std::move(document_interface_broker_request);
+  // |document_interface_broker_receiver| in tests.
+  void PassLastDocumentInterfaceBrokerReceiver(
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_receiver) {
+    last_document_interface_broker_receiver_ =
+        std::move(document_interface_broker_receiver);
   }
 
   // Holds on to the request end of the BrowserInterfaceBroker interface whose
@@ -98,9 +98,10 @@
     if (interface_params) {
       last_interface_provider_request_ =
           std::move(interface_params->interface_provider_request);
-      last_document_interface_broker_request_ =
-          blink::mojom::DocumentInterfaceBrokerRequest(std::move(
-              interface_params->document_interface_broker_content_request));
+      last_document_interface_broker_receiver_ =
+          mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>(
+              std::move(interface_params
+                            ->document_interface_broker_content_receiver));
       last_browser_interface_broker_receiver_ =
           std::move(interface_params->browser_interface_broker_receiver);
     }
@@ -226,8 +227,8 @@
       last_commit_params_;
   service_manager::mojom::InterfaceProviderRequest
       last_interface_provider_request_;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      last_document_interface_broker_request_;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      last_document_interface_broker_receiver_;
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
       last_browser_interface_broker_receiver_;
 
@@ -251,8 +252,8 @@
   mock_frame_host_->PassLastInterfaceProviderRequest(
       mock_render_thread->TakeInitialInterfaceProviderRequestForFrame(
           params.routing_id));
-  mock_frame_host_->PassLastDocumentInterfaceBrokerRequest(
-      mock_render_thread->TakeInitialDocumentInterfaceBrokerRequestForFrame(
+  mock_frame_host_->PassLastDocumentInterfaceBrokerReceiver(
+      mock_render_thread->TakeInitialDocumentInterfaceBrokerReceiverForFrame(
           params.routing_id));
   mock_frame_host_->PassLastBrowserInterfaceBrokerReceiver(
       mock_render_thread->TakeInitialBrowserInterfaceBrokerReceiverForFrame(
@@ -417,9 +418,9 @@
   return mock_frame_host_->TakeLastInterfaceProviderRequest();
 }
 
-blink::mojom::DocumentInterfaceBrokerRequest
-TestRenderFrame::TakeLastDocumentInterfaceBrokerRequest() {
-  return mock_frame_host_->TakeLastDocumentInterfaceBrokerRequest();
+mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+TestRenderFrame::TakeLastDocumentInterfaceBrokerReceiver() {
+  return mock_frame_host_->TakeLastDocumentInterfaceBrokerReceiver();
 }
 
 mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
diff --git a/content/test/test_render_frame.h b/content/test/test_render_frame.h
index 48e4d19..0880cc7c 100644
--- a/content/test/test_render_frame.h
+++ b/content/test/test_render_frame.h
@@ -13,6 +13,7 @@
 #include "content/common/input/input_handler.mojom.h"
 #include "content/common/navigation_params.mojom.h"
 #include "content/renderer/render_frame_impl.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
 namespace blink {
@@ -75,8 +76,8 @@
   service_manager::mojom::InterfaceProviderRequest
   TakeLastInterfaceProviderRequest();
 
-  blink::mojom::DocumentInterfaceBrokerRequest
-  TakeLastDocumentInterfaceBrokerRequest();
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+  TakeLastDocumentInterfaceBrokerReceiver();
 
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
   TakeLastBrowserInterfaceBrokerReceiver();
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 7332a204..f684882 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -143,8 +143,8 @@
   std::string frame_unique_name = base::GenerateGUID();
   OnCreateChildFrame(
       GetProcess()->GetNextRoutingID(), CreateStubInterfaceProviderRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
-      CreateStubDocumentInterfaceBrokerRequest(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
+      CreateStubDocumentInterfaceBrokerReceiver(),
       CreateStubBrowserInterfaceBrokerReceiver(),
       blink::WebTreeScopeType::kDocument, frame_name, frame_unique_name, false,
       base::UnguessableToken::Create(), blink::FramePolicy(),
@@ -454,10 +454,10 @@
     NavigationRequest* navigation_request,
     std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params,
     service_manager::mojom::InterfaceProviderRequest interface_provider_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_content_request,
-    blink::mojom::DocumentInterfaceBrokerRequest
-        document_interface_broker_blink_request,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_content_receiver,
+    mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+        document_interface_broker_blink_receiver,
     mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
         browser_interface_broker_receiver,
     bool same_document) {
@@ -482,8 +482,8 @@
             .Run(std::move(params),
                  mojom::DidCommitProvisionalLoadInterfaceParams::New(
                      std::move(interface_provider_request),
-                     std::move(document_interface_broker_content_request),
-                     std::move(document_interface_broker_blink_request),
+                     std::move(document_interface_broker_content_receiver),
+                     std::move(document_interface_broker_blink_receiver),
                      std::move(browser_interface_broker_receiver)));
         did_commit = true;
       }
@@ -501,8 +501,8 @@
             .Run(std::move(params),
                  mojom::DidCommitProvisionalLoadInterfaceParams::New(
                      std::move(interface_provider_request),
-                     std::move(document_interface_broker_content_request),
-                     std::move(document_interface_broker_blink_request),
+                     std::move(document_interface_broker_content_receiver),
+                     std::move(document_interface_broker_blink_receiver),
                      std::move(browser_interface_broker_receiver)));
         did_commit = true;
       }
@@ -514,8 +514,8 @@
         params.get(),
         mojom::DidCommitProvisionalLoadInterfaceParams::New(
             std::move(interface_provider_request),
-            std::move(document_interface_broker_content_request),
-            std::move(document_interface_broker_blink_request),
+            std::move(document_interface_broker_content_receiver),
+            std::move(document_interface_broker_blink_receiver),
             std::move(browser_interface_broker_receiver)),
         same_document);
   }
@@ -647,21 +647,21 @@
   service_manager::mojom::InterfaceProviderPtr interface_provider;
   service_manager::mojom::InterfaceProviderRequest interface_provider_request;
 
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_content;
-  blink::mojom::DocumentInterfaceBrokerPtr document_interface_broker_blink;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_content_request;
-  blink::mojom::DocumentInterfaceBrokerRequest
-      document_interface_broker_blink_request;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_content_receiver;
+  mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+      document_interface_broker_blink_receiver;
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
       browser_interface_broker_receiver;
 
   if (!is_same_document) {
     interface_provider_request = mojo::MakeRequest(&interface_provider);
-    document_interface_broker_content_request =
-        mojo::MakeRequest(&document_interface_broker_content);
-    document_interface_broker_blink_request =
-        mojo::MakeRequest(&document_interface_broker_blink);
+    document_interface_broker_content_receiver =
+        mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+            .InitWithNewPipeAndPassReceiver();
+    document_interface_broker_blink_receiver =
+        mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+            .InitWithNewPipeAndPassReceiver();
     browser_interface_broker_receiver =
         mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
             .InitWithNewPipeAndPassReceiver();
@@ -669,8 +669,8 @@
 
   auto interface_params = mojom::DidCommitProvisionalLoadInterfaceParams::New(
       std::move(interface_provider_request),
-      std::move(document_interface_broker_content_request),
-      std::move(document_interface_broker_blink_request),
+      std::move(document_interface_broker_content_receiver),
+      std::move(document_interface_broker_blink_receiver),
       std::move(browser_interface_broker_receiver));
   return interface_params;
 }
@@ -688,11 +688,10 @@
 }
 
 // static
-blink::mojom::DocumentInterfaceBrokerRequest
-TestRenderFrameHost::CreateStubDocumentInterfaceBrokerRequest() {
-  ::blink::mojom::DocumentInterfaceBrokerPtrInfo
-      dead_document_interface_broker_proxy;
-  return mojo::MakeRequest(&dead_document_interface_broker_proxy);
+mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+TestRenderFrameHost::CreateStubDocumentInterfaceBrokerReceiver() {
+  return mojo::PendingRemote<::blink::mojom::DocumentInterfaceBroker>()
+      .InitWithNewPipeAndPassReceiver();
 }
 
 // static
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index b2e3d89..2b39c895 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -21,6 +21,7 @@
 #include "content/public/test/test_renderer_host.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_render_widget_host.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/base/page_transition_types.h"
 
 namespace net {
@@ -158,10 +159,10 @@
       std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params,
       service_manager::mojom::InterfaceProviderRequest
           interface_provider_request,
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_content_request,
-      blink::mojom::DocumentInterfaceBrokerRequest
-          document_interface_broker_blink_request,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_content_receiver,
+      mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+          document_interface_broker_blink_receiver,
       mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
           browser_interface_broker_receiver,
       bool same_document);
@@ -185,10 +186,10 @@
   static service_manager::mojom::InterfaceProviderRequest
   CreateStubInterfaceProviderRequest();
 
-  // Returns a pending DocumentInterfaceBrokerRequest that is safe to bind to an
-  // implementation, but will never receive any interface requests.
-  static blink::mojom::DocumentInterfaceBrokerRequest
-  CreateStubDocumentInterfaceBrokerRequest();
+  // Returns a pending PendingReceiver<DocumentInterfaceBroker> that is safe to
+  // bind to an implementation, but will never receive any interface requests.
+  static mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker>
+  CreateStubDocumentInterfaceBrokerReceiver();
 
   // Returns a PendingReceiver<BrowserInterfaceBroker> that is safe to bind to
   // an implementation, but will never receive any interface requests.
diff --git a/extensions/renderer/scoped_web_frame.cc b/extensions/renderer/scoped_web_frame.cc
index c17d952..18bcd84 100644
--- a/extensions/renderer/scoped_web_frame.cc
+++ b/extensions/renderer/scoped_web_frame.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/renderer/scoped_web_frame.h"
 
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
 #include "third_party/blink/public/web/web_heap.h"
 #include "third_party/blink/public/web/web_view.h"
@@ -13,8 +14,9 @@
 
 // returns a valid handle that can be passed to WebLocalFrame constructor
 mojo::ScopedMessagePipeHandle CreateStubDocumentInterfaceBrokerHandle() {
-  blink::mojom::DocumentInterfaceBrokerPtrInfo info;
-  return mojo::MakeRequest(&info).PassMessagePipe();
+  return mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+      .InitWithNewPipeAndPassReceiver()
+      .PassPipe();
 }
 
 ScopedWebFrame::ScopedWebFrame()
diff --git a/google_apis/drive/drive_api_requests_unittest.cc b/google_apis/drive/drive_api_requests_unittest.cc
index 06f54a9..24b90d3 100644
--- a/google_apis/drive/drive_api_requests_unittest.cc
+++ b/google_apis/drive/drive_api_requests_unittest.cc
@@ -141,11 +141,12 @@
     network_service_ptr->SetClient(std::move(network_service_client_ptr),
                                    network::mojom::NetworkServiceParams::New());
 
-    network::mojom::NetworkContextClientPtr network_context_client_ptr;
+    mojo::PendingRemote<network::mojom::NetworkContextClient>
+        network_context_client_remote;
     network_context_client_ =
         std::make_unique<network::TestNetworkContextClient>(
-            mojo::MakeRequest(&network_context_client_ptr));
-    network_context_->SetClient(std::move(network_context_client_ptr));
+            network_context_client_remote.InitWithNewPipeAndPassReceiver());
+    network_context_->SetClient(std::move(network_context_client_remote));
 
     network::mojom::URLLoaderFactoryParamsPtr params =
         network::mojom::URLLoaderFactoryParams::New();
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index dc4f9c3..e56b9cca 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -1159,6 +1159,13 @@
     }
 
     builders {
+      name: "Android WebView P (dbg)"
+      mixins: "android-ci-goma-rbe-prod"
+      mixins: "builderless"
+      mixins: "linux-xenial"
+    }
+
+    builders {
       name: "Android WebView O NetworkService (dbg)"
       mixins: "android-fyi-ci"
       mixins: "builderless"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 7c3cb73..9d238d5 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -1587,6 +1587,11 @@
     short_name: "O"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Android WebView P (dbg)"
+    category: "tester|webview"
+    short_name: "P"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/android-kitkat-arm-rel"
     category: "on_cq"
     short_name: "K"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index ee048ac..d9e9060 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -664,6 +664,17 @@
 }
 
 job {
+  id: "Android WebView P (dbg)"
+  # triggered by "Android arm64 Builder (dbg)"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android WebView P (dbg)"
+  }
+}
+
+job {
   id: "Android WebView O NetworkService (dbg)"
   # triggered by "Android arm64 Builder (dbg)"
   acl_sets: "triggered-by-parent-builders"
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 7ff76fcf..2b1fabe 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -137,31 +137,9 @@
       <message name="IDS_IOS_ACCNAME_VOICE_SEARCH" desc="The accessibility label for the voice search button in the location bar [Length: unlimited]">
         Voice Search
       </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON" desc="Title of the button to accept sign in and navigate away from the confirmation screen. [Length: 20m] [iOS only]">
-        Ok, Got it
-      </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OPEN_SETTINGS" desc="Description of how to configure sync and Google services on the sign-in confirmation screen. [Length: unlimited]">
-        Manage Chrome Sync and personalization in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>
-      </message>
       <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SCROLL_BUTTON" desc="Title of the button to scroll the confirmation screen when it is too small to show everything at once. [Length: 20m] [iOS only]">
         More
       </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_DESCRIPTION" desc="Description of the Google services section on the sign-in confirmation screen. [Length: unlimited]">
-        Google may use your browsing history to personalize Search, ads, and other Google services.
-      </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_TITLE" desc="Title of the Google services section on the sign-in confirmation screen. [Length: 50em]">
-        Personalize Google services
-      </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_DESCRIPTION" desc="Description of the Chrome sync section on the sign-in confirmation screen. [Length: unlimited]">
-        Your bookmarks, history, passwords, and other settings will be synced to your Google Account so you can use them on all your devices.
-      </message>
-      <!-- "Chrome sync" is the Google Cloud Based service used for sync. Thus this string resource is set to "Chrome sync" even for Chromium builds. -->
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_TITLE" desc="Title of the Chrome sync section on the sign-in confirmation screen. [Length: 50em]">
-        Chrome Sync
-      </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_TITLE" desc="Title of the screen confirming selection of an account. [Length: 10em] [iOS only]">
-        Hi, <ph name="FULL_ACCOUNT_NAME">$1<ex>Jane Doe</ex></ph>
-      </message>
       <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_UNDO_BUTTON" desc="Title of the button to undo sign-in. [Length: 20em] [iOS only]">
         Undo
       </message>
@@ -174,9 +152,6 @@
       <message name="IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON" desc="Title of the button to sign in. [Length: 20em] [iOS only]">
         Continue
       </message>
-      <message name="IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_NO_ACCOUNT_BUTTON" desc="Title of the button to sign in when there is no accounts on the device. [Length: 20em] [iOS only]">
-        Sign in
-      </message>
       <message name="IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SKIP_BUTTON" desc="Title of the button to skip the selection of an account. [Length: 20em] [iOS only]">
         Cancel
       </message>
@@ -2069,9 +2044,6 @@
       <message name="IDS_IOS_SIGNIN_PROMO_CONTINUE_AS" desc="Button that the user can press to login without asking the password and continue using Chrome with this acccount. [Length: 9em]">
         Continue as <ph name="NAME">$1<ex>John Doe</ex></ph>
       </message>
-      <message name="IDS_IOS_SIGNIN_PROMO_NOT" desc="Button that the user can press if they are not the profile that Chrome found (opposite of 'Continue as Joe Doe').">
-        Not <ph name="EMAIL">$1<ex>john.doe@example.com</ex>?</ph>
-      </message>
       <message name="IDS_IOS_SIGNIN_PROMO_RECENT_TABS_WITH_UNITY" desc="Text to inform the user that they can sign in and sync to get tabs shared between devices. [iOS only]">
         To get your tabs from your other devices, turn on sync.
       </message>
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index 4f04a69..60c2509 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -24,8 +24,6 @@
     "signed_in_accounts_view_controller.mm",
     "signin_account_selector_view_controller.h",
     "signin_account_selector_view_controller.mm",
-    "signin_confirmation_view_controller.h",
-    "signin_confirmation_view_controller.mm",
     "signin_promo_view_mediator.h",
     "signin_promo_view_mediator.mm",
   ]
@@ -117,8 +115,6 @@
     "//components/signin/public/identity_manager",
     "//components/sync_preferences",
     "//components/sync_preferences:test_support",
-    "//components/unified_consent",
-    "//components/unified_consent:test_support",
     "//components/version_info",
     "//ios/chrome/app/strings:ios_chromium_strings_grit",
     "//ios/chrome/app/strings:ios_strings_grit",
@@ -162,7 +158,6 @@
     ":authentication",
     "unified_consent",
     "//components/signin/public/identity_manager",
-    "//components/unified_consent",
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/signin",
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
index efda3a6..4435c09 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
@@ -17,7 +17,6 @@
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/unified_consent/feature.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/signin/authentication_service.h"
@@ -100,13 +99,8 @@
 }
 
 - (void)commitSyncForBrowserState:(ios::ChromeBrowserState*)browserState {
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    SyncSetupServiceFactory::GetForBrowserState(browserState)
-        ->CommitSyncChanges();
-  } else {
-    SyncSetupServiceFactory::GetForBrowserState(browserState)
-        ->PreUnityCommitChanges();
-  }
+  SyncSetupServiceFactory::GetForBrowserState(browserState)
+      ->CommitSyncChanges();
 }
 
 - (void)startWatchdogTimerForManagedStatus {
diff --git a/ios/chrome/browser/ui/authentication/cells/BUILD.gn b/ios/chrome/browser/ui/authentication/cells/BUILD.gn
index 1d3de93..37c857e 100644
--- a/ios/chrome/browser/ui/authentication/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/cells/BUILD.gn
@@ -9,8 +9,6 @@
   sources = [
     "account_control_item.h",
     "account_control_item.mm",
-    "legacy_account_control_item.h",
-    "legacy_account_control_item.mm",
     "signin_promo_view.h",
     "signin_promo_view.mm",
     "signin_promo_view_configurator.h",
@@ -25,7 +23,6 @@
   deps = [
     "//base",
     "//build:branding_buildflags",
-    "//components/unified_consent",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/ui/collection_view/cells",
@@ -48,7 +45,6 @@
   testonly = true
   sources = [
     "account_control_item_unittest.mm",
-    "legacy_account_control_item_unittest.mm",
     "signin_promo_view_unittest.mm",
     "table_view_account_item_unittest.mm",
   ]
@@ -61,8 +57,6 @@
     "//components/pref_registry",
     "//components/sync_preferences",
     "//components/sync_preferences:test_support",
-    "//components/unified_consent",
-    "//components/unified_consent:test_support",
     "//components/version_info",
     "//ios/chrome/app/strings:ios_chromium_strings_grit",
     "//ios/chrome/app/strings:ios_strings_grit",
diff --git a/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h b/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h
deleted file mode 100644
index dd3d13e..0000000
--- a/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_LEGACY_ACCOUNT_CONTROL_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_LEGACY_ACCOUNT_CONTROL_ITEM_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_style.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
-
-// TODO(crbug.com/894800): Remove this.
-// Item for account collection view and sign-in confirmation view.
-@interface LegacyAccountControlItem : CollectionViewItem
-
-// The style to use for the cell.
-@property(nonatomic, assign) CollectionViewCellStyle cellStyle;
-
-@property(nonatomic, strong) UIImage* image;
-@property(nonatomic, copy) NSString* text;
-@property(nonatomic, copy) NSString* detailText;
-@property(nonatomic, assign) BOOL shouldDisplayError;
-
-// The accessory type for the represented cell.
-@property(nonatomic) MDCCollectionViewCellAccessoryType accessoryType;
-
-@end
-
-// Cell for account settings view with a leading imageView, title text label,
-// and detail text label. The imageView is top-leading aligned.
-@interface LegacyAccountControlCell : MDCCollectionViewCell
-
-@property(nonatomic, readonly, strong) UIImageView* imageView;
-@property(nonatomic, readonly, strong) UILabel* textLabel;
-@property(nonatomic, readonly, strong) UILabel* detailTextLabel;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_LEGACY_ACCOUNT_CONTROL_ITEM_H_
diff --git a/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.mm b/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.mm
deleted file mode 100644
index a2b8359..0000000
--- a/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.mm
+++ /dev/null
@@ -1,230 +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.
-
-#import "ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h"
-
-#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
-#include "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Padding used on the leading and trailing edges of the cell.
-const CGFloat kHorizontalPadding = 16;
-
-// Padding used on the top and bottom edges of the cell.
-const CGFloat kVerticalPadding = 16;
-
-// Padding used between the image and text.
-const CGFloat kHorizontalPaddingBetweenImageAndText = 16;
-
-// Padding between top label and detail label.
-const CGFloat kVerticalPaddingBetweenLabelAndDetailLabel = 8;
-}  // namespace
-
-@implementation LegacyAccountControlItem
-
-@synthesize cellStyle = _cellStyle;
-@synthesize image = _image;
-@synthesize text = _text;
-@synthesize detailText = _detailText;
-@synthesize accessoryType = _accessoryType;
-@synthesize shouldDisplayError = _shouldDisplayError;
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [LegacyAccountControlCell class];
-    self.accessibilityTraits |= UIAccessibilityTraitButton;
-  }
-  return self;
-}
-
-#pragma mark - CollectionViewItem
-
-- (void)configureCell:(LegacyAccountControlCell*)cell {
-  [super configureCell:cell];
-  cell.imageView.image = self.image;
-  [cell cr_setAccessoryType:self.accessoryType];
-
-  BOOL uikitStyle = self.cellStyle == CollectionViewCellStyle::kUIKit;
-  UIFont* textFont = uikitStyle ? [UIFont systemFontOfSize:kUIKitMainFontSize]
-                                : [MDCTypography body2Font];
-  UIColor* textColor = uikitStyle ? UIColorFromRGB(kUIKitMainTextColor)
-                                  : [[MDCPalette greyPalette] tint900];
-  UIFont* detailTextFont =
-      uikitStyle ? [UIFont systemFontOfSize:kUIKitMultilineDetailFontSize]
-                 : [MDCTypography body1Font];
-
-  UIColor* detailTextColor =
-      uikitStyle ? UIColorFromRGB(kUIKitMultilineDetailTextColor)
-                 : [[MDCPalette greyPalette] tint700];
-  if (self.shouldDisplayError) {
-    detailTextColor = [[MDCPalette cr_redPalette] tint700];
-  }
-
-  cell.textLabel.attributedText = [self attributedStringForText:self.text
-                                                           font:textFont
-                                                          color:textColor];
-  cell.detailTextLabel.attributedText =
-      [self attributedStringForText:self.detailText
-                               font:detailTextFont
-                              color:detailTextColor];
-}
-
-#pragma mark - Helper methods
-
-- (NSAttributedString*)attributedStringForText:(NSString*)text
-                                          font:(UIFont*)font
-                                         color:(UIColor*)color {
-  NSMutableParagraphStyle* paragraphStyle =
-      [[NSMutableParagraphStyle alloc] init];
-  paragraphStyle.lineHeightMultiple = 1.15;
-  return [[NSAttributedString alloc]
-      initWithString:text
-          attributes:@{
-            NSParagraphStyleAttributeName : paragraphStyle,
-            NSFontAttributeName : font,
-            NSForegroundColorAttributeName : color
-          }];
-}
-
-@end
-
-@interface LegacyAccountControlCell () {
-  // Constraint used to set padding between image and text when image exists.
-  NSLayoutConstraint* _textLeadingAnchorConstraint;
-}
-@end
-
-@implementation LegacyAccountControlCell
-
-@synthesize imageView = _imageView;
-@synthesize textLabel = _textLabel;
-@synthesize detailTextLabel = _detailTextLabel;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    self.isAccessibilityElement = YES;
-    [self addSubviews];
-    [self setDefaultViewStyling];
-    [self setViewConstraints];
-  }
-  return self;
-}
-
-// Create and add subviews.
-- (void)addSubviews {
-  UIView* contentView = self.contentView;
-  contentView.clipsToBounds = YES;
-
-  _imageView = [[UIImageView alloc] init];
-  _imageView.translatesAutoresizingMaskIntoConstraints = NO;
-  [contentView addSubview:_imageView];
-
-  _textLabel = [[UILabel alloc] init];
-  _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  [contentView addSubview:_textLabel];
-
-  _detailTextLabel = [[UILabel alloc] init];
-  _detailTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  [contentView addSubview:_detailTextLabel];
-}
-
-// Set default imageView styling and default font and text colors for labels.
-- (void)setDefaultViewStyling {
-  _imageView.contentMode = UIViewContentModeCenter;
-
-  _textLabel.font = [MDCTypography body2Font];
-  _textLabel.textColor = [[MDCPalette greyPalette] tint900];
-  _detailTextLabel.font = [MDCTypography body1Font];
-  _detailTextLabel.numberOfLines = 0;
-}
-
-// Set constraints on subviews.
-- (void)setViewConstraints {
-  UIView* contentView = self.contentView;
-
-  _textLeadingAnchorConstraint = [_textLabel.leadingAnchor
-      constraintEqualToAnchor:_imageView.trailingAnchor];
-
-  [NSLayoutConstraint activateConstraints:@[
-    // Set leading anchors.
-    [_imageView.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor
-                                             constant:kHorizontalPadding],
-    [_detailTextLabel.leadingAnchor
-        constraintEqualToAnchor:_textLabel.leadingAnchor],
-    _textLeadingAnchorConstraint,
-
-    // Set vertical anchors.
-    [_textLabel.topAnchor constraintEqualToAnchor:contentView.topAnchor
-                                         constant:kVerticalPadding],
-    [_textLabel.bottomAnchor
-        constraintEqualToAnchor:_detailTextLabel.topAnchor
-                       constant:-kVerticalPaddingBetweenLabelAndDetailLabel],
-    [_imageView.centerYAnchor constraintEqualToAnchor:_textLabel.centerYAnchor],
-    [_detailTextLabel.bottomAnchor
-        constraintEqualToAnchor:contentView.bottomAnchor
-                       constant:-kVerticalPadding],
-
-    // Set trailing anchors.
-    [_textLabel.trailingAnchor
-        constraintLessThanOrEqualToAnchor:contentView.trailingAnchor
-                                 constant:-kHorizontalPadding],
-    [_detailTextLabel.trailingAnchor
-        constraintLessThanOrEqualToAnchor:contentView.trailingAnchor
-                                 constant:-kHorizontalPadding],
-  ]];
-}
-
-#pragma mark - UIView
-
-- (void)layoutSubviews {
-  [super layoutSubviews];
-
-  // Adjust the text label preferredMaxLayoutWidth when the parent's width
-  // changes, for instance on screen rotation.
-  CGFloat parentWidth = self.contentView.frame.size.width;
-  if (_imageView.image) {
-    _detailTextLabel.preferredMaxLayoutWidth =
-        parentWidth - 2.f * kHorizontalPadding -
-        kHorizontalPaddingBetweenImageAndText - _imageView.image.size.width;
-    _textLeadingAnchorConstraint.constant =
-        kHorizontalPaddingBetweenImageAndText;
-  } else {
-    _detailTextLabel.preferredMaxLayoutWidth =
-        parentWidth - 2.f * kHorizontalPadding;
-    _textLeadingAnchorConstraint.constant = 0;
-  }
-
-  // Re-layout with the new preferred width to allow the label to adjust its
-  // height.
-  [super layoutSubviews];
-}
-
-#pragma mark - UICollectionReusableView
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  self.imageView.image = nil;
-  self.textLabel.text = nil;
-  self.detailTextLabel.text = nil;
-  self.accessoryType = MDCCollectionViewCellAccessoryNone;
-  self.detailTextLabel.textColor = [[MDCPalette greyPalette] tint700];
-}
-
-#pragma mark - NSObject(Accessibility)
-
-- (NSString*)accessibilityLabel {
-  return [NSString stringWithFormat:@"%@, %@", self.textLabel.text,
-                                    self.detailTextLabel.text];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item_unittest.mm b/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item_unittest.mm
deleted file mode 100644
index f9a024d..0000000
--- a/ios/chrome/browser/ui/authentication/cells/legacy_account_control_item_unittest.mm
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h"
-
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using LegacyAccountControlItemTest = PlatformTest;
-
-// Tests that the cell is properly configured with image and texts after a call
-// to |configureCell:|. All other cell decorations are default.
-TEST_F(LegacyAccountControlItemTest, ConfigureCellDefault) {
-  LegacyAccountControlItem* item =
-      [[LegacyAccountControlItem alloc] initWithType:0];
-  UIImage* image = [[UIImage alloc] init];
-  NSString* mainText = @"Main text";
-  NSString* detailText = @"Detail text";
-
-  item.image = image;
-  item.text = mainText;
-  item.detailText = detailText;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[LegacyAccountControlCell class]]);
-
-  LegacyAccountControlCell* accountCell = cell;
-  [accountCell prepareForReuse];
-  EXPECT_FALSE(accountCell.imageView.image);
-  EXPECT_FALSE(accountCell.textLabel.text);
-  EXPECT_FALSE(accountCell.detailTextLabel.text);
-  EXPECT_EQ(MDCCollectionViewCellAccessoryNone, accountCell.accessoryType);
-  EXPECT_NSEQ([[MDCPalette greyPalette] tint700],
-              accountCell.detailTextLabel.textColor);
-
-  [item configureCell:cell];
-  EXPECT_NSEQ(image, accountCell.imageView.image);
-  EXPECT_NSEQ(mainText, accountCell.textLabel.text);
-  EXPECT_NSEQ(detailText, accountCell.detailTextLabel.text);
-  EXPECT_EQ(MDCCollectionViewCellAccessoryNone, accountCell.accessoryType);
-  EXPECT_NSEQ([[MDCPalette greyPalette] tint700],
-              accountCell.detailTextLabel.textColor);
-}
-
-// Tests that the cell is properly configured with error and an accessory after
-// a call to |configureCell:|.
-TEST_F(LegacyAccountControlItemTest, ConfigureCellWithErrorAndAccessory) {
-  LegacyAccountControlItem* item =
-      [[LegacyAccountControlItem alloc] initWithType:0];
-  UIImage* image = [[UIImage alloc] init];
-  NSString* mainText = @"Main text";
-  NSString* detailText = @"Detail text";
-
-  item.image = image;
-  item.text = mainText;
-  item.detailText = detailText;
-  item.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
-  item.shouldDisplayError = YES;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[LegacyAccountControlCell class]]);
-
-  LegacyAccountControlCell* accountCell = cell;
-  [accountCell prepareForReuse];
-  EXPECT_FALSE(accountCell.imageView.image);
-  EXPECT_FALSE(accountCell.textLabel.text);
-  EXPECT_FALSE(accountCell.detailTextLabel.text);
-  EXPECT_EQ(MDCCollectionViewCellAccessoryNone, accountCell.accessoryType);
-  EXPECT_NSEQ([[MDCPalette greyPalette] tint700],
-              accountCell.detailTextLabel.textColor);
-
-  [item configureCell:cell];
-  EXPECT_NSEQ(image, accountCell.imageView.image);
-  EXPECT_NSEQ(mainText, accountCell.textLabel.text);
-  EXPECT_NSEQ(detailText, accountCell.detailTextLabel.text);
-  EXPECT_EQ(MDCCollectionViewCellAccessoryCheckmark, accountCell.accessoryType);
-  EXPECT_NSEQ([[MDCPalette cr_redPalette] tint700],
-              accountCell.detailTextLabel.textColor);
-}
diff --git a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.mm b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.mm
index acb9672d..01f59dc8 100644
--- a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.mm
+++ b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
 
 #include "base/strings/sys_string_conversions.h"
-#include "components/unified_consent/feature.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -80,16 +79,9 @@
         forState:UIControlStateNormal];
     signinPromoView.accessibilityLabel =
         GetNSStringF(IDS_IOS_SIGNIN_PROMO_ACCESSIBILITY_LABEL, name16);
-    if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-      [signinPromoView.secondaryButton
-          setTitle:GetNSString(IDS_IOS_SIGNIN_PROMO_CHANGE_ACCOUNT)
-          forState:UIControlStateNormal];
-    } else {
-      [signinPromoView.secondaryButton
-          setTitle:GetNSStringF(IDS_IOS_SIGNIN_PROMO_NOT,
-                                SysNSStringToUTF16(self.userEmail))
-          forState:UIControlStateNormal];
-    }
+    [signinPromoView.secondaryButton
+        setTitle:GetNSString(IDS_IOS_SIGNIN_PROMO_CHANGE_ACCOUNT)
+        forState:UIControlStateNormal];
     UIImage* image = self.userImage;
     if (!image) {
       image = ios::GetChromeBrowserProvider()
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h
index 04fbf9e..93a6243a 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h
@@ -12,7 +12,6 @@
 #include "base/auto_reset.h"
 #include "base/timer/timer.h"
 #import "ios/chrome/browser/signin/constants.h"
-#include "ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h"
 
 @protocol ApplicationCommands;
 @class ChromeIdentity;
@@ -73,8 +72,7 @@
 // this class uses the presentation controller. Therefore the presentation style
 // cannot be changed after the init. The style is set to
 // UIModalPresentationFormSheet by the init method.
-@interface ChromeSigninViewController
-    : UIViewController<SigninConfirmationViewControllerDelegate>
+@interface ChromeSigninViewController : UIViewController
 
 @property(nonatomic, weak) id<ChromeSigninViewControllerDelegate> delegate;
 
@@ -84,9 +82,6 @@
 
 @property(nonatomic, weak, readonly) id<ApplicationCommands> dispatcher;
 
-// Sign-in conformation view controller.
-@property(nonatomic, readonly) SigninConfirmationViewController* confirmationVC;
-
 // Designated initializer.
 // * |browserState| is the current browser state.
 // * |accessPoint| represents the access point that initiated the sign-in.
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 56ead10..3179b2f 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -20,7 +20,6 @@
 #include "components/consent_auditor/consent_auditor.h"
 #include "components/signin/public/base/signin_metrics.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/unified_consent/feature.h"
 #include "components/unified_consent/unified_consent_service.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
@@ -36,7 +35,6 @@
 #import "ios/chrome/browser/ui/authentication/authentication_flow.h"
 #import "ios/chrome/browser/ui/authentication/authentication_ui_util.h"
 #include "ios/chrome/browser/ui/authentication/signin_account_selector_view_controller.h"
-#include "ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h"
 #include "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/util/label_link_controller.h"
@@ -124,14 +122,8 @@
   IDENTITY_PICKER_STATE,
   // Signs in using AuthenticationFlow. If it fails, the state transitions back
   // to IDENTITY_PICKER_STATE.
-  // Unified consent:
-  //   When done, transitions to DONE_STATE.
-  // Non unified consent:
-  //   When done, transitions to IDENTITY_SELECTED_STATE.
+  // When done, transitions to DONE_STATE.
   SIGNIN_PENDING_STATE,
-  // Used only for non unified consent. Shows the confirmation dialog with
-  // SigninConfirmationViewController.
-  IDENTITY_SELECTED_STATE,
   DONE_STATE,
 };
 
@@ -153,13 +145,11 @@
   std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
   ChromeIdentity* _selectedIdentity;
   TimerGeneratorBlock _timerGenerator;
-  BOOL _unifiedConsentEnabled;
 
   // Authentication
   AlertCoordinator* _alertCoordinator;
   AuthenticationFlow* _authenticationFlow;
   BOOL _addedAccount;
-  BOOL _autoSignIn;
   BOOL _didSignIn;
   BOOL _didAcceptSignIn;
   BOOL _didFinishSignIn;
@@ -187,15 +177,9 @@
   std::unique_ptr<base::OneShotTimer> _leavingPendingStateTimer;
 
   // Identity selected state.
-  SigninConfirmationViewController* _confirmationVC;
   BOOL _hasConfirmationScreenReachedBottom;
 }
 
-@synthesize delegate = _delegate;
-@synthesize shouldClearData = _shouldClearData;
-@synthesize dispatcher = _dispatcher;
-@synthesize confirmationVC = _confirmationVC;
-
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                          accessPoint:(signin_metrics::AccessPoint)accessPoint
                          promoAction:(signin_metrics::PromoAction)promoAction
@@ -203,14 +187,12 @@
                           dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super init];
   if (self) {
-    _unifiedConsentEnabled = unified_consent::IsUnifiedConsentFeatureEnabled();
     _browserState = browserState;
     _accessPoint = accessPoint;
     _promoAction = promoAction;
     _dispatcher = dispatcher;
 
     if (identity) {
-      _autoSignIn = !_unifiedConsentEnabled;
       [self setSelectedIdentity:identity];
     }
     _identityServiceObserver.reset(
@@ -272,17 +254,9 @@
   }
   std::vector<int> consent_text_ids;
   int openSettingsStringId = -1;
-  if (_unifiedConsentEnabled) {
-    DCHECK(_unifiedConsentCoordinator);
-    DCHECK(!_confirmationVC);
-    consent_text_ids = _unifiedConsentCoordinator.consentStringIds;
-    openSettingsStringId = _unifiedConsentCoordinator.openSettingsStringId;
-  } else {
-    DCHECK(_confirmationVC);
-    DCHECK(!_unifiedConsentCoordinator);
-    consent_text_ids = _confirmationVC.consentStringIds;
-    openSettingsStringId = _confirmationVC.openSettingsStringId;
-  }
+  DCHECK(_unifiedConsentCoordinator);
+  consent_text_ids = _unifiedConsentCoordinator.consentStringIds;
+  openSettingsStringId = _unifiedConsentCoordinator.openSettingsStringId;
   int consent_confirmation_id = showAccountsSettings
                                     ? openSettingsStringId
                                     : [self acceptSigninButtonStringId];
@@ -314,7 +288,6 @@
 // the sign-in view.
 - (void)signinCompletedWithUnity {
   DCHECK(_didSignIn);
-  DCHECK(_unifiedConsentEnabled);
   // The consent has to be given as soon as the user is signed in. Even when
   // they open the settings through the link.
   unified_consent::UnifiedConsentService* unifiedConsentService =
@@ -334,14 +307,6 @@
                                                 .settingsLinkWasTapped];
 }
 
-- (void)acceptSignInAndCommitSyncChanges {
-  DCHECK(_didSignIn);
-  DCHECK(!_unifiedConsentEnabled);
-  SyncSetupServiceFactory::GetForBrowserState(_browserState)
-      ->PreUnityCommitChanges();
-  [self acceptSignInAndShowAccountsSettings:NO];
-}
-
 - (void)setPrimaryButtonStyling:(MDCButton*)button {
   UIColor* hintColor = UIColor.cr_systemBackgroundColor;
   UIColor* backgroundColor = [UIColor colorNamed:kBlueColor];
@@ -388,10 +353,9 @@
 }
 
 // Configures the primary button as the more button. This can be used in
-// IDENTITY_PICKER_STATE or IDENTITY_SELECTED_STATE.
+// IDENTITY_PICKER_STATE.
 - (void)updatePrimaryButtonAsMoreButton {
-  DCHECK(_currentState == IDENTITY_PICKER_STATE ||
-         _currentState == IDENTITY_SELECTED_STATE)
+  DCHECK_EQ(IDENTITY_PICKER_STATE, _currentState)
       << "Unsupported current state: " << _currentState;
   NSString* primaryButtonTitle = l10n_util::GetNSString(
       IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SCROLL_BUTTON);
@@ -403,10 +367,9 @@
 }
 
 // Configures the primary button for consent validation. This can be used in
-// IDENTITY_PICKER_STATE or IDENTITY_SELECTED_STATE.
+// IDENTITY_PICKER_STATE.
 - (void)updatePrimaryButtonAsConsentValidationButton {
-  DCHECK(_currentState == IDENTITY_PICKER_STATE ||
-         _currentState == IDENTITY_SELECTED_STATE)
+  DCHECK_EQ(IDENTITY_PICKER_STATE, _currentState)
       << "Unsupported current state: " << _currentState;
   [self setPrimaryButtonStyling:_primaryButton];
   [_primaryButton setTitle:[self acceptSigninButtonTitle]
@@ -451,28 +414,24 @@
   CGSize collectionViewSize =
       CGSizeMake(viewSize.width,
                  _primaryButton.frame.origin.y - constants.ButtonTopPadding);
-  if (_unifiedConsentEnabled) {
-    if (isRegularSizeClass &&
-        !UIContentSizeCategoryIsAccessibilityCategory(
-            self.traitCollection.preferredContentSizeCategory)) {
-      // Constraint the size to (|kUCEmbeddedViewMaxWidthForRegularLayout| x
-      // |kUCEmbeddedViewMaxHeightForRegularLayout|) on regular layout. This is
-      // required to avoid having a lot of empty space between |_embeddedView|
-      // and the buttons.
-      if (collectionViewSize.width > kUCEmbeddedViewMaxWidthForRegularLayout) {
-        contentViewOrigin.x = floorf((collectionViewSize.width -
-                                      kUCEmbeddedViewMaxWidthForRegularLayout) /
-                                     2);
-        collectionViewSize.width = kUCEmbeddedViewMaxWidthForRegularLayout;
-      }
-      if (collectionViewSize.height >
-          kUCEmbeddedViewMaxHeightForRegularLayout) {
-        contentViewOrigin.y =
-            floorf((collectionViewSize.height -
-                    kUCEmbeddedViewMaxHeightForRegularLayout) /
-                   2);
-        collectionViewSize.height = kUCEmbeddedViewMaxHeightForRegularLayout;
-      }
+  if (isRegularSizeClass &&
+      !UIContentSizeCategoryIsAccessibilityCategory(
+          self.traitCollection.preferredContentSizeCategory)) {
+    // Constraint the size to (|kUCEmbeddedViewMaxWidthForRegularLayout| x
+    // |kUCEmbeddedViewMaxHeightForRegularLayout|) on regular layout. This is
+    // required to avoid having a lot of empty space between |_embeddedView|
+    // and the buttons.
+    if (collectionViewSize.width > kUCEmbeddedViewMaxWidthForRegularLayout) {
+      contentViewOrigin.x = floorf(
+          (collectionViewSize.width - kUCEmbeddedViewMaxWidthForRegularLayout) /
+          2);
+      collectionViewSize.width = kUCEmbeddedViewMaxWidthForRegularLayout;
+    }
+    if (collectionViewSize.height > kUCEmbeddedViewMaxHeightForRegularLayout) {
+      contentViewOrigin.y = floorf((collectionViewSize.height -
+                                    kUCEmbeddedViewMaxHeightForRegularLayout) /
+                                   2);
+      collectionViewSize.height = kUCEmbeddedViewMaxHeightForRegularLayout;
     }
   }
   [_embeddedView setFrame:CGRect{contentViewOrigin, collectionViewSize}];
@@ -507,11 +466,6 @@
 
 #pragma mark - UIAdaptivePresentationController
 
-- (BOOL)presentationControllerShouldDismiss:
-    (UIPresentationController*)presentationController {
-  return _unifiedConsentEnabled;
-}
-
 - (void)presentationControllerDidDismiss:
     (UIPresentationController*)presentationController {
   [self onSecondaryButtonPressed:self];
@@ -540,9 +494,7 @@
 }
 
 - (int)acceptSigninButtonStringId {
-  return _unifiedConsentEnabled
-             ? IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON
-             : IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON;
+  return IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON;
 }
 
 - (NSString*)acceptSigninButtonTitle {
@@ -626,10 +578,6 @@
   }
   [self identityListChanged];
   [self setSelectedIdentity:identity];
-  if (!_unifiedConsentEnabled) {
-    _addedAccount = YES;
-    [self changeToState:SIGNIN_PENDING_STATE];
-  }
 }
 
 - (void)onAccountSigninCompletion:(BOOL)success {
@@ -638,11 +586,7 @@
     DCHECK(!_didSignIn);
     _didSignIn = YES;
     [_delegate didSignIn:self];
-    if (_unifiedConsentEnabled) {
-      [self signinCompletedWithUnity];
-    } else {
-      [self changeToState:IDENTITY_SELECTED_STATE];
-    }
+    [self signinCompletedWithUnity];
   } else {
     [self changeToState:IDENTITY_PICKER_STATE];
     [_unifiedConsentCoordinator resetSettingLinkTapped];
@@ -687,22 +631,17 @@
     case SIGNIN_PENDING_STATE:
       [self enterSigninPendingState];
       break;
-    case IDENTITY_SELECTED_STATE:
-      [self enterIdentitySelectedState];
-      break;
     case DONE_STATE:
       break;
   }
 }
 
 - (void)changeToState:(AuthenticationState)nextState {
-  CHECK(nextState != IDENTITY_SELECTED_STATE || !_unifiedConsentEnabled);
   if (_currentState == nextState)
     return;
   _ongoingStateChange = YES;
   switch (_currentState) {
     case NULL_STATE:
-      DCHECK_NE(IDENTITY_SELECTED_STATE, nextState);
       [self enterState:nextState];
       return;
     case IDENTITY_PICKER_STATE:
@@ -712,10 +651,6 @@
     case SIGNIN_PENDING_STATE:
       [self leaveSigninPendingState:nextState];
       return;
-    case IDENTITY_SELECTED_STATE:
-      DCHECK_EQ(IDENTITY_PICKER_STATE, nextState);
-      [self leaveIdentitySelectedState:nextState];
-      return;
     case DONE_STATE:
       // Ignored
       return;
@@ -729,58 +664,35 @@
 // more button, the consent validation or sign-in button.
 - (void)updatePrimaryButtonForIdentityPickerState {
   DCHECK_EQ(IDENTITY_PICKER_STATE, _currentState);
-  if (_unifiedConsentEnabled) {
-    if (!_unifiedConsentCoordinator.selectedIdentity) {
-      [_primaryButton setTitle:l10n_util::GetNSString(
-                                   IDS_IOS_ACCOUNT_UNIFIED_CONSENT_ADD_ACCOUNT)
-                      forState:UIControlStateNormal];
-      [self setPrimaryButtonStyling:_primaryButton];
-    } else if (!_hasConfirmationScreenReachedBottom) {
-      [self updatePrimaryButtonAsMoreButton];
-    } else {
-      [self updatePrimaryButtonAsConsentValidationButton];
-    }
-  } else {
-    bool hasIdentities = ios::GetChromeBrowserProvider()
-                             ->GetChromeIdentityService()
-                             ->HasIdentities();
-    NSString* primaryButtonTitle =
-        hasIdentities
-            ? l10n_util::GetNSString(
-                  IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON)
-            : l10n_util::GetNSString(
-                  IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_NO_ACCOUNT_BUTTON);
-    [_primaryButton setTitle:primaryButtonTitle forState:UIControlStateNormal];
+  if (!_unifiedConsentCoordinator.selectedIdentity) {
+    [_primaryButton setTitle:l10n_util::GetNSString(
+                                 IDS_IOS_ACCOUNT_UNIFIED_CONSENT_ADD_ACCOUNT)
+                    forState:UIControlStateNormal];
     [self setPrimaryButtonStyling:_primaryButton];
+  } else if (!_hasConfirmationScreenReachedBottom) {
+    [self updatePrimaryButtonAsMoreButton];
+  } else {
+    [self updatePrimaryButtonAsConsentValidationButton];
   }
   [self.view setNeedsLayout];
 }
 
 - (void)enterIdentityPickerState {
   // Add the account selector view controller.
-  if (_unifiedConsentEnabled) {
-    if (!_unifiedConsentCoordinator) {
-      // The user can refuse to sign-in into a managed account, so the state
-      // returns to "IdentityPicker". In that case, there is no need to create a
-      // new UnifiedConsentCoordinator. The current one should be used.
-      _unifiedConsentCoordinator = [[UnifiedConsentCoordinator alloc] init];
-      _unifiedConsentCoordinator.delegate = self;
-      if (_selectedIdentity)
-        _unifiedConsentCoordinator.selectedIdentity = _selectedIdentity;
-      _unifiedConsentCoordinator.autoOpenIdentityPicker =
-          _promoAction == signin_metrics::PromoAction::PROMO_ACTION_NOT_DEFAULT;
-      [_unifiedConsentCoordinator start];
-      [self
-          showEmbeddedViewController:_unifiedConsentCoordinator.viewController];
-    }
-    DCHECK_EQ(_embeddedView, _unifiedConsentCoordinator.viewController.view);
-  } else {
-    // Reset the selected identity.
-    [self setSelectedIdentity:nil];
-    _accountSelectorVC = [[SigninAccountSelectorViewController alloc] init];
-    _accountSelectorVC.delegate = self;
-    [self showEmbeddedViewController:_accountSelectorVC];
+  if (!_unifiedConsentCoordinator) {
+    // The user can refuse to sign-in into a managed account, so the state
+    // returns to "IdentityPicker". In that case, there is no need to create a
+    // new UnifiedConsentCoordinator. The current one should be used.
+    _unifiedConsentCoordinator = [[UnifiedConsentCoordinator alloc] init];
+    _unifiedConsentCoordinator.delegate = self;
+    if (_selectedIdentity)
+      _unifiedConsentCoordinator.selectedIdentity = _selectedIdentity;
+    _unifiedConsentCoordinator.autoOpenIdentityPicker =
+        _promoAction == signin_metrics::PromoAction::PROMO_ACTION_NOT_DEFAULT;
+    [_unifiedConsentCoordinator start];
+    [self showEmbeddedViewController:_unifiedConsentCoordinator.viewController];
   }
+  DCHECK_EQ(_embeddedView, _unifiedConsentCoordinator.viewController.view);
 
   // Update the button title.
   [self updatePrimaryButtonForIdentityPickerState];
@@ -830,10 +742,6 @@
         // When the unified consent is enabled, the |_unifiedConsentVC| has to
         // be kept, so the consent can be recorded (with the string ids), once
         // the sign-in is done.
-        if (!_unifiedConsentEnabled) {
-          [self removeEmbeddedViewController:_accountSelectorVC];
-          _accountSelectorVC = nil;
-        }
         [self enterState:nextState];
       }];
 }
@@ -903,73 +811,6 @@
   }
 }
 
-#pragma mark - IdentitySelectedState
-
-// Updates the primary button for IDENTITY_SELECTED_STATE to be either the
-// more button or the consent validation.
-- (void)updatePrimaryButtonForIdentitySelectedState {
-  DCHECK_EQ(IDENTITY_SELECTED_STATE, _currentState);
-  DCHECK(!_unifiedConsentEnabled);
-  if (_hasConfirmationScreenReachedBottom) {
-    [self updatePrimaryButtonAsConsentValidationButton];
-  } else {
-    [self updatePrimaryButtonAsMoreButton];
-  }
-  [self.view setNeedsLayout];
-}
-
-- (void)enterIdentitySelectedState {
-  _confirmationVC = [[SigninConfirmationViewController alloc]
-      initWithIdentity:self.selectedIdentity];
-  _confirmationVC.delegate = self;
-
-  _hasConfirmationScreenReachedBottom = NO;
-  [self showEmbeddedViewController:_confirmationVC];
-
-  [self updatePrimaryButtonForIdentitySelectedState];
-  NSString* secondaryButtonTitle = l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_UNDO_BUTTON);
-  [_secondaryButton setTitle:secondaryButtonTitle
-                    forState:UIControlStateNormal];
-  [self.view setNeedsLayout];
-  _primaryButton.hidden = YES;
-  _secondaryButton.hidden = YES;
-  [UIView transitionWithView:_primaryButton
-                    duration:kAnimationDuration
-                     options:UIViewAnimationOptionTransitionCrossDissolve
-                  animations:^{
-                    _primaryButton.hidden = NO;
-                  }
-                  completion:nil];
-  [UIView transitionWithView:_secondaryButton
-                    duration:kAnimationDuration
-                     options:UIViewAnimationOptionTransitionCrossDissolve
-                  animations:^{
-                    _secondaryButton.hidden = NO;
-                  }
-                  completion:nil];
-}
-
-- (void)reloadIdentitySelectedState {
-  BOOL isSelectedIdentityValid = ios::GetChromeBrowserProvider()
-                                     ->GetChromeIdentityService()
-                                     ->IsValidIdentity(self.selectedIdentity);
-  if (!isSelectedIdentityValid) {
-    [self changeToState:IDENTITY_PICKER_STATE];
-    return;
-  }
-}
-
-- (void)leaveIdentitySelectedState:(AuthenticationState)nextState {
-  [self removeEmbeddedViewController:_confirmationVC];
-  _confirmationVC = nil;
-  [self setPrimaryButtonStyling:_primaryButton];
-  _primaryButton.hidden = YES;
-  _secondaryButton.hidden = YES;
-  [self undoSignIn];
-  [self enterState:nextState];
-}
-
 #pragma mark - UIViewController
 
 - (void)viewDidLoad {
@@ -1016,11 +857,7 @@
   if (_currentState != NULL_STATE) {
     return;
   }
-  if (_autoSignIn) {
-    [self enterState:SIGNIN_PENDING_STATE];
-  } else {
-    [self enterState:IDENTITY_PICKER_STATE];
-  }
+  [self enterState:IDENTITY_PICKER_STATE];
 }
 
 - (void)viewSafeAreaInsetsDidChange {
@@ -1041,9 +878,6 @@
         case IDENTITY_PICKER_STATE:
           [self updatePrimaryButtonForIdentityPickerState];
           break;
-        case IDENTITY_SELECTED_STATE:
-          [self updatePrimaryButtonForIdentitySelectedState];
-          break;
         case NULL_STATE:
         case SIGNIN_PENDING_STATE:
         case DONE_STATE:
@@ -1063,43 +897,21 @@
       NOTREACHED();
       return;
     case IDENTITY_PICKER_STATE: {
-      if (_unifiedConsentEnabled) {
-        if (!_unifiedConsentCoordinator.selectedIdentity) {
-          [self openAuthenticationDialogAddIdentity];
-        } else if (!_hasConfirmationScreenReachedBottom) {
-          [_unifiedConsentCoordinator scrollToBottom];
-        } else {
-          ChromeIdentity* selectedIdentity =
-              _unifiedConsentCoordinator.selectedIdentity;
-          [self setSelectedIdentity:selectedIdentity];
-          [self changeToState:SIGNIN_PENDING_STATE];
-        }
+      if (!_unifiedConsentCoordinator.selectedIdentity) {
+        [self openAuthenticationDialogAddIdentity];
+      } else if (!_hasConfirmationScreenReachedBottom) {
+        [_unifiedConsentCoordinator scrollToBottom];
       } else {
-        if (_interactionManager) {
-          // Adding an account is ongoing, ignore the button press.
-          return;
-        }
         ChromeIdentity* selectedIdentity =
-            [_accountSelectorVC selectedIdentity];
+            _unifiedConsentCoordinator.selectedIdentity;
         [self setSelectedIdentity:selectedIdentity];
-        if (selectedIdentity) {
-          [self changeToState:SIGNIN_PENDING_STATE];
-        } else {
-          [self openAuthenticationDialogAddIdentity];
-        }
+        [self changeToState:SIGNIN_PENDING_STATE];
       }
       return;
     }
     case SIGNIN_PENDING_STATE:
       NOTREACHED();
       return;
-    case IDENTITY_SELECTED_STATE:
-      if (_hasConfirmationScreenReachedBottom) {
-        [self acceptSignInAndCommitSyncChanges];
-      } else {
-        [_confirmationVC scrollToBottom];
-      }
-      return;
     case DONE_STATE:
       // Ignored
       return;
@@ -1114,9 +926,7 @@
       return;
     case IDENTITY_PICKER_STATE:
       if (!_didFinishSignIn) {
-        if (_unifiedConsentEnabled) {
-          base::RecordAction(base::UserMetricsAction("Signin_Undo_Signin"));
-        }
+        base::RecordAction(base::UserMetricsAction("Signin_Undo_Signin"));
         _didFinishSignIn = YES;
         [_delegate didSkipSignIn:self];
       }
@@ -1127,10 +937,6 @@
       [self undoSignIn];
       [self changeToState:IDENTITY_PICKER_STATE];
       return;
-    case IDENTITY_SELECTED_STATE:
-      base::RecordAction(base::UserMetricsAction("Signin_Undo_Signin"));
-      [self changeToState:IDENTITY_PICKER_STATE];
-      return;
     case DONE_STATE:
       // Ignored
       return;
@@ -1151,9 +957,6 @@
     case SIGNIN_PENDING_STATE:
       [self reloadSigninPendingState];
       return;
-    case IDENTITY_SELECTED_STATE:
-      [self reloadIdentitySelectedState];
-      return;
   }
 }
 
@@ -1223,9 +1026,6 @@
     case IDENTITY_PICKER_STATE:
       [self updatePrimaryButtonForIdentityPickerState];
       break;
-    case IDENTITY_SELECTED_STATE:
-      [self updatePrimaryButtonForIdentitySelectedState];
-      break;
   }
 }
 
@@ -1272,26 +1072,10 @@
   [self openAuthenticationDialogAddIdentity];
 }
 
-#pragma mark - SigninConfirmationViewControllerDelegate
-
-// Callback for when a link in the label is pressed.
-- (void)signinConfirmationControllerDidTapSettingsLink:
-    (SigninConfirmationViewController*)controller {
-  DCHECK_EQ(_confirmationVC, controller);
-
-  [self acceptSignInAndShowAccountsSettings:YES];
-}
-
-- (void)signinConfirmationControllerDidReachBottom:
-    (SigninConfirmationViewController*)controller {
-  [self didReachBottom];
-}
-
 #pragma mark - UnifiedConsentCoordinatorDelegate
 
 - (void)unifiedConsentCoordinatorDidTapSettingsLink:
     (UnifiedConsentCoordinator*)coordinator {
-  DCHECK_EQ(_unifiedConsentCoordinator, coordinator);
   DCHECK_EQ(IDENTITY_PICKER_STATE, _currentState);
   ChromeIdentity* selectedIdentity =
       _unifiedConsentCoordinator.selectedIdentity;
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
index a21800d..6bf41f7b 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
@@ -10,12 +10,9 @@
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/timer/mock_timer.h"
 #include "components/consent_auditor/consent_auditor.h"
 #include "components/consent_auditor/fake_consent_auditor.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/unified_consent/feature.h"
-#include "components/unified_consent/scoped_unified_consent.h"
 #include "components/version_info/version_info.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
@@ -84,7 +81,8 @@
 
 namespace {
 
-// Returns the first TransparentLinkButton view in |mainView|.
+// Returns the first view in |mainView| with the accessibility identifier:
+// |accessibilityID|.
 UIView* FindViewWithAccessibilityID(UIView* mainView,
                                     NSString* accessibilityID) {
   NSMutableArray* views = [NSMutableArray array];
@@ -100,6 +98,7 @@
   return nil;
 }
 
+// Returns the Settings link button to open the advanced sign-in settings view.
 UIButton* FindLinkButton(UIView* mainView) {
   UIView* view = FindViewWithAccessibilityID(
       mainView, kAdvancedSigninSettingsLinkIdentifier);
@@ -107,10 +106,6 @@
   return base::mac::ObjCCastStrict<UIButton>(view);
 }
 
-const bool kUnifiedConsentParam[] = {
-    false, true,
-};
-
 static std::unique_ptr<KeyedService> CreateFakeConsentAuditor(
     web::BrowserState* context) {
   return std::make_unique<consent_auditor::FakeConsentAuditor>();
@@ -130,14 +125,6 @@
 class ChromeSigninViewControllerTest
     : public PlatformTest,
       public ::testing::WithParamInterface<bool> {
- public:
-  ChromeSigninViewControllerTest()
-      : unified_consent_enabled_(GetParam()),
-        scoped_unified_consent_(
-            unified_consent_enabled_
-                ? unified_consent::UnifiedConsentFeatureState::kEnabled
-                : unified_consent::UnifiedConsentFeatureState::kDisabled) {}
-
  protected:
   void SetUp() override {
     PlatformTest::SetUp();
@@ -174,22 +161,10 @@
                   dispatcher:nil];
     vc_delegate_ = [[FakeChromeSigninViewControllerDelegate alloc] init];
     vc_.delegate = vc_delegate_;
-    __block base::MockOneShotTimer* mock_timer_ptr = nullptr;
-    if (!unified_consent_enabled_) {
-      vc_.timerGenerator = ^std::unique_ptr<base::OneShotTimer>() {
-        auto mock_timer = std::make_unique<base::MockOneShotTimer>();
-        mock_timer_ptr = mock_timer.get();
-        return mock_timer;
-      };
-    }
     UIScreen* screen = [UIScreen mainScreen];
     UIWindow* window = [[UIWindow alloc] initWithFrame:screen.bounds];
     [window makeKeyAndVisible];
     [window addSubview:[vc_ view]];
-    if (!unified_consent_enabled_) {
-      ASSERT_TRUE(mock_timer_ptr);
-      mock_timer_ptr->Fire();
-    }
     window_ = window;
   }
 
@@ -271,46 +246,19 @@
   // then the consent is given. The list is ordered according to the position
   // on the screen.
   const std::vector<int> ExpectedConsentStringIds() const {
-    if (unified_consent_enabled_) {
-      return {
-          IDS_IOS_ACCOUNT_UNIFIED_CONSENT_TITLE,
-          IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_TITLE,
-          IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_SUBTITLE,
-          IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SETTINGS,
-      };
-    }
     return {
-        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_TITLE,
-        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_DESCRIPTION,
-        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_TITLE,
-        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_DESCRIPTION,
-        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OPEN_SETTINGS,
+        IDS_IOS_ACCOUNT_UNIFIED_CONSENT_TITLE,
+        IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_TITLE,
+        IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_SUBTITLE,
+        IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SETTINGS,
     };
   }
 
   // Returns the white list of strings that can be displayed on screen but
   // should not be part of ExpectedConsentStringIds().
   NSSet<NSString*>* WhiteListLocalizedStrings() const {
-    if (unified_consent_enabled_) {
-      return [NSSet setWithObjects:@"Fake Foo 1", @"foo1@gmail.com", @"CANCEL",
-                                   @"YES, I'M IN", nil];
-    }
-    return [NSSet setWithObjects:@"Hi, Fake Foo 1", @"foo1@gmail.com",
-                                 @"OK, GOT IT", @"UNDO", nil];
-  }
-
-  int ConfirmationStringId() const {
-    if (unified_consent_enabled_) {
-      return IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON;
-    }
-    return IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON;
-  }
-
-  int SettingsConfirmationStringId() const {
-    if (unified_consent_enabled_) {
-      return IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SETTINGS;
-    }
-    return IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OPEN_SETTINGS;
+    return [NSSet setWithObjects:@"Fake Foo 1", @"foo1@gmail.com", @"CANCEL",
+                                 @"YES, I'M IN", nil];
   }
 
   // Returns true if the primary button is visible and its tile is equal the
@@ -342,7 +290,7 @@
   }
 
   // Scrolls to the bottom if needed and returns once the primary button is
-  // found with the confirmation title (based on ConfirmationStringId()).
+  // found with the confirmation title.
   // The scroll is done without animation. Otherwise, the scroll view doesn't
   // scroll correctly inside WaitUntilConditionOrTimeout().
   void ScrollConsentViewToBottom() {
@@ -356,7 +304,8 @@
                                consent_scroll_view.contentInset.bottom);
         [consent_scroll_view setContentOffset:bottom_offset animated:NO];
       }
-      return IsPrimaryButtonVisibleWithTitle(ConfirmationStringId());
+      return IsPrimaryButtonVisibleWithTitle(
+          IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON);
     };
     bool condition_met =
         WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition);
@@ -391,8 +340,6 @@
     EXPECT_TRUE(condition_met) << base::SysNSStringToUTF8(failureExplaination);
   }
 
-  bool unified_consent_enabled_;
-  unified_consent::ScopedUnifiedConsent scoped_unified_consent_;
   web::WebTaskEnvironment task_environment_;
   std::unique_ptr<TestChromeBrowserState> context_;
   FakeChromeIdentity* identity_;
@@ -400,25 +347,20 @@
   ChromeSigninViewController* vc_;
   consent_auditor::FakeConsentAuditor* fake_consent_auditor_;
   signin::IdentityManager* identity_manager_;
-  base::MockOneShotTimer* mock_timer_ptr_ = nullptr;
   FakeChromeSigninViewControllerDelegate* vc_delegate_;
 };
 
-INSTANTIATE_TEST_SUITE_P(,
-                         ChromeSigninViewControllerTest,
-                         ::testing::ValuesIn(kUnifiedConsentParam));
-
 // Tests that all strings on the screen are either part of the consent string
 // list defined in FakeConsentAuditor::ExpectedConsentStringIds()), or are part
 // of the white list strings defined in
 // FakeConsentAuditor::WhiteListLocalizedStrings().
-TEST_P(ChromeSigninViewControllerTest, TestAllStrings) {
+TEST_F(ChromeSigninViewControllerTest, TestAllStrings) {
   WaitAndExpectAllStringsOnScreen();
 }
 
 // Tests when the user taps on "OK GOT IT", that RecordGaiaConsent() is called
 // with the expected list of string ids, and confirmation string id.
-TEST_P(ChromeSigninViewControllerTest, TestConsentWithOKGOTIT) {
+TEST_F(ChromeSigninViewControllerTest, TestConsentWithOKGOTIT) {
   WaitAndExpectAllStringsOnScreen();
   [vc_.primaryButton sendActionsForControlEvents:UIControlEventTouchUpInside];
   ConditionBlock condition = ^bool() {
@@ -428,7 +370,7 @@
   const std::vector<int>& recorded_ids =
       fake_consent_auditor_->recorded_id_vectors().at(0);
   EXPECT_EQ(ExpectedConsentStringIds(), recorded_ids);
-  EXPECT_EQ(ConfirmationStringId(),
+  EXPECT_EQ(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON,
             fake_consent_auditor_->recorded_confirmation_ids().at(0));
   EXPECT_EQ(consent_auditor::ConsentStatus::GIVEN,
             fake_consent_auditor_->recorded_statuses().at(0));
@@ -441,7 +383,7 @@
 }
 
 // Tests that RecordGaiaConsent() is not called when the user taps on UNDO.
-TEST_P(ChromeSigninViewControllerTest, TestRefusingConsent) {
+TEST_F(ChromeSigninViewControllerTest, TestRefusingConsent) {
   WaitAndExpectAllStringsOnScreen();
   [vc_.secondaryButton sendActionsForControlEvents:UIControlEventTouchUpInside];
   EXPECT_EQ(0ul, fake_consent_auditor_->recorded_id_vectors().size());
@@ -450,24 +392,19 @@
 
 // Tests that RecordGaiaConsent() is called with the expected list of string
 // ids, and settings confirmation string id.
-TEST_P(ChromeSigninViewControllerTest, TestConsentWithSettings) {
+TEST_F(ChromeSigninViewControllerTest, TestConsentWithSettings) {
   WaitAndExpectAllStringsOnScreen();
-  if (unified_consent_enabled_) {
-    UIButton* linkButton = FindLinkButton(vc_.view);
-    EXPECT_NE(nil, linkButton);
-    [linkButton sendActionsForControlEvents:UIControlEventTouchUpInside];
-    ConditionBlock condition = ^bool() {
-      return this->vc_delegate_.didSigninCalled;
-    };
-    EXPECT_TRUE(
-        WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition));
-  } else {
-    [vc_ signinConfirmationControllerDidTapSettingsLink:vc_.confirmationVC];
-  }
+  UIButton* linkButton = FindLinkButton(vc_.view);
+  EXPECT_NE(nil, linkButton);
+  [linkButton sendActionsForControlEvents:UIControlEventTouchUpInside];
+  ConditionBlock condition = ^bool() {
+    return this->vc_delegate_.didSigninCalled;
+  };
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition));
   const std::vector<int>& recorded_ids =
       fake_consent_auditor_->recorded_id_vectors().at(0);
   EXPECT_EQ(ExpectedConsentStringIds(), recorded_ids);
-  EXPECT_EQ(SettingsConfirmationStringId(),
+  EXPECT_EQ(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SETTINGS,
             fake_consent_auditor_->recorded_confirmation_ids().at(0));
   EXPECT_EQ(consent_auditor::ConsentStatus::GIVEN,
             fake_consent_auditor_->recorded_statuses().at(0));
diff --git a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h b/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h
deleted file mode 100644
index 51766eb..0000000
--- a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_H_
-
-#import <UIKit/UIKit.h>
-
-#include <vector>
-
-#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
-
-extern NSString* const kSigninConfirmationCollectionViewId;
-
-@class ChromeIdentity;
-@class SigninConfirmationViewController;
-
-@protocol SigninConfirmationViewControllerDelegate
-
-// Informs the delegate that the link to open the sync settings was tapped.
-- (void)signinConfirmationControllerDidTapSettingsLink:
-    (SigninConfirmationViewController*)controller;
-
-// Informs the delegate that the confirmation view has been scrolled all
-// the way to the bottom.
-- (void)signinConfirmationControllerDidReachBottom:
-    (SigninConfirmationViewController*)controller;
-
-@end
-
-// Controller of the sign-in confirmation collection view.
-@interface SigninConfirmationViewController : CollectionViewController
-
-@property(nonatomic, weak) id<SigninConfirmationViewControllerDelegate>
-    delegate;
-
-// String id for text to open the settings.
-@property(nonatomic, readonly) int openSettingsStringId;
-
-- (instancetype)initWithIdentity:(ChromeIdentity*)identity
-    NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)initWithLayout:(UICollectionViewLayout*)layout
-                         style:(CollectionViewControllerStyle)style
-    NS_UNAVAILABLE;
-
-// Scrolls the confirmation view to the bottom of its content.
-- (void)scrollToBottom;
-
-// List of string ids used for the user consent. The string ids order matches
-// the way they appear on the screen.
-- (const std::vector<int>&)consentStringIds;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm b/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm
deleted file mode 100644
index 423a6f7..0000000
--- a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm
+++ /dev/null
@@ -1,415 +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.
-
-#include "ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h"
-
-#import "base/mac/foundation_util.h"
-#include "base/metrics/user_metrics.h"
-#import "base/strings/sys_string_conversions.h"
-#include "components/google/core/common/google_util.h"
-#include "ios/chrome/browser/application_context.h"
-#include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
-#import "ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h"
-#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/material_components/chrome_app_bar_view_controller.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/string_util.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#include "ios/chrome/grit/ios_chromium_strings.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#include "ios/public/provider/chrome/browser/images/branded_image_provider.h"
-#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
-#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
-#include "ios/public/provider/chrome/browser/signin/signin_resources_provider.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-NSString* const kSigninConfirmationCollectionViewId =
-    @"SigninConfirmationCollectionView";
-
-namespace {
-const CGFloat kAccountImageDimension = 64.;
-const CGFloat kHeaderViewMinHeight = 170.;
-const CGFloat kHeaderViewHeightMultiplier = 0.33;
-const CGFloat kContentViewBottomInset = 40.;
-// Leading separator inset.
-const CGFloat kLeadingSeparatorInset = 30.;
-// Trailing separator inset.
-const CGFloat kTrailingSeparatorInset = 16.;
-
-UIImage* GetImageForIdentity(ChromeIdentity* identity) {
-  UIImage* image = ios::GetChromeBrowserProvider()
-                       ->GetChromeIdentityService()
-                       ->GetCachedAvatarForIdentity(identity);
-  if (!image) {
-    image = ios::GetChromeBrowserProvider()
-                ->GetSigninResourcesProvider()
-                ->GetDefaultAvatar();
-    // No cached image, trigger a fetch, which will notify all observers
-    // (including the corresponding AccountViewBase).
-    ios::GetChromeBrowserProvider()
-        ->GetChromeIdentityService()
-        ->GetAvatarForIdentity(identity, nil);
-  }
-  return image;
-}
-
-typedef NS_ENUM(NSInteger, SectionIdentifier) {
-  SectionIdentifierInfo = kSectionIdentifierEnumZero,
-};
-
-typedef NS_ENUM(NSInteger, ItemType) {
-  ItemTypeSync = kItemTypeEnumZero,
-  ItemTypeGoogleServices,
-  ItemTypeFooter,
-};
-}
-
-#pragma mark - SigninConfirmationViewController
-
-@interface SigninConfirmationViewController ()<
-    ChromeIdentityServiceObserver,
-    CollectionViewFooterLinkDelegate> {
-  ChromeIdentity* _identity;
-  std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
-  __weak UIImage* _oldImage;
-  UIImageView* _imageView;
-  UILabel* _titleLabel;
-  UILabel* _emailLabel;
-  // List of string ids used for the user consent. The string ids order matches
-  // the way they appear on the screen.
-  std::vector<int> _consentStringIds;
-}
-@end
-
-@implementation SigninConfirmationViewController
-
-@synthesize delegate;
-
-- (instancetype)initWithIdentity:(ChromeIdentity*)identity {
-  UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
-  self =
-      [super initWithLayout:layout style:CollectionViewControllerStyleAppBar];
-  if (self) {
-    _identity = identity;
-    _identityServiceObserver.reset(
-        new ChromeIdentityServiceObserverBridge(self));
-  }
-  return self;
-}
-
-- (void)scrollToBottom {
-  CGPoint bottomOffset = CGPointMake(
-      0, self.collectionView.contentSize.height -
-             self.collectionView.bounds.size.height + kContentViewBottomInset);
-  [self.collectionView setContentOffset:bottomOffset animated:YES];
-}
-
-- (const std::vector<int>&)consentStringIds {
-  return _consentStringIds;
-}
-
-- (int)openSettingsStringId {
-  return IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OPEN_SETTINGS;
-}
-
-#pragma mark - UIViewController
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-  self.view.accessibilityIdentifier = kSigninConfirmationCollectionViewId;
-
-  // Configure the header.
-  MDCFlexibleHeaderView* headerView = self.appBarViewController.headerView;
-  headerView.canOverExtend = YES;
-  headerView.maximumHeight = 200;
-  headerView.shiftBehavior = MDCFlexibleHeaderShiftBehaviorEnabled;
-  headerView.backgroundColor = [UIColor whiteColor];
-  [headerView addSubview:[self contentViewWithFrame:headerView.bounds]];
-  self.appBarViewController.navigationBar.hidesBackButton = YES;
-  self.collectionView.backgroundColor = [UIColor clearColor];
-  [headerView changeContentInsets:^{
-    UIEdgeInsets contentInset = self.collectionView.contentInset;
-    contentInset.bottom += kContentViewBottomInset;
-    self.collectionView.contentInset = contentInset;
-  }];
-
-  // Load the contents of the collection view.
-  [self loadModel];
-}
-
-- (void)viewDidAppear:(BOOL)animated {
-  [super viewDidAppear:animated];
-
-  BOOL didSend = [self
-      sendDidReachBottomIfNecessary:self.collectionView.collectionViewLayout
-                                        .collectionViewContentSize.height];
-  if (!didSend && [self isMovingToParentViewController]) {
-    // The confirmation screen just appeared and there wasn't enough space to
-    // show the full screen (since the scroll hasn't reach the botton). This
-    // means the "More" button is actually necessary.
-    base::RecordAction(base::UserMetricsAction("Signin_MoreButton_Shown"));
-  }
-}
-
-- (UIView*)contentViewWithFrame:(CGRect)frame {
-  UIView* contentView = [[UIView alloc] initWithFrame:frame];
-  contentView.autoresizingMask =
-      (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
-  contentView.clipsToBounds = YES;
-  _imageView = [[UIImageView alloc] init];
-  _imageView.translatesAutoresizingMaskIntoConstraints = NO;
-
-  _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-  _titleLabel.textColor = [[MDCPalette greyPalette] tint900];
-  _titleLabel.font = [MDCTypography headlineFont];
-  _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
-
-  _emailLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-  _emailLabel.textColor = [[MDCPalette greyPalette] tint700];
-  _emailLabel.font = [MDCTypography body1Font];
-  _emailLabel.translatesAutoresizingMaskIntoConstraints = NO;
-
-  [self updateViewWithIdentity:_identity];
-
-  UIView* divider = [[UIView alloc] initWithFrame:CGRectZero];
-  divider.backgroundColor = [[MDCPalette greyPalette] tint300];
-  divider.translatesAutoresizingMaskIntoConstraints = NO;
-
-  UILayoutGuide* layoutGuide1 = [[UILayoutGuide alloc] init];
-  UILayoutGuide* layoutGuide2 = [[UILayoutGuide alloc] init];
-
-  [contentView addSubview:_imageView];
-  [contentView addSubview:_titleLabel];
-  [contentView addSubview:_emailLabel];
-  [contentView addSubview:divider];
-  [contentView addLayoutGuide:layoutGuide1];
-  [contentView addLayoutGuide:layoutGuide2];
-
-  NSDictionary* views = @{
-    @"image" : _imageView,
-    @"title" : _titleLabel,
-    @"email" : _emailLabel,
-    @"divider" : divider,
-    @"v1" : layoutGuide1,
-    @"v2" : layoutGuide2
-  };
-  NSArray* constraints = @[
-    @"V:[image]-(24)-[title]-(8)-[email]-(16)-[divider(==1)]|",
-    @"H:|[v1][image]",
-    @"H:|[v1(16)][title(<=440)][v2(>=v1)]|",
-    @"H:|[v1][email]",
-    @"H:|[divider]|",
-  ];
-  ApplyVisualConstraints(constraints, views);
-  return contentView;
-}
-
-- (void)viewWillLayoutSubviews {
-  CGSize viewSize = self.view.bounds.size;
-  MDCFlexibleHeaderView* headerView = self.appBarViewController.headerView;
-  headerView.maximumHeight =
-      MAX(kHeaderViewMinHeight, kHeaderViewHeightMultiplier * viewSize.height);
-}
-
-- (void)updateViewWithIdentity:(ChromeIdentity*)identity {
-  UIImage* identityImage = GetImageForIdentity(identity);
-  if (_oldImage != identityImage) {
-    _oldImage = identityImage;
-    identityImage =
-        ResizeImage(identityImage,
-                    CGSizeMake(kAccountImageDimension, kAccountImageDimension),
-                    ProjectionMode::kAspectFit);
-    identityImage =
-        CircularImageFromImage(identityImage, kAccountImageDimension);
-    _imageView.image = identityImage;
-  }
-
-  _titleLabel.text = l10n_util::GetNSStringF(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_TITLE,
-      base::SysNSStringToUTF16([identity userFullName]));
-
-  _emailLabel.text = [identity userEmail];
-}
-
-#pragma mark - Model
-
-- (void)loadModel {
-  [super loadModel];
-  CollectionViewModel* model = self.collectionViewModel;
-
-  [model addSectionWithIdentifier:SectionIdentifierInfo];
-  [model addItem:[self syncItem] toSectionWithIdentifier:SectionIdentifierInfo];
-  [model addItem:[self googleServicesItem]
-      toSectionWithIdentifier:SectionIdentifierInfo];
-  [model addItem:[self openSettingsItem]
-      toSectionWithIdentifier:SectionIdentifierInfo];
-}
-
-#pragma mark - Model items
-
-- (CollectionViewItem*)syncItem {
-  LegacyAccountControlItem* item =
-      [[LegacyAccountControlItem alloc] initWithType:ItemTypeSync];
-  item.text = [self localizedConsentStringWithId:
-                        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_TITLE];
-  item.detailText =
-      [self localizedConsentStringWithId:
-                IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_DESCRIPTION];
-  item.image = ios::GetChromeBrowserProvider()
-                   ->GetBrandedImageProvider()
-                   ->GetSigninConfirmationSyncSettingsImage();
-  return item;
-}
-
-- (CollectionViewItem*)googleServicesItem {
-  LegacyAccountControlItem* item =
-      [[LegacyAccountControlItem alloc] initWithType:ItemTypeGoogleServices];
-  item.text =
-      [self localizedConsentStringWithId:
-                IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_TITLE];
-  item.detailText =
-      [self localizedConsentStringWithId:
-                IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_DESCRIPTION];
-  item.image = ios::GetChromeBrowserProvider()
-                   ->GetBrandedImageProvider()
-                   ->GetSigninConfirmationPersonalizeServicesImage();
-  return item;
-}
-
-- (CollectionViewItem*)openSettingsItem {
-  CollectionViewFooterItem* item =
-      [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter];
-  item.text = [self localizedConsentStringWithId:self.openSettingsStringId];
-  item.linkURL = google_util::AppendGoogleLocaleParam(
-      GURL("internal://settings-sync"),
-      GetApplicationContext()->GetApplicationLocale());
-  item.linkDelegate = self;
-  return item;
-}
-
-#pragma mark - Helpers
-
-// Calls |signinConfirmationControllerDidReachBottom:| on |delegate| if
-// the collection view has reached its bottom based on a content size height of
-// |contentSizeHeight|. Returns whether the delegate was notified.
-- (BOOL)sendDidReachBottomIfNecessary:(CGFloat)contentSizeHeight {
-  if (contentSizeHeight &&
-      self.collectionView.contentOffset.y +
-              self.collectionView.frame.size.height >=
-          contentSizeHeight) {
-    [self.delegate signinConfirmationControllerDidReachBottom:self];
-    return YES;
-  }
-  return NO;
-}
-
-// Adds the string id to the list of string for the user consent, and returns
-// the NSString related to the string id.
-- (NSString*)localizedConsentStringWithId:(int)stringId {
-  _consentStringIds.push_back(stringId);
-  return l10n_util::GetNSString(stringId);
-}
-
-#pragma mark - ChromeIdentityServiceObserver
-
-- (void)profileUpdate:(ChromeIdentity*)identity {
-  if (identity == _identity) {
-    [self updateViewWithIdentity:identity];
-  }
-}
-
-- (void)chromeIdentityServiceWillBeDestroyed {
-  _identityServiceObserver.reset();
-}
-
-#pragma mark - UIScrollViewDelegate
-
-- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
-  [super scrollViewDidScroll:scrollView];
-
-  if (scrollView == self.collectionView) {
-    [self sendDidReachBottomIfNecessary:scrollView.contentSize.height];
-  }
-}
-
-#pragma mark UICollectionViewDataSource
-
-- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
-                 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
-  MDCCollectionViewCell* cell =
-      [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
-
-  NSInteger itemType =
-      [self.collectionViewModel itemTypeForIndexPath:indexPath];
-  switch (itemType) {
-    case ItemTypeSync:
-      cell.separatorInset = UIEdgeInsetsMake(0, kLeadingSeparatorInset, 0,
-                                             kTrailingSeparatorInset);
-      break;
-    case ItemTypeGoogleServices:
-      cell.shouldHideSeparator = YES;
-      break;
-    case ItemTypeFooter: {
-      CollectionViewFooterCell* footerCell =
-          base::mac::ObjCCastStrict<CollectionViewFooterCell>(cell);
-      // TODO(crbug.com/664648): Must use atomic text formatting operation due
-      // to LabelLinkController bug.
-      footerCell.textLabel.attributedText = [[NSAttributedString alloc]
-          initWithString:footerCell.textLabel.text
-              attributes:@{
-                NSFontAttributeName : [MDCTypography body1Font],
-                NSForegroundColorAttributeName :
-                    [[MDCPalette greyPalette] tint700]
-              }];
-      footerCell.horizontalPadding = 16;
-      break;
-    }
-
-    default:
-      break;
-  }
-  return cell;
-}
-
-#pragma mark - MDCCollectionViewStylingDelegate
-
-- (CGFloat)collectionView:(UICollectionView*)collectionView
-    cellHeightAtIndexPath:(NSIndexPath*)indexPath {
-  CollectionViewItem* item =
-      [self.collectionViewModel itemAtIndexPath:indexPath];
-
-  // ItemTypeSync, ItemTypeGoogleServices, and ItemTypeFooter all support
-  // dynamic height calculation.
-  return [MDCCollectionViewCell
-      cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
-                         forItem:item];
-}
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
-  return YES;
-}
-
-- (BOOL)collectionView:(nonnull UICollectionView*)collectionView
-    shouldHideItemBackgroundAtIndexPath:(nonnull NSIndexPath*)indexPath {
-  return YES;
-}
-
-#pragma mark - CollectionViewFooterLinkDelegate
-
-- (void)cell:(CollectionViewFooterCell*)cell didTapLinkURL:(GURL)URL {
-  [[self delegate] signinConfirmationControllerDidTapSettingsLink:self];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
index 17aa0053..d8a0da0a 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
@@ -7,8 +7,6 @@
 #import <EarlGrey/EarlGrey.h>
 
 #include "base/mac/foundation_util.h"
-#include "components/unified_consent/feature.h"
-#include "ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_cell.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h"
@@ -70,21 +68,13 @@
 }
 
 + (void)selectIdentityWithEmail:(NSString*)userEmail {
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    // Assumes that the identity chooser is visible.
-    [[EarlGrey
-        selectElementWithMatcher:grey_allOf(grey_accessibilityID(userEmail),
-                                            grey_kindOfClass(
-                                                [IdentityChooserCell class]),
-                                            grey_sufficientlyVisible(), nil)]
-        performAction:grey_tap()];
-  } else {
-    // Sign in to |userEmail|.
-    [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(userEmail)]
-        performAction:grey_tap()];
-    [[EarlGrey selectElementWithMatcher:AccountConsistencySetupSigninButton()]
-        performAction:grey_tap()];
-  }
+  // Assumes that the identity chooser is visible.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(grey_accessibilityID(userEmail),
+                                          grey_kindOfClass(
+                                              [IdentityChooserCell class]),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
 }
 
 + (void)tapSettingsLink {
@@ -110,17 +100,9 @@
   // If the matcher fails, then the scroll view should be scrolled to the
   // bottom.
   // Once to the bottom, the consent can be confirmed.
-  id<GREYMatcher> confirmationScrollViewMatcher = nil;
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    confirmationScrollViewMatcher =
-        grey_accessibilityID(kUnifiedConsentScrollViewIdentifier);
-  } else {
-    confirmationScrollViewMatcher = grey_allOf(
-        grey_ancestor(
-            grey_accessibilityID(kSigninConfirmationCollectionViewId)),
-        grey_kindOfClass([UICollectionView class]), nil);
-  }
+  id<GREYMatcher> confirmationScrollViewMatcher =
+      grey_accessibilityID(kUnifiedConsentScrollViewIdentifier);
   NSError* error = nil;
   [[EarlGrey selectElementWithMatcher:confirmationScrollViewMatcher]
       assertWithMatcher:ContentViewSmallerThanScrollView()
@@ -140,9 +122,6 @@
 }
 
 + (void)tapAddAccountButton {
-  GREYAssertTrue(unified_consent::IsUnifiedConsentFeatureEnabled(),
-                 @"-[SigninEarlGreyUI tapAddAccountButton] is not available "
-                 @"without UnifiedConsent flag");
   id<GREYMatcher> confirmationScrollViewMatcher =
       grey_accessibilityID(kUnifiedConsentScrollViewIdentifier);
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
index 42088bb..fe3eb914 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
@@ -8,7 +8,6 @@
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "components/signin/public/base/signin_metrics.h"
-#include "components/unified_consent/feature.h"
 #include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
index 5a1a461..73f45ba 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
@@ -82,6 +82,9 @@
   // Shows the UI for the presented request using the container coordinator.
   void ShowUIForPresentedRequest();
 
+  // Called when the UI for |request_| has finished being presented.
+  void OverlayUIWasPresented();
+
   // Dismisses the UI for the presented request for |reason|.
   void DismissPresentedUI(OverlayDismissalReason reason);
 
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
index 77be7a2..29aeabae 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
@@ -218,6 +218,15 @@
   state->OverlayUIWasPresented();
 }
 
+void OverlayPresentationContextImpl::OverlayUIWasPresented() {
+  OverlayRequestUIState* state = GetRequestUIState(request_);
+  DCHECK(state);
+  UIView* overlay_view = state->coordinator().viewController.view;
+  DCHECK(overlay_view);
+  UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,
+                                  overlay_view);
+}
+
 void OverlayPresentationContextImpl::DismissPresentedUI(
     OverlayDismissalReason reason) {
   OverlayRequestUIState* state = GetRequestUIState(request_);
@@ -276,7 +285,11 @@
     ~OverlayRequestCoordinatorDelegateImpl() = default;
 
 void OverlayPresentationContextImpl::OverlayRequestCoordinatorDelegateImpl::
-    OverlayUIDidFinishPresentation(OverlayRequest* request) {}
+    OverlayUIDidFinishPresentation(OverlayRequest* request) {
+  DCHECK(request);
+  DCHECK_EQ(presentation_context_->request_, request);
+  presentation_context_->OverlayUIWasPresented();
+}
 
 void OverlayPresentationContextImpl::OverlayRequestCoordinatorDelegateImpl::
     OverlayUIDidFinishDismissal(OverlayRequest* request) {
diff --git a/ios/chrome/browser/ui/overlays/web_content_area/app_launcher/app_launcher_alert_overlay_coordinator.mm b/ios/chrome/browser/ui/overlays/web_content_area/app_launcher/app_launcher_alert_overlay_coordinator.mm
index b996e58..8319aba 100644
--- a/ios/chrome/browser/ui/overlays/web_content_area/app_launcher/app_launcher_alert_overlay_coordinator.mm
+++ b/ios/chrome/browser/ui/overlays/web_content_area/app_launcher/app_launcher_alert_overlay_coordinator.mm
@@ -63,9 +63,14 @@
   self.mediator =
       [[AppLauncherAlertOverlayMediator alloc] initWithRequest:self.request];
   self.mediator.consumer = self.alertViewController;
-  [self.baseViewController presentViewController:self.alertViewController
-                                        animated:animated
-                                      completion:nil];
+  __weak __typeof__(self) weakSelf = self;
+  [self.baseViewController
+      presentViewController:self.alertViewController
+                   animated:animated
+                 completion:^{
+                   weakSelf.delegate->OverlayUIDidFinishPresentation(
+                       weakSelf.request);
+                 }];
   self.started = YES;
 }
 
diff --git a/ios/chrome/browser/ui/overlays/web_content_area/http_auth_dialogs/http_auth_dialog_overlay_coordinator.mm b/ios/chrome/browser/ui/overlays/web_content_area/http_auth_dialogs/http_auth_dialog_overlay_coordinator.mm
index a3b63ac..c8be674 100644
--- a/ios/chrome/browser/ui/overlays/web_content_area/http_auth_dialogs/http_auth_dialog_overlay_coordinator.mm
+++ b/ios/chrome/browser/ui/overlays/web_content_area/http_auth_dialogs/http_auth_dialog_overlay_coordinator.mm
@@ -80,9 +80,14 @@
   self.mediator =
       [[HTTPAuthDialogOverlayMediator alloc] initWithRequest:self.request];
   self.mediator.consumer = self.alertViewController;
-  [self.baseViewController presentViewController:self.alertViewController
-                                        animated:animated
-                                      completion:nil];
+  __weak __typeof__(self) weakSelf = self;
+  [self.baseViewController
+      presentViewController:self.alertViewController
+                   animated:animated
+                 completion:^{
+                   weakSelf.delegate->OverlayUIDidFinishPresentation(
+                       weakSelf.request);
+                 }];
   self.started = YES;
 }
 
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 421fadf..97f0bee 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
@@ -10,7 +10,6 @@
 #include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/grit/components_scaled_resources.h"
-#import "ios/chrome/browser/ui/authentication/cells/legacy_account_control_item.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_delegate.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
@@ -89,7 +88,6 @@
   ItemTypeAutofillDynamicHeight,
   ItemTypeAutofillCVC,
   ItemTypeAutofillStatus,
-  ItemTypeAccountControlDynamicHeight,
   ItemTypeFooter,
   ItemTypeSyncPassphraseError,
   ItemTypeContentSuggestions,
@@ -290,13 +288,6 @@
   [model addItem:[self accountItemCheckMark]
       toSectionWithIdentifier:SectionIdentifierAccountCell];
 
-  // Account control cells.
-  [model addSectionWithIdentifier:SectionIdentifierAccountControlCell];
-  [model addItem:[self accountControlItem]
-      toSectionWithIdentifier:SectionIdentifierAccountControlCell];
-  [model addItem:[self accountControlItemWithExtraLongText]
-      toSectionWithIdentifier:SectionIdentifierAccountControlCell];
-
   // Content Suggestions cells.
   [model addSectionWithIdentifier:SectionIdentifierContentSuggestionsCell];
   [model addItem:[self contentSuggestionsItem]
@@ -327,7 +318,6 @@
     case ItemTypeContentSuggestions:
     case ItemTypeFooter:
     case ItemTypeSwitchDynamicHeight:
-    case ItemTypeAccountControlDynamicHeight:
     case ItemTypeTextCheckmark:
     case ItemTypeTextDetail:
     case ItemTypeText:
@@ -434,29 +424,6 @@
   return accountItemCheckMark;
 }
 
-- (CollectionViewItem*)accountControlItem {
-  LegacyAccountControlItem* item = [[LegacyAccountControlItem alloc]
-      initWithType:ItemTypeAccountControlDynamicHeight];
-  item.cellStyle = CollectionViewCellStyle::kUIKit;
-  item.image = [UIImage imageNamed:@"settings_sync"];
-  item.text = @"Account Sync Settings";
-  item.detailText = @"Detail text";
-  item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
-  return item;
-}
-
-- (CollectionViewItem*)accountControlItemWithExtraLongText {
-  LegacyAccountControlItem* item = [[LegacyAccountControlItem alloc]
-      initWithType:ItemTypeAccountControlDynamicHeight];
-  item.cellStyle = CollectionViewCellStyle::kUIKit;
-  item.image = [ChromeIcon infoIcon];
-  item.text = @"Account Control Settings";
-  item.detailText =
-      @"Detail text detail text detail text detail text detail text.";
-  item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
-  return item;
-}
-
 #pragma mark Private
 
 - (CollectionViewItem*)paymentsItemWithWrappingTextandOptionalImage {
diff --git a/ios/chrome/content_widget_extension/OWNERS b/ios/chrome/content_widget_extension/OWNERS
index 737378fc..137f338 100644
--- a/ios/chrome/content_widget_extension/OWNERS
+++ b/ios/chrome/content_widget_extension/OWNERS
@@ -1,3 +1,4 @@
 olivierrobin@chromium.org
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
+# COMPONENT: UI>Browser>Mobile>TodayView
diff --git a/ios/chrome/search_widget_extension/OWNERS b/ios/chrome/search_widget_extension/OWNERS
index 737378fc..137f338 100644
--- a/ios/chrome/search_widget_extension/OWNERS
+++ b/ios/chrome/search_widget_extension/OWNERS
@@ -1,3 +1,4 @@
 olivierrobin@chromium.org
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
+# COMPONENT: UI>Browser>Mobile>TodayView
diff --git a/ios/chrome/share_extension/OWNERS b/ios/chrome/share_extension/OWNERS
index 737378fc..97eaf1f9 100644
--- a/ios/chrome/share_extension/OWNERS
+++ b/ios/chrome/share_extension/OWNERS
@@ -1,3 +1,4 @@
 olivierrobin@chromium.org
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
+# COMPONENT: UI>Browser>Sharing
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
index ca30aa8e..fd09eeb 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -367,10 +367,8 @@
 }
 
 + (id<GREYMatcher>)accountConsistencyConfirmationOKButton {
-  int labelID = unified_consent::IsUnifiedConsentFeatureEnabled()
-                    ? IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON
-                    : IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON;
-  return [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:(labelID)];
+  int labelID = IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON;
+  return [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:labelID];
 }
 
 + (id<GREYMatcher>)unifiedConsentAddAccountButton {
diff --git a/ios/web/web_state/js/common_js_unittest.mm b/ios/web/web_state/js/common_js_unittest.mm
index a02a757..47c39b7 100644
--- a/ios/web/web_state/js/common_js_unittest.mm
+++ b/ios/web/web_state/js/common_js_unittest.mm
@@ -175,6 +175,9 @@
 
 TEST_F(CommonJsTest, IsSameOrigin) {
   TestScriptAndExpectedValue test_data[] = {
+      {@"'', ''", @NO},
+      {@"'http://abc.com', ''", @NO},
+      {@"'', 'http://abc.com'", @NO},
       {@"'http://abc.com', 'http://abc.com'", @YES},
       {@"'http://abc.com',  'https://abc.com'", @NO},
       {@"'http://abc.com', 'http://abc.com:123'", @NO},
diff --git a/ios/web/web_state/js/resources/all_frames_context_menu.js b/ios/web/web_state/js/resources/all_frames_context_menu.js
index 567cba2..9d5bcf9 100644
--- a/ios/web/web_state/js/resources/all_frames_context_menu.js
+++ b/ios/web/web_state/js/resources/all_frames_context_menu.js
@@ -103,7 +103,11 @@
         x: x - element.offsetLeft,
         y: y - element.offsetTop
       };
-      element.contentWindow.postMessage(payload, element.src);
+      // The message will not be sent if |targetOrigin| is null, so use * which
+      // allows the message to be delievered to the contentWindow regardless of
+      // the origin.
+      var targetOrigin = element.src || '*';
+      element.contentWindow.postMessage(payload, targetOrigin);
       return;
     }
 
diff --git a/ios/web/web_state/js/resources/common.js b/ios/web/web_state/js/resources/common.js
index 8d6a2cd..1d2e9d63 100644
--- a/ios/web/web_state/js/resources/common.js
+++ b/ios/web/web_state/js/resources/common.js
@@ -237,6 +237,11 @@
  * @return {boolean} Whether the two URLs have the same origin.
  */
 __gCrWeb.common.isSameOrigin = function(url_one, url_two) {
+  if (!url_one || !url_two) {
+    // Attempting to create URL representations of an empty string throws an
+    // exception.
+    return false;
+  }
   return new URL(url_one).origin == new URL(url_two).origin;
 };
 
diff --git a/media/audio/cras/cras_input.cc b/media/audio/cras/cras_input.cc
index 4b4276f2..954fc2ad 100644
--- a/media/audio/cras/cras_input.cc
+++ b/media/audio/cras/cras_input.cc
@@ -210,6 +210,9 @@
     return;
   }
 
+  cras_client_stream_params_set_client_type(stream_params,
+                                            CRAS_CLIENT_TYPE_CHROME);
+
   if (UseCrasAec())
     cras_client_stream_params_enable_aec(stream_params);
 
diff --git a/media/audio/cras/cras_unified.cc b/media/audio/cras/cras_unified.cc
index 0719abca..002d6111 100644
--- a/media/audio/cras/cras_unified.cc
+++ b/media/audio/cras/cras_unified.cc
@@ -202,6 +202,9 @@
     return;
   }
 
+  cras_client_stream_params_set_client_type(stream_params,
+                                            CRAS_CLIENT_TYPE_CHROME);
+
   // Before starting the stream, save the number of bytes in a frame for use in
   // the callback.
   bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 1e988b7d..a0f1494 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -43,6 +43,7 @@
 #include "media/mojo/services/watch_time_recorder.h"
 #include "media/renderers/default_decoder_factory.h"
 #include "media/renderers/default_renderer_factory.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -99,8 +100,9 @@
 
 // returns a valid handle that can be passed to WebLocalFrame constructor
 mojo::ScopedMessagePipeHandle CreateStubDocumentInterfaceBrokerHandle() {
-  blink::mojom::DocumentInterfaceBrokerPtrInfo info;
-  return mojo::MakeRequest(&info).PassMessagePipe();
+  return mojo::PendingRemote<blink::mojom::DocumentInterfaceBroker>()
+      .InitWithNewPipeAndPassReceiver()
+      .PassPipe();
 }
 
 class MockWebMediaPlayerClient : public blink::WebMediaPlayerClient {
diff --git a/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.cc b/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.cc
index da44a70..798cccf 100644
--- a/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.cc
+++ b/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.cc
@@ -22,9 +22,8 @@
       decode_done_cb_(std::move(decode_done_cb)),
       send_log_message_cb_(std::move(send_log_message_cb)),
       has_received_decoded_frame_(false),
-      next_bitstream_buffer_id_(0),
-      in_buffer_id_(
-          chromeos_camera::MjpegDecodeAccelerator::kInvalidBitstreamBufferId),
+      next_task_id_(0),
+      task_id_(chromeos_camera::MjpegDecodeAccelerator::kInvalidTaskId),
       decoder_status_(INIT_PENDING) {}
 
 VideoCaptureJpegDecoderImpl::~VideoCaptureJpegDecoderImpl() {
@@ -59,7 +58,7 @@
   DCHECK(decoder_);
 
   TRACE_EVENT_ASYNC_BEGIN0("jpeg", "VideoCaptureJpegDecoderImpl decoding",
-                           next_bitstream_buffer_id_);
+                           next_task_id_);
   TRACE_EVENT0("jpeg", "VideoCaptureJpegDecoderImpl::DecodeCapturedData");
 
   // TODO(kcwu): enqueue decode requests in case decoding is not fast enough
@@ -96,12 +95,12 @@
   }
   memcpy(in_shared_mapping_.memory(), data, in_buffer_size);
 
-  // No need to lock for |in_buffer_id_| since IsDecoding_Locked() is false.
-  in_buffer_id_ = next_bitstream_buffer_id_;
-  media::BitstreamBuffer in_buffer(in_buffer_id_, in_shared_region_.Duplicate(),
+  // No need to lock for |task_id_| since IsDecoding_Locked() is false.
+  task_id_ = next_task_id_;
+  media::BitstreamBuffer in_buffer(task_id_, in_shared_region_.Duplicate(),
                                    in_buffer_size);
   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
-  next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
+  next_task_id_ = (next_task_id_ + 1) & 0x3FFFFFFF;
 
   // The API of |decoder_| requires us to wrap the |out_buffer| in a VideoFrame.
   const gfx::Size dimensions = frame_format.frame_size;
@@ -155,12 +154,16 @@
   // |decoder_task_runner_|.
   decoder_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&chromeos_camera::MjpegDecodeAccelerator::Decode,
-                     base::Unretained(decoder_.get()), std::move(in_buffer),
-                     std::move(out_frame)));
+      base::BindOnce(
+          [](chromeos_camera::MjpegDecodeAccelerator* decoder,
+             BitstreamBuffer in_buffer, scoped_refptr<VideoFrame> out_frame) {
+            decoder->Decode(std::move(in_buffer), std::move(out_frame));
+          },
+          base::Unretained(decoder_.get()), std::move(in_buffer),
+          std::move(out_frame)));
 }
 
-void VideoCaptureJpegDecoderImpl::VideoFrameReady(int32_t bitstream_buffer_id) {
+void VideoCaptureJpegDecoderImpl::VideoFrameReady(int32_t task_id) {
   DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("jpeg", "VideoCaptureJpegDecoderImpl::VideoFrameReady");
   if (!has_received_decoded_frame_) {
@@ -174,26 +177,23 @@
     return;
   }
 
-  if (bitstream_buffer_id != in_buffer_id_) {
-    LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
-               << ", expected " << in_buffer_id_;
+  if (task_id != task_id_) {
+    LOG(ERROR) << "Unexpected task_id " << task_id << ", expected " << task_id_;
     return;
   }
-  in_buffer_id_ =
-      chromeos_camera::MjpegDecodeAccelerator::kInvalidBitstreamBufferId;
+  task_id_ = chromeos_camera::MjpegDecodeAccelerator::kInvalidTaskId;
 
   std::move(decode_done_closure_).Run();
 
   TRACE_EVENT_ASYNC_END0("jpeg", "VideoCaptureJpegDecoderImpl decoding",
-                         bitstream_buffer_id);
+                         task_id);
 }
 
 void VideoCaptureJpegDecoderImpl::NotifyError(
-    int32_t bitstream_buffer_id,
+    int32_t task_id,
     chromeos_camera::MjpegDecodeAccelerator::Error error) {
   DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence());
-  LOG(ERROR) << "Decode error, bitstream_buffer_id=" << bitstream_buffer_id
-             << ", error=" << error;
+  LOG(ERROR) << "Decode error, task_id=" << task_id << ", error=" << error;
   send_log_message_cb_.Run("Gpu Jpeg decoder failed");
   base::AutoLock lock(lock_);
   decode_done_closure_.Reset();
@@ -241,11 +241,4 @@
                         decoder_status_ == INIT_PASSED);
 }
 
-void VideoCaptureJpegDecoderImpl::DestroyDecoderOnIOThread(
-    base::WaitableEvent* event) {
-  DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence());
-  decoder_.reset();
-  event->Signal();
-}
-
 }  // namespace media
diff --git a/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h b/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h
index d3d4e26d..7bb0296 100644
--- a/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h
+++ b/media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h
@@ -94,10 +94,10 @@
   base::OnceClosure decode_done_closure_;
 
   // Next id for input BitstreamBuffer.
-  int32_t next_bitstream_buffer_id_;
+  int32_t next_task_id_;
 
   // The id for current input BitstreamBuffer being decoded.
-  int32_t in_buffer_id_;
+  int32_t task_id_;
 
   // Shared memory to store JPEG stream buffer. The input BitstreamBuffer is
   // backed by this.
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 85cb6c3..7e26f28 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -18,6 +18,7 @@
     "USE_VAAPI=$use_vaapi",
     "USE_V4L2_CODEC=$use_v4l2_codec",
     "USE_LIBV4L2=$use_v4lplugin",
+    "USE_CHROMEOS_MEDIA_ACCELERATION=$use_vaapi||$use_v4l2_codec",
   ]
 }
 
diff --git a/media/gpu/chromeos/chromeos_video_decoder_factory.cc b/media/gpu/chromeos/chromeos_video_decoder_factory.cc
index e2734a9..00612bc 100644
--- a/media/gpu/chromeos/chromeos_video_decoder_factory.cc
+++ b/media/gpu/chromeos/chromeos_video_decoder_factory.cc
@@ -10,11 +10,11 @@
 #include "media/base/video_decoder.h"
 #include "media/gpu/buildflags.h"
 
-#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 #include "media/gpu/linux/mailbox_video_frame_converter.h"
 #include "media/gpu/linux/platform_video_frame_pool.h"
 #include "media/gpu/linux/video_decoder_pipeline.h"
-#endif  // BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 #if BUILDFLAG(USE_VAAPI)
 #include "media/gpu/vaapi/vaapi_video_decoder.h"
@@ -24,7 +24,6 @@
 #include "media/gpu/v4l2/v4l2_slice_video_decoder.h"
 #endif
 
-
 namespace media {
 
 // static
@@ -53,12 +52,12 @@
     scoped_refptr<base::SequencedTaskRunner> client_task_runner,
     std::unique_ptr<DmabufVideoFramePool> frame_pool,
     std::unique_ptr<VideoFrameConverter> frame_converter) {
-#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   // TODO(akahuang): Remove ChromeosVideoDecoderFactory.
   return VideoDecoderPipeline::Create(std::move(client_task_runner),
                                       std::move(frame_pool),
                                       std::move(frame_converter));
-#endif  // BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
   return nullptr;
 }
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.cc b/media/gpu/gpu_video_decode_accelerator_factory.cc
index f9787be..737f71d 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_decode_accelerator_factory.cc
@@ -55,7 +55,7 @@
   capabilities.supported_profiles =
       DXVAVideoDecodeAccelerator::GetSupportedProfiles(gpu_preferences,
                                                        workarounds);
-#elif BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   VideoDecodeAccelerator::SupportedProfiles vda_profiles;
 #if BUILDFLAG(USE_V4L2_CODEC)
   vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles();
diff --git a/media/gpu/test/image_processor/image_processor_client.cc b/media/gpu/test/image_processor/image_processor_client.cc
index d26ce42..b33d7f3 100644
--- a/media/gpu/test/image_processor/image_processor_client.cc
+++ b/media/gpu/test/image_processor/image_processor_client.cc
@@ -17,13 +17,17 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_layout.h"
+#include "media/gpu/buildflags.h"
 #include "media/gpu/image_processor_factory.h"
-#include "media/gpu/linux/platform_video_frame_utils.h"
 #include "media/gpu/test/image.h"
 #include "media/gpu/test/video_frame_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
 
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+#include "media/gpu/linux/platform_video_frame_utils.h"
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+
 namespace media {
 namespace test {
 
@@ -136,14 +140,14 @@
         output_layout, gfx::Rect(output_image.Size()), output_image.Size(),
         base::TimeDelta(), false /* zero_initialize_memory*/);
   } else {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
     LOG_ASSERT(image_processor_->output_storage_type() ==
                VideoFrame::STORAGE_DMABUFS);
     return CreatePlatformVideoFrame(
         output_layout.format(), output_layout.coded_size(),
         gfx::Rect(output_image.Size()), output_image.Size(), base::TimeDelta(),
         gfx::BufferUsage::GPU_READ_CPU_READ_WRITE);
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
     return nullptr;
   }
 }
diff --git a/media/gpu/test/texture_ref.cc b/media/gpu/test/texture_ref.cc
index 9311f057..6cac302 100644
--- a/media/gpu/test/texture_ref.cc
+++ b/media/gpu/test/texture_ref.cc
@@ -13,9 +13,11 @@
 
 #if defined(OS_LINUX)
 #include <libdrm/drm_fourcc.h>
+#endif  // defined(OS_LINUX)
 
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 #include "media/gpu/linux/platform_video_frame_utils.h"
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 namespace media {
 namespace test {
@@ -46,7 +48,8 @@
     const gfx::Size& size,
     gfx::BufferUsage buffer_usage) {
   scoped_refptr<TextureRef> texture_ref;
-#if defined(OS_CHROMEOS)
+
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   texture_ref = TextureRef::Create(texture_id, std::move(no_longer_needed_cb));
   LOG_ASSERT(texture_ref);
   // We set visible size to coded_size. The correct visible rectangle is set
@@ -54,28 +57,29 @@
   texture_ref->frame_ =
       CreatePlatformVideoFrame(pixel_format, size, gfx::Rect(size), size,
                                base::TimeDelta(), buffer_usage);
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+
   return texture_ref;
 }
 
 gfx::GpuMemoryBufferHandle TextureRef::ExportGpuMemoryBufferHandle() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   auto handle = CreateGpuMemoryBufferHandle(frame_.get());
   DCHECK(!handle.is_null());
   return handle;
 #else
   return gfx::GpuMemoryBufferHandle();
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 }
 
 scoped_refptr<VideoFrame> TextureRef::ExportVideoFrame(
     gfx::Rect visible_rect) const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   return VideoFrame::WrapVideoFrame(*frame_, frame_->format(), visible_rect,
                                     visible_rect.size());
 #else
   return nullptr;
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 }
 
 }  // namespace test
diff --git a/media/gpu/test/texture_ref.h b/media/gpu/test/texture_ref.h
index 3bae3b3a..8c0f58ad 100644
--- a/media/gpu/test/texture_ref.h
+++ b/media/gpu/test/texture_ref.h
@@ -9,6 +9,7 @@
 #include "base/threading/thread_checker.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_types.h"
+#include "media/gpu/buildflags.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -44,9 +45,9 @@
 
   uint32_t texture_id_;
   base::OnceClosure no_longer_needed_cb_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   scoped_refptr<VideoFrame> frame_;
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   THREAD_CHECKER(thread_checker_);
 };
 
diff --git a/media/gpu/test/video_frame_helpers.cc b/media/gpu/test/video_frame_helpers.cc
index 681e17f..eebe8cf 100644
--- a/media/gpu/test/video_frame_helpers.cc
+++ b/media/gpu/test/video_frame_helpers.cc
@@ -9,16 +9,16 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "media/base/video_frame.h"
+#include "media/gpu/buildflags.h"
 #include "media/gpu/test/image.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
-#if defined(OS_CHROMEOS)
-#include "media/base/scopedfd_helper.h"
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 #include "media/gpu/linux/platform_video_frame_utils.h"
 #include "media/gpu/video_frame_mapper.h"
 #include "media/gpu/video_frame_mapper_factory.h"
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 namespace media {
 namespace test {
@@ -121,7 +121,7 @@
 bool CopyVideoFrame(const VideoFrame* src_frame,
                     scoped_refptr<VideoFrame> dst_frame) {
   LOG_ASSERT(src_frame->IsMappable());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   // If |dst_frame| is a Dmabuf-backed VideoFrame, we need to map its underlying
   // buffer into memory. We use a VideoFrameMapper to create a memory-based
   // VideoFrame that refers to the |dst_frame|'s buffer.
@@ -135,7 +135,7 @@
       return false;
     }
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   LOG_ASSERT(dst_frame->IsMappable());
   LOG_ASSERT(src_frame->format() == dst_frame->format());
 
@@ -208,14 +208,14 @@
 
   scoped_refptr<VideoFrame> dst_frame;
   switch (dst_storage_type) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
     case VideoFrame::STORAGE_DMABUFS:
       dst_frame = CreatePlatformVideoFrame(
           dst_layout.format(), dst_layout.coded_size(),
           src_frame->visible_rect(), src_frame->visible_rect().size(),
           src_frame->timestamp(), gfx::BufferUsage::GPU_READ_CPU_READ_WRITE);
       break;
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
     case VideoFrame::STORAGE_OWNED_MEMORY:
       // Create VideoFrame, which allocates and owns data.
       dst_frame = VideoFrame::CreateFrameWithLayout(
diff --git a/media/gpu/test/video_frame_validator.cc b/media/gpu/test/video_frame_validator.cc
index c8392353..d51bd99 100644
--- a/media/gpu/test/video_frame_validator.cc
+++ b/media/gpu/test/video_frame_validator.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "media/base/video_frame.h"
+#include "media/gpu/buildflags.h"
 #include "media/gpu/test/video_decode_accelerator_unittest_helpers.h"
 #include "media/gpu/video_frame_mapper.h"
 #include "media/gpu/video_frame_mapper_factory.h"
@@ -110,7 +111,7 @@
 
   scoped_refptr<const VideoFrame> validated_frame = video_frame;
   // If this is a DMABuf-backed memory frame we need to map it before accessing.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   if (validated_frame->storage_type() == VideoFrame::STORAGE_DMABUFS) {
     // Create VideoFrameMapper if not yet created. The decoder's output pixel
     // format is not known yet when creating the VideoFrameValidator. We can
@@ -127,7 +128,7 @@
       return;
     }
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
   LOG_ASSERT(validated_frame->IsMappable());
   if (validated_frame->format() != validation_format_) {
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc
index cc14231e..7ce174eb 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.cc
+++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -22,9 +22,9 @@
 #include "media/gpu/test/video_player/video.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 #include "media/gpu/linux/platform_video_frame_utils.h"
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 namespace media {
 namespace test {
@@ -217,20 +217,24 @@
       // handles to the video frame's data to the decoder.
       for (const PictureBuffer& picture_buffer : picture_buffers) {
         scoped_refptr<VideoFrame> video_frame;
-#if BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
         video_frame = CreatePlatformVideoFrame(
             format, dimensions, visible_rect, visible_rect.size(),
             base::TimeDelta(), gfx::BufferUsage::SCANOUT_VDA_WRITE);
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+
         LOG_ASSERT(video_frame) << "Failed to create video frame";
         video_frames_.emplace(picture_buffer.id(), video_frame);
         gfx::GpuMemoryBufferHandle handle;
-#if BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
         handle = CreateGpuMemoryBufferHandle(video_frame.get());
         DCHECK(!handle.is_null());
 #else
         NOTREACHED();
-#endif
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+
         LOG_ASSERT(!handle.is_null()) << "Failed to create GPU memory handle";
         decoder_->ImportBufferForPicture(picture_buffer.id(), format,
                                          std::move(handle));
diff --git a/media/gpu/test/video_player/video_decoder_client.cc b/media/gpu/test/video_player/video_decoder_client.cc
index 4fd7d2d..65bdc66 100644
--- a/media/gpu/test/video_player/video_decoder_client.cc
+++ b/media/gpu/test/video_player/video_decoder_client.cc
@@ -20,9 +20,9 @@
 #include "media/gpu/test/video_player/test_vda_video_decoder.h"
 #include "media/gpu/test/video_player/video.h"
 
-#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 #include "media/gpu/linux/platform_video_frame_pool.h"
-#endif  // BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 #if defined(OS_CHROMEOS)
 #include "media/gpu/chromeos/chromeos_video_decoder_factory.h"
@@ -163,12 +163,12 @@
   LOG_ASSERT(!decoder_) << "Can't create decoder: already created";
 
   if (decoder_client_config_.use_vd) {
-#if defined(OS_CHROMEOS) && (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))
+#if defined(OS_CHROMEOS) && BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
     decoder_ = ChromeosVideoDecoderFactory::Create(
         base::ThreadTaskRunnerHandle::Get(),
         std::make_unique<PlatformVideoFramePool>(),
         std::make_unique<VideoFrameConverter>());
-#endif  // defined(OS_CHROMEOS)
+#endif  // defined(OS_CHROMEOS) && BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   } else {
     // The video decoder client expects decoders to use the VD interface. We
     // can use the TestVDAVideoDecoder wrapper here to test VDA-based video
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn
index bbd6a96..4a3df4ff7 100644
--- a/media/gpu/v4l2/BUILD.gn
+++ b/media/gpu/v4l2/BUILD.gn
@@ -51,6 +51,8 @@
     "v4l2_video_decode_accelerator.h",
     "v4l2_video_encode_accelerator.cc",
     "v4l2_video_encode_accelerator.h",
+    "v4l2_vp8_accelerator.cc",
+    "v4l2_vp8_accelerator.h",
     "v4l2_vp8_accelerator_legacy.cc",
     "v4l2_vp8_accelerator_legacy.h",
     "v4l2_vp9_accelerator.cc",
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
index 9422499f..4d56fdf0 100644
--- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
@@ -17,9 +17,13 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback_helpers.h"
+#include "base/files/scoped_file.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/process/process_metrics.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "media/base/bitstream_buffer.h"
+#include "media/base/unaligned_shared_memory.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_types.h"
 #include "media/gpu/format_utils.h"
@@ -30,13 +34,13 @@
 #include "media/parsers/jpeg_parser.h"
 #include "third_party/libyuv/include/libyuv.h"
 
-#define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_name)    \
-  do {                                                              \
-    if (device_->Ioctl(type, arg) != 0) {                           \
-      VPLOGF(1) << "ioctl() failed: " << type_name;                 \
-      PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); \
-      return value;                                                 \
-    }                                                               \
+#define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_name) \
+  do {                                                           \
+    if (device_->Ioctl(type, arg) != 0) {                        \
+      VPLOGF(1) << "ioctl() failed: " << type_name;              \
+      PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);         \
+      return value;                                              \
+    }                                                            \
   } while (0)
 
 #define IOCTL_OR_ERROR_RETURN(type, arg) \
@@ -45,12 +49,12 @@
 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
   IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type)
 
-#define IOCTL_OR_LOG_ERROR(type, arg)                               \
-  do {                                                              \
-    if (device_->Ioctl(type, arg) != 0) {                           \
-      VPLOGF(1) << "ioctl() failed: " << #type;                     \
-      PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); \
-    }                                                               \
+#define IOCTL_OR_LOG_ERROR(type, arg)                    \
+  do {                                                   \
+    if (device_->Ioctl(type, arg) != 0) {                \
+      VPLOGF(1) << "ioctl() failed: " << #type;          \
+      PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE); \
+    }                                                    \
   } while (0)
 
 #define READ_U8_OR_RETURN_FALSE(reader, out)                               \
@@ -130,6 +134,118 @@
     0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
     0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA};
 
+class V4L2MjpegDecodeAccelerator::JobRecord {
+ public:
+  virtual ~JobRecord() = default;
+
+  // Task ID passed from Decode() call.
+  virtual int32_t task_id() const = 0;
+  // Input buffer size.
+  virtual size_t size() const = 0;
+  // Input buffer offset.
+  virtual off_t offset() const = 0;
+  // Maps input buffer.
+  virtual bool map() = 0;
+  // Pointer to the input content. Only valid if map() is already called.
+  virtual const void* memory() const = 0;
+
+  // Output frame buffer.
+  virtual const scoped_refptr<VideoFrame>& out_frame() = 0;
+
+ protected:
+  JobRecord() = default;
+
+  DISALLOW_COPY_AND_ASSIGN(JobRecord);
+};
+
+// Job record when the client uses BitstreamBuffer as input in Decode().
+class JobRecordBitstreamBuffer : public V4L2MjpegDecodeAccelerator::JobRecord {
+ public:
+  JobRecordBitstreamBuffer(BitstreamBuffer bitstream_buffer,
+                           scoped_refptr<VideoFrame> video_frame)
+      : task_id_(bitstream_buffer.id()),
+        shm_(bitstream_buffer.TakeRegion(),
+             bitstream_buffer.size(),
+             false /* read_only */),
+        offset_(bitstream_buffer.offset()),
+        out_frame_(video_frame) {}
+
+  int32_t task_id() const override { return task_id_; }
+  size_t size() const override { return shm_.size(); }
+  off_t offset() const override { return offset_; }
+  bool map() override { return shm_.MapAt(offset(), size()); }
+  const void* memory() const override { return shm_.memory(); }
+
+  const scoped_refptr<VideoFrame>& out_frame() override { return out_frame_; }
+
+ private:
+  int32_t task_id_;
+  UnalignedSharedMemory shm_;
+  off_t offset_;
+  scoped_refptr<VideoFrame> out_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(JobRecordBitstreamBuffer);
+};
+
+// Job record when the client uses DMA buffer as input in Decode().
+class JobRecordDmaBuf : public V4L2MjpegDecodeAccelerator::JobRecord {
+ public:
+  JobRecordDmaBuf(int32_t task_id,
+                  base::ScopedFD src_dmabuf_fd,
+                  size_t src_size,
+                  off_t src_offset,
+                  scoped_refptr<VideoFrame> dst_frame)
+      : task_id_(task_id),
+        dmabuf_fd_(std::move(src_dmabuf_fd)),
+        size_(src_size),
+        offset_(src_offset),
+        mapped_addr_(nullptr),
+        out_frame_(std::move(dst_frame)) {}
+
+  ~JobRecordDmaBuf() {
+    if (mapped_addr_) {
+      const int ret = munmap(mapped_addr_, size());
+      DPCHECK(ret == 0);
+    }
+  }
+
+  int32_t task_id() const override { return task_id_; }
+  size_t size() const override { return size_; }
+  off_t offset() const override { return offset_; }
+
+  bool map() override {
+    if (mapped_addr_)
+      return true;
+    // The DMA-buf FD should be mapped as read-only since it may only have read
+    // permission, e.g. when it comes from camera driver.
+    DCHECK(dmabuf_fd_.is_valid());
+    DCHECK_GT(size(), 0u);
+    void* addr = mmap(nullptr, size(), PROT_READ, MAP_SHARED, dmabuf_fd_.get(),
+                      offset());
+    if (addr == MAP_FAILED)
+      return false;
+    mapped_addr_ = addr;
+    return true;
+  }
+
+  const void* memory() const override {
+    DCHECK(mapped_addr_);
+    return mapped_addr_;
+  }
+
+  const scoped_refptr<VideoFrame>& out_frame() override { return out_frame_; }
+
+ private:
+  int32_t task_id_;
+  base::ScopedFD dmabuf_fd_;
+  size_t size_;
+  off_t offset_;
+  void* mapped_addr_;
+  scoped_refptr<VideoFrame> out_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(JobRecordDmaBuf);
+};
+
 V4L2MjpegDecodeAccelerator::BufferRecord::BufferRecord() : at_device(false) {
   memset(address, 0, sizeof(address));
   memset(length, 0, sizeof(length));
@@ -137,18 +253,6 @@
 
 V4L2MjpegDecodeAccelerator::BufferRecord::~BufferRecord() {}
 
-V4L2MjpegDecodeAccelerator::JobRecord::JobRecord(
-    BitstreamBuffer bitstream_buffer,
-    scoped_refptr<VideoFrame> video_frame)
-    : bitstream_buffer_id(bitstream_buffer.id()),
-      shm(bitstream_buffer.TakeRegion(),
-          bitstream_buffer.size(),
-          false /* read_only */),
-      offset(bitstream_buffer.offset()),
-      out_frame(video_frame) {}
-
-V4L2MjpegDecodeAccelerator::JobRecord::~JobRecord() {}
-
 V4L2MjpegDecodeAccelerator::V4L2MjpegDecodeAccelerator(
     const scoped_refptr<V4L2Device>& device,
     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
@@ -193,24 +297,21 @@
   DestroyOutputBuffers();
 }
 
-void V4L2MjpegDecodeAccelerator::VideoFrameReady(int32_t bitstream_buffer_id) {
+void V4L2MjpegDecodeAccelerator::VideoFrameReady(int32_t task_id) {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
-  client_->VideoFrameReady(bitstream_buffer_id);
+  client_->VideoFrameReady(task_id);
 }
 
-void V4L2MjpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
-                                             Error error) {
+void V4L2MjpegDecodeAccelerator::NotifyError(int32_t task_id, Error error) {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
-  VLOGF(1) << "Notifying of error " << error << " for buffer id "
-           << bitstream_buffer_id;
-  client_->NotifyError(bitstream_buffer_id, error);
+  VLOGF(1) << "Notifying of error " << error << " for task id " << task_id;
+  client_->NotifyError(task_id, error);
 }
 
-void V4L2MjpegDecodeAccelerator::PostNotifyError(int32_t bitstream_buffer_id,
-                                                 Error error) {
+void V4L2MjpegDecodeAccelerator::PostNotifyError(int32_t task_id, Error error) {
   child_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&V4L2MjpegDecodeAccelerator::NotifyError,
-                                weak_ptr_, bitstream_buffer_id, error));
+                                weak_ptr_, task_id, error));
 }
 
 bool V4L2MjpegDecodeAccelerator::Initialize(
@@ -272,13 +373,82 @@
     return;
   }
 
-  std::unique_ptr<JobRecord> job_record(
-      new JobRecord(std::move(bitstream_buffer), std::move(video_frame)));
+  // Validate output video frame.
+  if (!video_frame->IsMappable() && !video_frame->HasDmaBufs()) {
+    VLOGF(1) << "Unsupported output frame storage type";
+    PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT);
+    return;
+  }
+  if ((video_frame->visible_rect().width() & 1) ||
+      (video_frame->visible_rect().height() & 1)) {
+    VLOGF(1) << "Output frame visible size has odd dimension";
+    PostNotifyError(bitstream_buffer.id(), PLATFORM_FAILURE);
+    return;
+  }
+
+  std::unique_ptr<JobRecord> job_record(new JobRecordBitstreamBuffer(
+      std::move(bitstream_buffer), std::move(video_frame)));
 
   decoder_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&V4L2MjpegDecodeAccelerator::DecodeTask,
-                     base::Unretained(this), base::Passed(&job_record)));
+      FROM_HERE, base::BindOnce(&V4L2MjpegDecodeAccelerator::DecodeTask,
+                                base::Unretained(this), std::move(job_record)));
+}
+
+void V4L2MjpegDecodeAccelerator::Decode(
+    int32_t task_id,
+    base::ScopedFD src_dmabuf_fd,
+    size_t src_size,
+    off_t src_offset,
+    scoped_refptr<media::VideoFrame> dst_frame) {
+  DVLOGF(4) << "task_id=" << task_id;
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+  if (task_id < 0) {
+    VLOGF(1) << "Invalid task id: " << task_id;
+    PostNotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+
+  // Validate input arguments.
+  if (!src_dmabuf_fd.is_valid()) {
+    VLOGF(1) << "Invalid input buffer FD";
+    PostNotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+  if (src_size == 0) {
+    VLOGF(1) << "Input buffer size is zero";
+    PostNotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+  const size_t page_size = base::GetPageSize();
+  if (src_offset < 0 || src_offset % page_size != 0) {
+    VLOGF(1) << "Input buffer offset (" << src_offset
+             << ") should be non-negative and aligned to page size ("
+             << page_size << ")";
+    PostNotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+
+  // Validate output video frame.
+  if (!dst_frame->IsMappable() && !dst_frame->HasDmaBufs()) {
+    VLOGF(1) << "Unsupported output frame storage type";
+    PostNotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+  if ((dst_frame->visible_rect().width() & 1) ||
+      (dst_frame->visible_rect().height() & 1)) {
+    VLOGF(1) << "Output frame visible size has odd dimension";
+    PostNotifyError(task_id, PLATFORM_FAILURE);
+    return;
+  }
+
+  std::unique_ptr<JobRecord> job_record(
+      new JobRecordDmaBuf(task_id, std::move(src_dmabuf_fd), src_size,
+                          src_offset, std::move(dst_frame)));
+
+  decoder_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&V4L2MjpegDecodeAccelerator::DecodeTask,
+                                base::Unretained(this), std::move(job_record)));
 }
 
 // static
@@ -293,9 +463,9 @@
 void V4L2MjpegDecodeAccelerator::DecodeTask(
     std::unique_ptr<JobRecord> job_record) {
   DCHECK(decoder_task_runner_->BelongsToCurrentThread());
-  if (!job_record->shm.MapAt(job_record->offset, job_record->shm.size())) {
-    VPLOGF(1) << "could not map bitstream_buffer";
-    PostNotifyError(job_record->bitstream_buffer_id, UNREADABLE_INPUT);
+  if (!job_record->map()) {
+    VPLOGF(1) << "could not map input buffer";
+    PostNotifyError(job_record->task_id(), UNREADABLE_INPUT);
     return;
   }
   input_jobs_.push(std::move(job_record));
@@ -318,8 +488,9 @@
 
   JobRecord* job_record = input_jobs_.front().get();
   // Check input buffer size is enough
+  // TODO(kamesan): use safe arithmetic to handle overflows.
   return (input_buffer_map_.empty() ||
-          (job_record->shm.size() + sizeof(kDefaultDhtSeg)) >
+          (job_record->size() + sizeof(kDefaultDhtSeg)) >
               input_buffer_map_.front().length[0]);
 }
 
@@ -364,7 +535,8 @@
   // The input image may miss huffman table. We didn't parse the image before,
   // so we create more to avoid the situation of not enough memory.
   // Reserve twice size to avoid recreating input buffer frequently.
-  size_t reserve_size = (job_record->shm.size() + sizeof(kDefaultDhtSeg)) * 2;
+  // TODO(kamesan): use safe arithmetic to handle overflows.
+  size_t reserve_size = (job_record->size() + sizeof(kDefaultDhtSeg)) * 2;
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
@@ -407,7 +579,7 @@
                         MAP_SHARED, planes[j].m.mem_offset);
       if (address == MAP_FAILED) {
         VPLOGF(1) << "mmap() failed";
-        PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+        PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
         return false;
       }
       input_buffer_map_[i].address[j] = address;
@@ -426,12 +598,12 @@
   JobRecord* job_record = running_jobs_.front().get();
 
   size_t frame_size = VideoFrame::AllocationSize(
-      PIXEL_FORMAT_I420, job_record->out_frame->coded_size());
+      PIXEL_FORMAT_I420, job_record->out_frame()->coded_size());
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-  format.fmt.pix_mp.width = job_record->out_frame->coded_size().width();
-  format.fmt.pix_mp.height = job_record->out_frame->coded_size().height();
+  format.fmt.pix_mp.width = job_record->out_frame()->coded_size().width();
+  format.fmt.pix_mp.height = job_record->out_frame()->coded_size().height();
   format.fmt.pix_mp.num_planes = 1;
   format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420;
   format.fmt.pix_mp.plane_fmt[0].sizeimage = frame_size;
@@ -449,7 +621,7 @@
   if (output_format == PIXEL_FORMAT_UNKNOWN) {
     VLOGF(1) << "unknown V4L2 pixel format: "
              << FourccToString(output_buffer_pixelformat_);
-    PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+    PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
     return false;
   }
 
@@ -493,7 +665,7 @@
                         MAP_SHARED, planes[j].m.mem_offset);
       if (address == MAP_FAILED) {
         VPLOGF(1) << "mmap() failed";
-        PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+        PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
         return false;
       }
       output_buffer_map_[i].address[j] = address;
@@ -571,7 +743,7 @@
   bool event_pending;
   if (!device_->Poll(true, &event_pending)) {
     VPLOGF(1) << "Poll device error.";
-    PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+    PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
     return;
   }
 
@@ -602,7 +774,7 @@
   } else {
     VLOGF(1) << "dequeue event failed.";
   }
-  PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+  PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
   return false;
 }
 
@@ -852,7 +1024,7 @@
         break;
       }
       VPLOGF(1) << "ioctl() failed: input buffer VIDIOC_DQBUF failed.";
-      PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+      PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
       return;
     }
     BufferRecord& input_record = input_buffer_map_[dqbuf.index];
@@ -862,7 +1034,7 @@
 
     if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
       VLOGF(1) << "Error in dequeued input buffer.";
-      PostNotifyError(kInvalidBitstreamBufferId, UNSUPPORTED_JPEG);
+      PostNotifyError(kInvalidTaskId, UNSUPPORTED_JPEG);
       running_jobs_.pop();
     }
   }
@@ -889,7 +1061,7 @@
         break;
       }
       VPLOGF(1) << "ioctl() failed: output buffer VIDIOC_DQBUF failed.";
-      PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+      PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
       return;
     }
     BufferRecord& output_record = output_buffer_map_[dqbuf.index];
@@ -903,23 +1075,26 @@
 
     if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
       VLOGF(1) << "Error in dequeued output buffer.";
-      PostNotifyError(kInvalidBitstreamBufferId, UNSUPPORTED_JPEG);
+      PostNotifyError(kInvalidTaskId, UNSUPPORTED_JPEG);
     } else {
       // Copy the decoded data from output buffer to the buffer provided by the
       // client. Do format conversion when output format is not
       // V4L2_PIX_FMT_YUV420.
-      if (!ConvertOutputImage(output_record,
-                              std::move(job_record->out_frame))) {
-        PostNotifyError(job_record->bitstream_buffer_id, PLATFORM_FAILURE);
+      if (!ConvertOutputImage(output_record, job_record->out_frame())) {
+        PostNotifyError(job_record->task_id(), PLATFORM_FAILURE);
         return;
       }
       DVLOGF(4) << "Decoding finished, returning bitstream buffer, id="
-                << job_record->bitstream_buffer_id;
+                << job_record->task_id();
 
+      // Destroy |job_record| before posting VideoFrameReady to the client to
+      // prevent race condition on the buffers.
+      const int32_t task_id = job_record->task_id();
+      job_record.reset();
       child_task_runner_->PostTask(
           FROM_HERE,
           base::BindOnce(&V4L2MjpegDecodeAccelerator::VideoFrameReady,
-                         weak_ptr_, job_record->bitstream_buffer_id));
+                         weak_ptr_, task_id));
     }
   }
 }
@@ -1016,9 +1191,9 @@
   DCHECK(!input_record.at_device);
 
   // It will add default huffman segment if it's missing.
-  if (!AddHuffmanTable(job_record->shm.memory(), job_record->shm.size(),
+  if (!AddHuffmanTable(job_record->memory(), job_record->size(),
                        input_record.address[0], input_record.length[0])) {
-    PostNotifyError(job_record->bitstream_buffer_id, PARSE_JPEG_FAILED);
+    PostNotifyError(job_record->task_id(), PARSE_JPEG_FAILED);
     return false;
   }
 
@@ -1036,8 +1211,7 @@
   IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
   input_record.at_device = true;
 
-  DVLOGF(3) << "enqueued frame id=" << job_record->bitstream_buffer_id
-            << " to device.";
+  DVLOGF(3) << "enqueued frame id=" << job_record->task_id() << " to device.";
   running_jobs_.push(std::move(job_record));
   free_input_buffers_.pop_back();
   return true;
@@ -1073,7 +1247,7 @@
 
   if (!device_poll_thread_.Start()) {
     VLOGF(1) << "Device thread failed to start";
-    PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+    PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
     return;
   }
   device_poll_task_runner_ = device_poll_thread_.task_runner();
@@ -1084,7 +1258,7 @@
   // Signal the DevicePollTask() to stop, and stop the device poll thread.
   if (!device_->SetDevicePollInterrupt()) {
     VLOGF(1) << "SetDevicePollInterrupt failed.";
-    PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+    PostNotifyError(kInvalidTaskId, PLATFORM_FAILURE);
     return false;
   }
 
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
index acff2f6..76ee0afd9 100644
--- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
@@ -18,8 +18,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "components/chromeos_camera/mjpeg_decode_accelerator.h"
-#include "media/base/bitstream_buffer.h"
-#include "media/base/unaligned_shared_memory.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/v4l2/v4l2_device.h"
 
@@ -30,6 +28,14 @@
 class MEDIA_GPU_EXPORT V4L2MjpegDecodeAccelerator
     : public chromeos_camera::MjpegDecodeAccelerator {
  public:
+  // Job record. Jobs are processed in a FIFO order. This is separate from
+  // BufferRecord of input, because a BufferRecord of input may be returned
+  // before we dequeue the corresponding output buffer. It can't always be
+  // associated with a BufferRecord of output immediately either, because at
+  // the time of submission we may not have one available (and don't need one
+  // to submit input to the device).
+  class JobRecord;
+
   V4L2MjpegDecodeAccelerator(
       const scoped_refptr<V4L2Device>& device,
       const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
@@ -40,6 +46,11 @@
       chromeos_camera::MjpegDecodeAccelerator::Client* client) override;
   void Decode(BitstreamBuffer bitstream_buffer,
               scoped_refptr<VideoFrame> video_frame) override;
+  void Decode(int32_t task_id,
+              base::ScopedFD src_dmabuf_fd,
+              size_t src_size,
+              off_t src_offset,
+              scoped_refptr<media::VideoFrame> dst_frame) override;
   bool IsSupported() override;
 
  private:
@@ -54,27 +65,6 @@
     bool at_device;
   };
 
-  // Job record. Jobs are processed in a FIFO order. This is separate from
-  // BufferRecord of input, because a BufferRecord of input may be returned
-  // before we dequeue the corresponding output buffer. It can't always be
-  // associated with a BufferRecord of output immediately either, because at
-  // the time of submission we may not have one available (and don't need one
-  // to submit input to the device).
-  struct JobRecord {
-    JobRecord(BitstreamBuffer bitstream_buffer,
-              scoped_refptr<VideoFrame> video_frame);
-    ~JobRecord();
-
-    // Input image buffer ID.
-    int32_t bitstream_buffer_id;
-    // Memory mapped from |bitstream_buffer|.
-    UnalignedSharedMemory shm;
-    // Offset used for shm.
-    off_t offset;
-    // Output frame buffer.
-    scoped_refptr<VideoFrame> out_frame;
-  };
-
   void EnqueueInput();
   void EnqueueOutput();
   void Dequeue();
@@ -103,9 +93,9 @@
   // Destroy and create output buffers. Return false on error.
   bool RecreateOutputBuffers();
 
-  void VideoFrameReady(int32_t bitstream_buffer_id);
-  void NotifyError(int32_t bitstream_buffer_id, Error error);
-  void PostNotifyError(int32_t bitstream_buffer_id, Error error);
+  void VideoFrameReady(int32_t task_id);
+  void NotifyError(int32_t task_id, Error error);
+  void PostNotifyError(int32_t task_id, Error error);
 
   // Run on |decoder_thread_| to enqueue the coming frame.
   void DecodeTask(std::unique_ptr<JobRecord> job_record);
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index 4f45eb33..3651fd89 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -41,6 +41,7 @@
 #include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h"
 #include "media/gpu/v4l2/v4l2_image_processor.h"
 #include "media/gpu/v4l2/v4l2_vda_helpers.h"
+#include "media/gpu/v4l2/v4l2_vp8_accelerator.h"
 #include "media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h"
 #include "media/gpu/v4l2/v4l2_vp9_accelerator.h"
 #include "ui/gl/gl_context.h"
@@ -287,8 +288,13 @@
     }
   } else if (video_profile_ >= VP8PROFILE_MIN &&
              video_profile_ <= VP8PROFILE_MAX) {
-    decoder_.reset(new VP8Decoder(
-        std::make_unique<V4L2LegacyVP8Accelerator>(this, device_.get())));
+    if (supports_requests_) {
+      decoder_.reset(new VP8Decoder(
+          std::make_unique<V4L2VP8Accelerator>(this, device_.get())));
+    } else {
+      decoder_.reset(new VP8Decoder(
+          std::make_unique<V4L2LegacyVP8Accelerator>(this, device_.get())));
+    }
   } else if (video_profile_ >= VP9PROFILE_MIN &&
              video_profile_ <= VP9PROFILE_MAX) {
     decoder_.reset(new VP9Decoder(
diff --git a/media/gpu/v4l2/v4l2_vp8_accelerator.cc b/media/gpu/v4l2/v4l2_vp8_accelerator.cc
new file mode 100644
index 0000000..c9be027
--- /dev/null
+++ b/media/gpu/v4l2/v4l2_vp8_accelerator.cc
@@ -0,0 +1,266 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/v4l2/v4l2_vp8_accelerator.h"
+
+#define __LINUX_MEDIA_VP8_CTRLS_LEGACY_H
+#include <linux/videodev2.h>
+#include <linux/media/vp8-ctrls.h>
+
+#include <type_traits>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
+#include "media/gpu/macros.h"
+#include "media/gpu/v4l2/v4l2_decode_surface.h"
+#include "media/gpu/v4l2/v4l2_decode_surface_handler.h"
+#include "media/gpu/v4l2/v4l2_device.h"
+#include "media/gpu/vp8_picture.h"
+#include "media/parsers/vp8_parser.h"
+
+namespace media {
+namespace {
+
+void FillV4L2SegmentationHeader(
+    const Vp8SegmentationHeader& vp8_sgmnt_hdr,
+    struct v4l2_vp8_segment_header* v4l2_sgmnt_hdr) {
+#define SET_V4L2_SGMNT_HDR_FLAG_IF(cond, flag) \
+  v4l2_sgmnt_hdr->flags |= ((vp8_sgmnt_hdr.cond) ? (flag) : 0)
+  SET_V4L2_SGMNT_HDR_FLAG_IF(segmentation_enabled,
+                             V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED);
+  SET_V4L2_SGMNT_HDR_FLAG_IF(update_mb_segmentation_map,
+                             V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP);
+  SET_V4L2_SGMNT_HDR_FLAG_IF(update_segment_feature_data,
+                             V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_FEATURE_DATA);
+  // TODO not sure about this one?
+  SET_V4L2_SGMNT_HDR_FLAG_IF(
+      segment_feature_mode == Vp8SegmentationHeader::FEATURE_MODE_DELTA,
+      V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE);
+  SET_V4L2_SGMNT_HDR_FLAG_IF(segment_feature_mode,
+                             V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_FEATURE_DATA);
+#undef SET_V4L2_SGMNT_HDR_FLAG_IF
+
+  SafeArrayMemcpy(v4l2_sgmnt_hdr->quant_update,
+                  vp8_sgmnt_hdr.quantizer_update_value);
+  SafeArrayMemcpy(v4l2_sgmnt_hdr->lf_update, vp8_sgmnt_hdr.lf_update_value);
+  SafeArrayMemcpy(v4l2_sgmnt_hdr->segment_probs, vp8_sgmnt_hdr.segment_prob);
+}
+
+void FillV4L2LoopFilterHeader(const Vp8LoopFilterHeader& vp8_loopfilter_hdr,
+                              struct v4l2_vp8_loopfilter_header* v4l2_lf_hdr) {
+#define SET_V4L2_LF_HDR_FLAG_IF(cond, flag) \
+  v4l2_lf_hdr->flags |= ((vp8_loopfilter_hdr.cond) ? (flag) : 0)
+  SET_V4L2_LF_HDR_FLAG_IF(loop_filter_adj_enable,
+                          V4L2_VP8_LF_HEADER_ADJ_ENABLE);
+  SET_V4L2_LF_HDR_FLAG_IF(mode_ref_lf_delta_update,
+                          V4L2_VP8_LF_HEADER_DELTA_UPDATE);
+  SET_V4L2_LF_HDR_FLAG_IF(type == Vp8LoopFilterHeader::LOOP_FILTER_TYPE_SIMPLE,
+                          V4L2_VP8_LF_FILTER_TYPE_SIMPLE);
+#undef SET_V4L2_LF_HDR_FLAG_IF
+
+#define LF_HDR_TO_V4L2_LF_HDR(a) v4l2_lf_hdr->a = vp8_loopfilter_hdr.a;
+  LF_HDR_TO_V4L2_LF_HDR(level);
+  LF_HDR_TO_V4L2_LF_HDR(sharpness_level);
+#undef LF_HDR_TO_V4L2_LF_HDR
+
+  SafeArrayMemcpy(v4l2_lf_hdr->ref_frm_delta,
+                  vp8_loopfilter_hdr.ref_frame_delta);
+  SafeArrayMemcpy(v4l2_lf_hdr->mb_mode_delta, vp8_loopfilter_hdr.mb_mode_delta);
+}
+
+void FillV4L2QuantizationHeader(
+    const Vp8QuantizationHeader& vp8_quant_hdr,
+    struct v4l2_vp8_quantization_header* v4l2_quant_hdr) {
+  v4l2_quant_hdr->y_ac_qi = vp8_quant_hdr.y_ac_qi;
+  v4l2_quant_hdr->y_dc_delta = vp8_quant_hdr.y_dc_delta;
+  v4l2_quant_hdr->y2_dc_delta = vp8_quant_hdr.y2_dc_delta;
+  v4l2_quant_hdr->y2_ac_delta = vp8_quant_hdr.y2_ac_delta;
+  v4l2_quant_hdr->uv_dc_delta = vp8_quant_hdr.uv_dc_delta;
+  v4l2_quant_hdr->uv_ac_delta = vp8_quant_hdr.uv_ac_delta;
+}
+
+void FillV4L2Vp8EntropyHeader(
+    const Vp8EntropyHeader& vp8_entropy_hdr,
+    struct v4l2_vp8_entropy_header* v4l2_entropy_hdr) {
+  SafeArrayMemcpy(v4l2_entropy_hdr->coeff_probs, vp8_entropy_hdr.coeff_probs);
+  SafeArrayMemcpy(v4l2_entropy_hdr->y_mode_probs, vp8_entropy_hdr.y_mode_probs);
+  SafeArrayMemcpy(v4l2_entropy_hdr->uv_mode_probs,
+                  vp8_entropy_hdr.uv_mode_probs);
+  SafeArrayMemcpy(v4l2_entropy_hdr->mv_probs, vp8_entropy_hdr.mv_probs);
+}
+
+}  // namespace
+
+class V4L2VP8Picture : public VP8Picture {
+ public:
+  explicit V4L2VP8Picture(const scoped_refptr<V4L2DecodeSurface>& dec_surface)
+      : dec_surface_(dec_surface) {}
+
+  V4L2VP8Picture* AsV4L2VP8Picture() override { return this; }
+  scoped_refptr<V4L2DecodeSurface> dec_surface() { return dec_surface_; }
+
+ private:
+  ~V4L2VP8Picture() override {}
+
+  scoped_refptr<V4L2DecodeSurface> dec_surface_;
+
+  DISALLOW_COPY_AND_ASSIGN(V4L2VP8Picture);
+};
+
+V4L2VP8Accelerator::V4L2VP8Accelerator(
+    V4L2DecodeSurfaceHandler* surface_handler,
+    V4L2Device* device)
+    : surface_handler_(surface_handler), device_(device) {
+  DCHECK(surface_handler_);
+}
+
+V4L2VP8Accelerator::~V4L2VP8Accelerator() {}
+
+scoped_refptr<VP8Picture> V4L2VP8Accelerator::CreateVP8Picture() {
+  scoped_refptr<V4L2DecodeSurface> dec_surface =
+      surface_handler_->CreateSurface();
+  if (!dec_surface)
+    return nullptr;
+
+  return new V4L2VP8Picture(dec_surface);
+}
+
+bool V4L2VP8Accelerator::SubmitDecode(
+    scoped_refptr<VP8Picture> pic,
+    const Vp8ReferenceFrameVector& reference_frames) {
+  struct v4l2_ctrl_vp8_frame_header v4l2_frame_hdr;
+  memset(&v4l2_frame_hdr, 0, sizeof(v4l2_frame_hdr));
+
+  const auto& frame_hdr = pic->frame_hdr;
+#define FHDR_TO_V4L2_FHDR(a) v4l2_frame_hdr.a = frame_hdr->a
+  FHDR_TO_V4L2_FHDR(version);
+  FHDR_TO_V4L2_FHDR(width);
+  FHDR_TO_V4L2_FHDR(horizontal_scale);
+  FHDR_TO_V4L2_FHDR(height);
+  FHDR_TO_V4L2_FHDR(vertical_scale);
+  FHDR_TO_V4L2_FHDR(prob_skip_false);
+  FHDR_TO_V4L2_FHDR(prob_intra);
+  FHDR_TO_V4L2_FHDR(prob_last);
+  FHDR_TO_V4L2_FHDR(prob_gf);
+#undef FHDR_TO_V4L2_FHDR
+  v4l2_frame_hdr.coder_state.range = frame_hdr->bool_dec_range;
+  v4l2_frame_hdr.coder_state.value = frame_hdr->bool_dec_value;
+  v4l2_frame_hdr.coder_state.bit_count = frame_hdr->bool_dec_count;
+
+#define SET_V4L2_FRM_HDR_FLAG_IF(cond, flag) \
+  v4l2_frame_hdr.flags |= ((frame_hdr->cond) ? (flag) : 0)
+  SET_V4L2_FRM_HDR_FLAG_IF(frame_type == Vp8FrameHeader::KEYFRAME,
+                           V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME);
+  SET_V4L2_FRM_HDR_FLAG_IF(sign_bias_golden,
+                           V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN);
+  SET_V4L2_FRM_HDR_FLAG_IF(sign_bias_alternate,
+                           V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT);
+  SET_V4L2_FRM_HDR_FLAG_IF(is_experimental,
+                           V4L2_VP8_FRAME_HEADER_FLAG_EXPERIMENTAL);
+  SET_V4L2_FRM_HDR_FLAG_IF(show_frame, V4L2_VP8_FRAME_HEADER_FLAG_SHOW_FRAME);
+  SET_V4L2_FRM_HDR_FLAG_IF(mb_no_skip_coeff,
+                           V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF);
+#undef SET_V4L2_FRM_HDR_FLAG_IF
+
+  FillV4L2SegmentationHeader(frame_hdr->segmentation_hdr,
+                             &v4l2_frame_hdr.segment_header);
+
+  FillV4L2LoopFilterHeader(frame_hdr->loopfilter_hdr,
+                           &v4l2_frame_hdr.lf_header);
+
+  FillV4L2QuantizationHeader(frame_hdr->quantization_hdr,
+                             &v4l2_frame_hdr.quant_header);
+
+  FillV4L2Vp8EntropyHeader(frame_hdr->entropy_hdr,
+                           &v4l2_frame_hdr.entropy_header);
+
+  v4l2_frame_hdr.first_part_size =
+      base::checked_cast<__u32>(frame_hdr->first_part_size);
+  v4l2_frame_hdr.first_part_header_bits =
+      base::checked_cast<__u32>(frame_hdr->macroblock_bit_offset);
+  v4l2_frame_hdr.num_dct_parts = frame_hdr->num_of_dct_partitions;
+
+  static_assert(std::extent<decltype(v4l2_frame_hdr.dct_part_sizes)>() ==
+                    std::extent<decltype(frame_hdr->dct_partition_sizes)>(),
+                "DCT partition size arrays must have equal number of elements");
+  for (size_t i = 0; i < frame_hdr->num_of_dct_partitions &&
+                     i < base::size(v4l2_frame_hdr.dct_part_sizes);
+       ++i)
+    v4l2_frame_hdr.dct_part_sizes[i] = frame_hdr->dct_partition_sizes[i];
+
+  scoped_refptr<V4L2DecodeSurface> dec_surface =
+      VP8PictureToV4L2DecodeSurface(pic);
+  std::vector<scoped_refptr<V4L2DecodeSurface>> ref_surfaces;
+
+  const auto last_frame = reference_frames.GetFrame(Vp8RefType::VP8_FRAME_LAST);
+  if (last_frame) {
+    scoped_refptr<V4L2DecodeSurface> last_frame_surface =
+        VP8PictureToV4L2DecodeSurface(last_frame);
+    v4l2_frame_hdr.last_frame_ts = last_frame_surface->GetReferenceID();
+    ref_surfaces.push_back(last_frame_surface);
+  }
+
+  const auto golden_frame =
+      reference_frames.GetFrame(Vp8RefType::VP8_FRAME_GOLDEN);
+  if (golden_frame) {
+    scoped_refptr<V4L2DecodeSurface> golden_frame_surface =
+        VP8PictureToV4L2DecodeSurface(golden_frame);
+    v4l2_frame_hdr.golden_frame_ts = golden_frame_surface->GetReferenceID();
+    ref_surfaces.push_back(golden_frame_surface);
+  }
+
+  const auto alt_frame =
+      reference_frames.GetFrame(Vp8RefType::VP8_FRAME_ALTREF);
+  if (alt_frame) {
+    scoped_refptr<V4L2DecodeSurface> alt_frame_surface =
+        VP8PictureToV4L2DecodeSurface(alt_frame);
+    v4l2_frame_hdr.alt_frame_ts = alt_frame_surface->GetReferenceID();
+    ref_surfaces.push_back(alt_frame_surface);
+  }
+
+  struct v4l2_ext_control ctrl;
+  memset(&ctrl, 0, sizeof(ctrl));
+  ctrl.id = V4L2_CTRL_TYPE_VP8_FRAME_HEADER;
+  ctrl.size = sizeof(v4l2_frame_hdr);
+  ctrl.ptr = &v4l2_frame_hdr;
+
+  struct v4l2_ext_controls ext_ctrls;
+  memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+  ext_ctrls.count = 1;
+  ext_ctrls.controls = &ctrl;
+  dec_surface->PrepareSetCtrls(&ext_ctrls);
+  if (device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) != 0) {
+    VPLOGF(1) << "ioctl() failed: VIDIOC_S_EXT_CTRLS";
+    return false;
+  }
+
+  dec_surface->SetReferenceSurfaces(ref_surfaces);
+
+  if (!surface_handler_->SubmitSlice(dec_surface, frame_hdr->data,
+                                     frame_hdr->frame_size))
+    return false;
+
+  DVLOGF(4) << "Submitting decode for surface: " << dec_surface->ToString();
+  surface_handler_->DecodeSurface(dec_surface);
+  return true;
+}
+
+bool V4L2VP8Accelerator::OutputPicture(const scoped_refptr<VP8Picture>& pic) {
+  // TODO(crbug.com/647725): Insert correct color space.
+  surface_handler_->SurfaceReady(VP8PictureToV4L2DecodeSurface(pic),
+                                 pic->bitstream_id(), pic->visible_rect(),
+                                 VideoColorSpace());
+  return true;
+}
+
+scoped_refptr<V4L2DecodeSurface>
+V4L2VP8Accelerator::VP8PictureToV4L2DecodeSurface(
+    const scoped_refptr<VP8Picture>& pic) {
+  V4L2VP8Picture* v4l2_pic = pic->AsV4L2VP8Picture();
+  CHECK(v4l2_pic);
+  return v4l2_pic->dec_surface();
+}
+
+}  // namespace media
diff --git a/media/gpu/v4l2/v4l2_vp8_accelerator.h b/media/gpu/v4l2/v4l2_vp8_accelerator.h
new file mode 100644
index 0000000..edff830
--- /dev/null
+++ b/media/gpu/v4l2/v4l2_vp8_accelerator.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_H_
+#define MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "media/gpu/vp8_decoder.h"
+
+namespace media {
+
+class V4L2Device;
+class V4L2DecodeSurface;
+class V4L2DecodeSurfaceHandler;
+
+class V4L2VP8Accelerator : public VP8Decoder::VP8Accelerator {
+ public:
+  explicit V4L2VP8Accelerator(V4L2DecodeSurfaceHandler* surface_handler,
+                              V4L2Device* device);
+  ~V4L2VP8Accelerator() override;
+
+  // VP8Decoder::VP8Accelerator implementation.
+  scoped_refptr<VP8Picture> CreateVP8Picture() override;
+  bool SubmitDecode(scoped_refptr<VP8Picture> pic,
+                    const Vp8ReferenceFrameVector& reference_frames) override;
+  bool OutputPicture(const scoped_refptr<VP8Picture>& pic) override;
+
+ private:
+  scoped_refptr<V4L2DecodeSurface> VP8PictureToV4L2DecodeSurface(
+      const scoped_refptr<VP8Picture>& pic);
+
+  V4L2DecodeSurfaceHandler* const surface_handler_;
+  V4L2Device* const device_;
+
+  DISALLOW_COPY_AND_ASSIGN(V4L2VP8Accelerator);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_H_
diff --git a/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.cc b/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.cc
index c08787fa..0fec58cd 100644
--- a/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.cc
+++ b/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.cc
@@ -32,7 +32,7 @@
                              V4L2_VP8_SEGMNT_HDR_FLAG_UPDATE_MAP);
   SET_V4L2_SGMNT_HDR_FLAG_IF(update_segment_feature_data,
                              V4L2_VP8_SEGMNT_HDR_FLAG_UPDATE_FEATURE_DATA);
-#undef SET_V4L2_SPARM_FLAG_IF
+#undef SET_V4L2_SGMNT_HDR_FLAG_IF
   v4l2_sgmnt_hdr->segment_feature_mode = vp8_sgmnt_hdr.segment_feature_mode;
 
   SafeArrayMemcpy(v4l2_sgmnt_hdr->quant_update,
@@ -48,7 +48,7 @@
   SET_V4L2_LF_HDR_FLAG_IF(loop_filter_adj_enable, V4L2_VP8_LF_HDR_ADJ_ENABLE);
   SET_V4L2_LF_HDR_FLAG_IF(mode_ref_lf_delta_update,
                           V4L2_VP8_LF_HDR_DELTA_UPDATE);
-#undef SET_V4L2_SGMNT_HDR_FLAG_IF
+#undef SET_V4L2_LF_HDR_FLAG_IF
 
 #define LF_HDR_TO_V4L2_LF_HDR(a) v4l2_lf_hdr->a = vp8_loopfilter_hdr.a;
   LF_HDR_TO_V4L2_LF_HDR(type);
diff --git a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
index b68e42c..bd6381c8 100644
--- a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
@@ -5,6 +5,7 @@
 #include "media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.h"
 
 #include <stddef.h>
+#include <sys/mman.h>
 #include <va/va.h>
 
 #include <array>
@@ -13,13 +14,14 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback_helpers.h"
-#include "base/containers/span.h"
+#include "base/files/scoped_file.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/optional.h"
+#include "base/process/process_metrics.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -133,13 +135,12 @@
 
 }  // namespace
 
-void VaapiMjpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
-                                              Error error) {
+void VaapiMjpegDecodeAccelerator::NotifyError(int32_t task_id, Error error) {
   if (!task_runner_->BelongsToCurrentThread()) {
     task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&VaapiMjpegDecodeAccelerator::NotifyError,
-                                  weak_this_factory_.GetWeakPtr(),
-                                  bitstream_buffer_id, error));
+        FROM_HERE,
+        base::BindOnce(&VaapiMjpegDecodeAccelerator::NotifyError,
+                       weak_this_factory_.GetWeakPtr(), task_id, error));
     return;
   }
   VLOGF(1) << "Notifying of error " << error;
@@ -148,14 +149,14 @@
   DCHECK_NE(chromeos_camera::MjpegDecodeAccelerator::Error::NO_ERRORS, error);
   ReportToVAJDAResponseToClientUMA(error);
   DCHECK(client_);
-  client_->NotifyError(bitstream_buffer_id, error);
+  client_->NotifyError(task_id, error);
 }
 
-void VaapiMjpegDecodeAccelerator::VideoFrameReady(int32_t bitstream_buffer_id) {
+void VaapiMjpegDecodeAccelerator::VideoFrameReady(int32_t task_id) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   ReportToVAJDAResponseToClientUMA(
       chromeos_camera::MjpegDecodeAccelerator::Error::NO_ERRORS);
-  client_->VideoFrameReady(bitstream_buffer_id);
+  client_->VideoFrameReady(task_id);
 }
 
 VaapiMjpegDecodeAccelerator::VaapiMjpegDecodeAccelerator(
@@ -286,6 +287,7 @@
     buffer_unmapper.ReplaceClosure(
         base::BindOnce(&gpu::GpuMemoryBufferImpl::Unmap, std::move(gmb)));
   } else {
+    DCHECK(video_frame->IsMappable());
     for (size_t i = 0; i < video_frame->layout().num_planes(); i++) {
       dst_ptrs[i] = video_frame->visible_data(i);
       dst_strides[i] = video_frame->stride(i);
@@ -433,65 +435,102 @@
   return true;
 }
 
-void VaapiMjpegDecodeAccelerator::DecodeTask(
-    int32_t bitstream_buffer_id,
+void VaapiMjpegDecodeAccelerator::DecodeFromShmTask(
+    int32_t task_id,
     std::unique_ptr<UnalignedSharedMemory> shm,
-    scoped_refptr<VideoFrame> video_frame) {
+    scoped_refptr<VideoFrame> dst_frame) {
   DVLOGF(4);
   DCHECK(decoder_task_runner_->BelongsToCurrentThread());
-  TRACE_EVENT0("jpeg", "DecodeTask");
+  TRACE_EVENT0("jpeg", __func__);
 
+  auto src_image =
+      base::make_span(static_cast<const uint8_t*>(shm->memory()), shm->size());
+  DecodeImpl(task_id, src_image, std::move(dst_frame));
+}
+
+void VaapiMjpegDecodeAccelerator::DecodeFromDmaBufTask(
+    int32_t task_id,
+    base::ScopedFD src_dmabuf_fd,
+    size_t src_size,
+    off_t src_offset,
+    scoped_refptr<VideoFrame> dst_frame) {
+  DVLOGF(4);
+  DCHECK(decoder_task_runner_->BelongsToCurrentThread());
+  TRACE_EVENT0("jpeg", __func__);
+
+  // The DMA-buf FD should be mapped as read-only since it may only have read
+  // permission, e.g. when it comes from camera driver.
+  DCHECK(src_dmabuf_fd.is_valid());
+  DCHECK_GT(src_size, 0u);
+  void* src_addr = mmap(nullptr, src_size, PROT_READ, MAP_SHARED,
+                        src_dmabuf_fd.get(), src_offset);
+  if (src_addr == MAP_FAILED) {
+    VPLOGF(1) << "Failed to map input DMA buffer";
+    NotifyError(task_id, UNREADABLE_INPUT);
+    return;
+  }
+  base::span<const uint8_t> src_image =
+      base::make_span(static_cast<const uint8_t*>(src_addr), src_size);
+
+  DecodeImpl(task_id, src_image, std::move(dst_frame));
+
+  const int ret = munmap(src_addr, src_size);
+  DPCHECK(ret == 0);
+}
+
+void VaapiMjpegDecodeAccelerator::DecodeImpl(
+    int32_t task_id,
+    base::span<const uint8_t> src_image,
+    scoped_refptr<VideoFrame> dst_frame) {
   // TODO(andrescj): validate that the video frame's visible size is the same as
   // the parsed JPEG's visible size when it is returned from Decode(), and
   // remove the size checks in OutputPicture*().
-  VaapiImageDecodeStatus status = decoder_.Decode(
-      base::make_span(static_cast<const uint8_t*>(shm->memory()), shm->size()));
+  VaapiImageDecodeStatus status = decoder_.Decode(src_image);
   if (status != VaapiImageDecodeStatus::kSuccess) {
-    NotifyError(bitstream_buffer_id, VaapiJpegDecodeStatusToError(status));
+    NotifyError(task_id, VaapiJpegDecodeStatusToError(status));
     return;
   }
   const ScopedVASurface* surface = decoder_.GetScopedVASurface();
   DCHECK(surface);
   DCHECK(surface->IsValid());
 
-  // For DMA-buf backed |video_frame|, we will import it as a VA surface and use
+  // For DMA-buf backed |dst_frame|, we will import it as a VA surface and use
   // VPP to convert the decoded |surface| into it, if the formats and sizes are
   // supported.
   const uint32_t video_frame_va_fourcc =
-      VideoPixelFormatToVAFourCC(video_frame->format());
+      VideoPixelFormatToVAFourCC(dst_frame->format());
   if (video_frame_va_fourcc == kInvalidVaFourcc) {
-    VLOGF(1) << "Unsupported video frame format: " << video_frame->format();
-    NotifyError(bitstream_buffer_id, PLATFORM_FAILURE);
+    VLOGF(1) << "Unsupported video frame format: " << dst_frame->format();
+    NotifyError(task_id, PLATFORM_FAILURE);
     return;
   }
   // TODO(kamesan): move HasDmaBufs() to DCHECK when we deprecate
   // shared-memory-backed video frame.
-  if (video_frame->HasDmaBufs() &&
+  if (dst_frame->HasDmaBufs() &&
       VaapiWrapper::IsVppResolutionAllowed(surface->size()) &&
       VaapiWrapper::IsVppSupportedForJpegDecodedSurfaceToFourCC(
           surface->format(), video_frame_va_fourcc)) {
-    if (!OutputPictureVppOnTaskRunner(surface, bitstream_buffer_id,
-                                      std::move(video_frame))) {
+    if (!OutputPictureVppOnTaskRunner(surface, task_id, std::move(dst_frame))) {
       VLOGF(1) << "Output picture using VPP failed";
-      NotifyError(bitstream_buffer_id, PLATFORM_FAILURE);
+      NotifyError(task_id, PLATFORM_FAILURE);
     }
     return;
   }
 
   // Fallback to do conversion by libyuv. This happens when:
-  // 1. |video_frame| is backed by shared memory.
+  // 1. |dst_frame| is backed by shared memory.
   // 2. VPP doesn't support the format conversion. This is intended for AMD
   //    VAAPI driver whose VPP only supports converting decoded 4:2:0 JPEGs.
   std::unique_ptr<ScopedVAImage> image =
       decoder_.GetImage(video_frame_va_fourcc, &status);
   if (status != VaapiImageDecodeStatus::kSuccess) {
-    NotifyError(bitstream_buffer_id, VaapiJpegDecodeStatusToError(status));
+    NotifyError(task_id, VaapiJpegDecodeStatusToError(status));
     return;
   }
-  if (!OutputPictureLibYuvOnTaskRunner(std::move(image), bitstream_buffer_id,
-                                       std::move(video_frame))) {
+  if (!OutputPictureLibYuvOnTaskRunner(std::move(image), task_id,
+                                       std::move(dst_frame))) {
     VLOGF(1) << "Output picture using libyuv failed";
-    NotifyError(bitstream_buffer_id, PLATFORM_FAILURE);
+    NotifyError(task_id, PLATFORM_FAILURE);
   }
 }
 
@@ -499,7 +538,7 @@
     BitstreamBuffer bitstream_buffer,
     scoped_refptr<VideoFrame> video_frame) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
-  TRACE_EVENT1("jpeg", "Decode", "input_id", bitstream_buffer.id());
+  TRACE_EVENT1("jpeg", __func__, "input_id", bitstream_buffer.id());
 
   DVLOGF(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
             << " size: " << bitstream_buffer.size();
@@ -510,6 +549,12 @@
     return;
   }
 
+  // Validate output video frame.
+  if (!video_frame->IsMappable() && !video_frame->HasDmaBufs()) {
+    VLOGF(1) << "Unsupported output frame storage type";
+    NotifyError(bitstream_buffer.id(), INVALID_ARGUMENT);
+    return;
+  }
   if ((video_frame->visible_rect().width() & 1) ||
       (video_frame->visible_rect().height() & 1)) {
     VLOGF(1) << "Video frame visible size has odd dimension";
@@ -531,11 +576,67 @@
   // It's safe to use base::Unretained(this) because |decoder_task_runner_| runs
   // tasks on |decoder_thread_| which is stopped in the destructor of |this|.
   decoder_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VaapiMjpegDecodeAccelerator::DecodeTask,
+      FROM_HERE, base::BindOnce(&VaapiMjpegDecodeAccelerator::DecodeFromShmTask,
                                 base::Unretained(this), bitstream_buffer.id(),
                                 std::move(shm), std::move(video_frame)));
 }
 
+void VaapiMjpegDecodeAccelerator::Decode(int32_t task_id,
+                                         base::ScopedFD src_dmabuf_fd,
+                                         size_t src_size,
+                                         off_t src_offset,
+                                         scoped_refptr<VideoFrame> dst_frame) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  TRACE_EVENT1("jpeg", __func__, "task_id", task_id);
+
+  if (task_id < 0) {
+    VLOGF(1) << "Invalid task id: " << task_id;
+    NotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+
+  // Validate input arguments.
+  if (!src_dmabuf_fd.is_valid()) {
+    VLOGF(1) << "Invalid input buffer FD";
+    NotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+  if (src_size == 0) {
+    VLOGF(1) << "Input buffer size is zero";
+    NotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+  const size_t page_size = base::GetPageSize();
+  if (src_offset < 0 || src_offset % page_size != 0) {
+    VLOGF(1) << "Input buffer offset (" << src_offset
+             << ") should be non-negative and aligned to page size ("
+             << page_size << ")";
+    NotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+
+  // Validate output video frame.
+  if (!dst_frame->IsMappable() && !dst_frame->HasDmaBufs()) {
+    VLOGF(1) << "Unsupported output frame storage type";
+    NotifyError(task_id, INVALID_ARGUMENT);
+    return;
+  }
+  if ((dst_frame->visible_rect().width() & 1) ||
+      (dst_frame->visible_rect().height() & 1)) {
+    VLOGF(1) << "Output frame visible size has odd dimension";
+    NotifyError(task_id, PLATFORM_FAILURE);
+    return;
+  }
+
+  // It's safe to use base::Unretained(this) because |decoder_task_runner_| runs
+  // tasks on |decoder_thread_| which is stopped in the destructor of |this|.
+  decoder_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&VaapiMjpegDecodeAccelerator::DecodeFromDmaBufTask,
+                     base::Unretained(this), task_id, std::move(src_dmabuf_fd),
+                     src_size, src_offset, std::move(dst_frame)));
+}
+
 bool VaapiMjpegDecodeAccelerator::IsSupported() {
   return VaapiWrapper::IsDecodeSupported(VAProfileJPEGBaseline);
 }
diff --git a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.h b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.h
index ff507816..419ddd4 100644
--- a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.h
+++ b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/containers/span.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
@@ -53,22 +54,38 @@
       chromeos_camera::MjpegDecodeAccelerator::Client* client) override;
   void Decode(BitstreamBuffer bitstream_buffer,
               scoped_refptr<VideoFrame> video_frame) override;
+  void Decode(int32_t task_id,
+              base::ScopedFD src_dmabuf_fd,
+              size_t src_size,
+              off_t src_offset,
+              scoped_refptr<VideoFrame> dst_frame) override;
   bool IsSupported() override;
 
  private:
   // Notifies the client that an error has occurred and decoding cannot
   // continue. The client is notified on the |task_runner_|, i.e., the thread in
   // which |*this| was created.
-  void NotifyError(int32_t bitstream_buffer_id, Error error);
+  void NotifyError(int32_t task_id, Error error);
 
   // Notifies the client that a decode is ready. The client is notified on the
   // |task_runner_|, i.e., the thread in which |*this| was created.
-  void VideoFrameReady(int32_t bitstream_buffer_id);
+  void VideoFrameReady(int32_t task_id);
 
   // Processes one decode request.
-  void DecodeTask(int32_t bitstream_buffer_id,
-                  std::unique_ptr<UnalignedSharedMemory> shm,
-                  scoped_refptr<VideoFrame> video_frame);
+  void DecodeFromShmTask(int32_t task_id,
+                         std::unique_ptr<UnalignedSharedMemory> shm,
+                         scoped_refptr<VideoFrame> dst_frame);
+  void DecodeFromDmaBufTask(int32_t task_id,
+                            base::ScopedFD src_dmabuf_fd,
+                            size_t src_size,
+                            off_t src_offset,
+                            scoped_refptr<VideoFrame> dst_frame);
+
+  // Decodes the JPEG in |src_image| into |dst_frame| and notifies the client
+  // when finished or when an error occurs.
+  void DecodeImpl(int32_t task_id,
+                  base::span<const uint8_t> src_image,
+                  scoped_refptr<VideoFrame> dst_frame);
 
   // Puts contents of |surface| into given |video_frame| using VA-API Video
   // Processing Pipeline (VPP), and passes the |input_buffer_id| of the
diff --git a/media/gpu/video_frame_mapper_factory.cc b/media/gpu/video_frame_mapper_factory.cc
index 6989b97e..f4fa04b 100644
--- a/media/gpu/video_frame_mapper_factory.cc
+++ b/media/gpu/video_frame_mapper_factory.cc
@@ -7,9 +7,9 @@
 #include "build/build_config.h"
 #include "media/gpu/buildflags.h"
 
-#if BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 #include "media/gpu/linux/generic_dmabuf_video_frame_mapper.h"
-#endif  // BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 #if BUILDFLAG(USE_VAAPI)
 #include "media/gpu/vaapi/vaapi_dmabuf_video_frame_mapper.h"
@@ -31,10 +31,10 @@
 std::unique_ptr<VideoFrameMapper> VideoFrameMapperFactory::CreateMapper(
     VideoPixelFormat format,
     bool linear_buffer_mapper) {
-#if BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   if (linear_buffer_mapper)
     return GenericDmaBufVideoFrameMapper::Create(format);
-#endif  // BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
+#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
 #if BUILDFLAG(USE_VAAPI)
   return VaapiDmaBufVideoFrameMapper::Create(format);
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index c841bf8..2fa80cd 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -289,6 +289,12 @@
   // It doesn't make sense for the request to have IO pending at this point.
   DCHECK_NE(bytes_read, ERR_IO_PENDING);
 
+  // If you've reached this, you've either called "RunUntilComplete" or are
+  // using legacy "QuitCurrent*Deprecated". If this DCHECK fails, that probably
+  // means you've run "RunUntilRedirect" or "RunUntilAuthRequired" and haven't
+  // redirected/auth-challenged
+  DCHECK(on_complete_ || use_legacy_on_complete_);
+
   // If the request was cancelled in a redirect, it should not signal
   // OnReadCompleted. Note that |cancel_in_rs_| may be true due to
   // https://crbug.com/564848.
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc
index 2119f3c..204f4a1 100644
--- a/net/websockets/websocket_channel.cc
+++ b/net/websockets/websocket_channel.cc
@@ -585,7 +585,6 @@
     return CHANNEL_ALIVE;
   }
 
-  // TODO(yoichio): Add test for this case.
   if (!InClosingState() && has_received_close_frame_) {
     DCHECK(!event_interface_->HasPendingDataFrames());
     // We've been waiting for the client to consume the frames before
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index 67aa5c8..748306c 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -1078,6 +1078,41 @@
   CreateChannelAndConnectSuccessfully();
 }
 
+// Do not close until browser has sent all pending frames.
+TEST_F(WebSocketChannelEventInterfaceTest, ShouldCloseWhileNoDataFrames) {
+  auto stream = std::make_unique<ReadableFakeWebSocketStream>();
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
+       CLOSE_DATA(SERVER_ERROR, "Internal Server Error")}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
+                                 ERR_CONNECTION_CLOSED);
+  set_stream(std::move(stream));
+  Checkpoint checkpoint;
+  {
+    InSequence s;
+    EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
+    EXPECT_CALL(*event_interface_, OnSendFlowControlQuotaAdded(_));
+    EXPECT_CALL(*event_interface_, HasPendingDataFrames())
+        .WillOnce(Return(false))
+        .WillOnce(Return(true))
+        .WillOnce(Return(true));
+    EXPECT_CALL(checkpoint, Call(1));
+#if DCHECK_IS_ON()
+    EXPECT_CALL(*event_interface_, HasPendingDataFrames())
+        .WillOnce(Return(false));
+#endif
+    EXPECT_CALL(*event_interface_, OnClosingHandshake());
+    EXPECT_CALL(*event_interface_,
+                OnDropChannel(true, kWebSocketErrorInternalServerError,
+                              "Internal Server Error"));
+  }
+
+  CreateChannelAndConnectSuccessfully();
+  checkpoint.Call(1);
+  ASSERT_EQ(CHANNEL_DELETED, channel_->ReadFrames());
+}
+
 // A remote server could close the connection immediately after sending the
 // handshake response (most likely a bug in the server).
 TEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) {
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index 4803b84..25f4f7c 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -1893,107 +1893,6 @@
                              "LOAD_RESTRICTED_PREFETCH flag is not trusted"));
 }
 
-// TODO(yhirano): Remove this as soon as possible.
-TEST_F(CorsURLLoaderTest, ExtraSafelistedHeader1) {
-  const GURL origin("https://example.com");
-  const GURL url("https://other.example.com/foo.png");
-  const GURL new_url("https://other2.example.com/bar.png");
-
-  ResourceRequest request;
-  request.mode = mojom::RequestMode::kCors;
-  request.credentials_mode = mojom::CredentialsMode::kOmit;
-  request.method = "GET";
-  request.url = url;
-  request.request_initiator = url::Origin::Create(origin);
-  request.headers.SetHeader("x-gOOgapps-allowed-domains", "foo");
-  request.headers.SetHeader("YouTube-restricT", "bar");
-
-  CreateLoaderAndStart(request);
-
-  // NO preflight request
-  ASSERT_EQ(1, num_created_loaders());
-  EXPECT_EQ(GetRequest().url, url);
-  EXPECT_EQ(GetRequest().method, "GET");
-}
-
-// TODO(yhirano): Remove this as soon as possible.
-TEST_F(CorsURLLoaderTest, ExtraSafelistedHeader2) {
-  const GURL origin("https://example.com");
-  const GURL url("https://other.example.com/foo.png");
-  const GURL new_url("https://other2.example.com/bar.png");
-
-  ResourceRequest request;
-  request.mode = mojom::RequestMode::kCors;
-  request.credentials_mode = mojom::CredentialsMode::kOmit;
-  request.method = "GET";
-  request.url = url;
-  request.request_initiator = url::Origin::Create(origin);
-  request.headers.SetHeader("x-gOOgapps-allowed-domains", "foo");
-
-  CreateLoaderAndStart(request);
-
-  // NO preflight request
-  ASSERT_EQ(1, num_created_loaders());
-  EXPECT_EQ(GetRequest().url, url);
-  EXPECT_EQ(GetRequest().method, "GET");
-}
-
-// TODO(yhirano): Remove this as soon as possible.
-TEST_F(CorsURLLoaderTest, ExtraSafelistedHeader3) {
-  const GURL origin("https://example.com");
-  const GURL url("https://other.example.com/foo.png");
-  const GURL new_url("https://other2.example.com/bar.png");
-
-  ResourceRequest request;
-  request.mode = mojom::RequestMode::kCors;
-  request.credentials_mode = mojom::CredentialsMode::kOmit;
-  request.method = "GET";
-  request.url = url;
-  request.request_initiator = url::Origin::Create(origin);
-  request.headers.SetHeader("x-gOOgapps-allowed-domains", "foo");
-  request.headers.SetHeader("foo", "foo");
-
-  CreateLoaderAndStart(request);
-
-  // preflight request
-  ASSERT_EQ(1, num_created_loaders());
-  EXPECT_EQ(GetRequest().url, url);
-  EXPECT_EQ(GetRequest().method, "OPTIONS");
-
-  std::string headers;
-  EXPECT_TRUE(GetRequest().headers.GetHeader("access-control-request-headers",
-                                             &headers));
-  EXPECT_EQ(headers, "foo");
-}
-
-// TODO(yhirano): Remove this as soon as possible.
-TEST_F(CorsURLLoaderTest, ExtraSafelistedHeader4) {
-  const GURL origin("https://example.com");
-  const GURL url("https://other.example.com/foo.png");
-  const GURL new_url("https://other2.example.com/bar.png");
-
-  ResourceRequest request;
-  request.mode = mojom::RequestMode::kCors;
-  request.credentials_mode = mojom::CredentialsMode::kOmit;
-  request.method = "GET";
-  request.url = url;
-  request.request_initiator = url::Origin::Create(origin);
-  request.headers.SetHeader("x-gOOgapps-allowed-domains", "foo");
-  request.headers.SetHeader("YouTube-restricT", "bar");
-  request.headers.SetHeader("hoge", "fuga");
-
-  CreateLoaderAndStart(request);
-
-  // preflight request
-  ASSERT_EQ(1, num_created_loaders());
-  EXPECT_EQ(GetRequest().url, url);
-  EXPECT_EQ(GetRequest().method, "OPTIONS");
-  std::string headers;
-  EXPECT_TRUE(GetRequest().headers.GetHeader("access-control-request-headers",
-                                             &headers));
-  EXPECT_EQ(headers, "hoge");
-}
-
 }  // namespace
 
 }  // namespace cors
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index a7ba430..93adb0b4 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -646,8 +646,10 @@
       std::move(request), &cors_origin_access_list_, nullptr));
 }
 
-void NetworkContext::SetClient(mojom::NetworkContextClientPtr client) {
-  client_ = std::move(client);
+void NetworkContext::SetClient(
+    mojo::PendingRemote<mojom::NetworkContextClient> client) {
+  client_.reset();
+  client_.Bind(std::move(client));
 }
 
 void NetworkContext::CreateURLLoaderFactory(
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 04873a0c..a6be42bf 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -25,6 +25,7 @@
 #include "build/build_config.h"
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cert/cert_verify_result.h"
@@ -138,7 +139,9 @@
 
   NetworkService* network_service() { return network_service_; }
 
-  mojom::NetworkContextClient* client() { return client_.get(); }
+  mojom::NetworkContextClient* client() {
+    return client_.is_bound() ? client_.get() : nullptr;
+  }
 
   ResourceScheduler* resource_scheduler() { return resource_scheduler_.get(); }
 
@@ -163,7 +166,8 @@
       scoped_refptr<ResourceSchedulerClient> resource_scheduler_client);
 
   // mojom::NetworkContext implementation:
-  void SetClient(mojom::NetworkContextClientPtr client) override;
+  void SetClient(
+      mojo::PendingRemote<mojom::NetworkContextClient> client) override;
   void CreateURLLoaderFactory(mojom::URLLoaderFactoryRequest request,
                               mojom::URLLoaderFactoryParamsPtr params) override;
   void ResetURLLoaderFactories() override;
@@ -457,7 +461,7 @@
 
   NetworkService* const network_service_;
 
-  mojom::NetworkContextClientPtr client_;
+  mojo::Remote<mojom::NetworkContextClient> client_;
 
   std::unique_ptr<ResourceScheduler> resource_scheduler_;
 
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index 56a5a53..dfe2ef19 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -21,6 +21,8 @@
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "net/base/escape.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
@@ -1520,8 +1522,8 @@
 class ClearSiteDataNetworkContextClient : public TestNetworkContextClient {
  public:
   explicit ClearSiteDataNetworkContextClient(
-      mojom::NetworkContextClientRequest request)
-      : binding_(this, std::move(request)) {}
+      mojo::PendingReceiver<mojom::NetworkContextClient> receiver)
+      : receiver_(this, std::move(receiver)) {}
   ~ClearSiteDataNetworkContextClient() override = default;
 
   void OnClearSiteData(uint32_t process_id,
@@ -1549,7 +1551,7 @@
  private:
   int on_clear_site_data_counter_ = 0;
   std::string last_on_clear_site_data_header_value_;
-  mojo::Binding<mojom::NetworkContextClient> binding_;
+  mojo::Receiver<mojom::NetworkContextClient> receiver_;
 };
 
 // Check that |NetworkServiceNetworkDelegate| handles Clear-Site-Data header
@@ -1567,10 +1569,10 @@
 
   // With |NetworkContextCient|. The request should go through
   // |ClearSiteDataNetworkContextClient| and complete.
-  mojom::NetworkContextClientPtr client_ptr;
+  mojo::PendingRemote<mojom::NetworkContextClient> client_remote;
   auto client_impl = std::make_unique<ClearSiteDataNetworkContextClient>(
-      mojo::MakeRequest(&client_ptr));
-  network_context_->SetClient(std::move(client_ptr));
+      client_remote.InitWithNewPipeAndPassReceiver());
+  network_context_->SetClient(std::move(client_remote));
   url = https_server()->GetURL("/bar");
   url = AddQuery(url, "header", kClearCookiesHeader);
   EXPECT_EQ(0, client_impl->on_clear_site_data_counter());
@@ -1585,10 +1587,10 @@
   const char kClearCookiesHeader[] = "Clear-Site-Data: \"cookies\"";
   CreateNetworkContext();
 
-  mojom::NetworkContextClientPtr client_ptr;
+  mojo::PendingRemote<mojom::NetworkContextClient> client_remote;
   auto client_impl = std::make_unique<ClearSiteDataNetworkContextClient>(
-      mojo::MakeRequest(&client_ptr));
-  network_context_->SetClient(std::move(client_ptr));
+      client_remote.InitWithNewPipeAndPassReceiver());
+  network_context_->SetClient(std::move(client_remote));
 
   // |passed_header_value| are only checked if |should_call_client| is true.
   const struct TestCase {
diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc
index 0348748..e0345d0 100644
--- a/services/network/public/cpp/cors/cors.cc
+++ b/services/network/public/cpp/cors/cors.cc
@@ -10,13 +10,11 @@
 #include <vector>
 
 #include "base/containers/flat_set.h"
-#include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "net/base/mime_util.h"
 #include "net/http/http_request_headers.h"
-#include "services/network/public/cpp/features.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 #include "url/url_constants.h"
@@ -416,17 +414,6 @@
       "sec-ch-ua-model",
   };
   const std::string lower_name = base::ToLowerASCII(name);
-
-  if (base::FeatureList::IsEnabled(features::kOutOfBlinkCors)) {
-    // Here we temporarily define extra CORS safelisted header names. This is
-    // a very short term fix in order to make the change mergeable.
-    // TODO(yhirano): Remove this definition as soon as possible.
-    if (lower_name == "x-googapps-allowed-domains" ||
-        lower_name == "youtube-restrict") {
-      return true;
-    }
-  }
-
   if (std::find(std::begin(safe_names), std::end(safe_names), lower_name) ==
       std::end(safe_names))
     return false;
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index 80f1f1a5..e80d0db 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -34,6 +34,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
@@ -587,10 +588,11 @@
     network_service_ptr->SetClient(std::move(network_service_client_ptr),
                                    network::mojom::NetworkServiceParams::New());
 
-    network::mojom::NetworkContextClientPtr network_context_client_ptr;
+    mojo::PendingRemote<network::mojom::NetworkContextClient>
+        network_context_client_remote;
     network_context_client_ = std::make_unique<TestNetworkContextClient>(
-        mojo::MakeRequest(&network_context_client_ptr));
-    network_context_->SetClient(std::move(network_context_client_ptr));
+        network_context_client_remote.InitWithNewPipeAndPassReceiver());
+    network_context_->SetClient(std::move(network_context_client_remote));
 
     mojom::URLLoaderFactoryParamsPtr params =
         mojom::URLLoaderFactoryParams::New();
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 953e518..873bce4 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -718,7 +718,7 @@
 // storage (e.g. cookies and cache).
 interface NetworkContext {
   // Sets a client for this network context.
-  SetClient(NetworkContextClient client);
+  SetClient(pending_remote<NetworkContextClient> client);
 
   // Creates a new URLLoaderFactory with the given |params|.
   CreateURLLoaderFactory(URLLoaderFactory& url_loader_factory,
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index c2c73ec..34a8050 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -40,7 +40,8 @@
   TestNetworkContext() = default;
   ~TestNetworkContext() override = default;
 
-  void SetClient(mojom::NetworkContextClientPtr client) override {}
+  void SetClient(
+      mojo::PendingRemote<mojom::NetworkContextClient> client) override {}
   void CreateURLLoaderFactory(
       mojom::URLLoaderFactoryRequest request,
       mojom::URLLoaderFactoryParamsPtr params) override {}
diff --git a/services/network/test/test_network_context_client.cc b/services/network/test/test_network_context_client.cc
index fffe1dc..011d717 100644
--- a/services/network/test/test_network_context_client.cc
+++ b/services/network/test/test_network_context_client.cc
@@ -13,11 +13,11 @@
 
 namespace network {
 
-TestNetworkContextClient::TestNetworkContextClient() : binding_(nullptr) {}
+TestNetworkContextClient::TestNetworkContextClient() : receiver_(nullptr) {}
 
 TestNetworkContextClient::TestNetworkContextClient(
-    mojom::NetworkContextClientRequest request)
-    : binding_(this, std::move(request)) {}
+    mojo::PendingReceiver<mojom::NetworkContextClient> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 TestNetworkContextClient::~TestNetworkContextClient() {}
 
diff --git a/services/network/test/test_network_context_client.h b/services/network/test/test_network_context_client.h
index 716ad15..8f7fd0a 100644
--- a/services/network/test/test_network_context_client.h
+++ b/services/network/test/test_network_context_client.h
@@ -6,8 +6,8 @@
 #define SERVICES_NETWORK_TEST_TEST_NETWORK_CONTEXT_CLIENT_H_
 
 #include "build/build_config.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 
 namespace network {
@@ -17,7 +17,8 @@
 class TestNetworkContextClient : public network::mojom::NetworkContextClient {
  public:
   TestNetworkContextClient();
-  explicit TestNetworkContextClient(mojom::NetworkContextClientRequest request);
+  explicit TestNetworkContextClient(
+      mojo::PendingReceiver<mojom::NetworkContextClient> receiver);
   ~TestNetworkContextClient() override;
 
   void set_upload_files_invalid(bool upload_files_invalid) {
@@ -95,7 +96,7 @@
 #endif
 
  private:
-  mojo::Binding<mojom::NetworkContextClient> binding_;
+  mojo::Receiver<mojom::NetworkContextClient> receiver_;
   bool upload_files_invalid_ = false;
   bool ignore_last_upload_file_ = false;
 };
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 1cd2e7c..9cf3a41 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -1365,6 +1365,390 @@
       }
     ]
   },
+  "Android WebView P (dbg)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "android_webview_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "android_webview_unittests"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "system_webview_shell_layout_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "system_webview_shell_layout_test_apk"
+      },
+      {
+        "args": [
+          "--disable-field-trial-config",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "system_webview_shell_layout_test_apk_no_field_trial"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "system_webview_shell_layout_test_apk_no_field_trial",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "system_webview_shell_layout_test_apk"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_cts_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/android_webview/tools/cts_archive",
+              "location": "android_webview/tools/cts_archive",
+              "revision": "version:1.7"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 3
+        },
+        "test": "webview_cts_tests"
+      },
+      {
+        "args": [
+          "--disable-field-trial-config",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_cts_tests_no_field_trial"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "webview_cts_tests_no_field_trial",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/android_webview/tools/cts_archive",
+              "location": "android_webview/tools/cts_archive",
+              "revision": "version:1.7"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 3
+        },
+        "test": "webview_cts_tests"
+      },
+      {
+        "args": [
+          "--disable-field-trials",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 12
+        },
+        "test": "webview_instrumentation_test_apk"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_ui_test_app_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "webview_ui_test_app_test_apk"
+      },
+      {
+        "args": [
+          "--disable-field-trial-config",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_ui_test_app_test_apk_no_field_trial"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "webview_ui_test_app_test_apk_no_field_trial",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "webview_ui_test_app_test_apk"
+      }
+    ]
+  },
   "Android arm Builder (dbg)": {
     "additional_compile_targets": [
       "dump_syms",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 29d0bca5..4b9b9c8 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -5790,6 +5790,27 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
+        "name": "headless_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
+        "args": [
+          "--ozone-platform=x11"
+        ],
+        "experiment_percentage": 100,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "x11_content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/filters/chromeos.browser_tests.filter b/testing/buildbot/filters/chromeos.browser_tests.filter
index 7f9aa2e..2de8ead 100644
--- a/testing/buildbot/filters/chromeos.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.browser_tests.filter
@@ -20,9 +20,6 @@
 # TODO(crbug.com/977743): Enable this.
 -ManagementApiKioskTest.ManagementApi
 
-# TODO(crbug.com/990844): Enable this.
--MergeSessionTest.XHRNotThrottled/1
-
 # TODO(crbug.com/985390): Enable this.
 -OSSettingsPeoplePageAccountManagerTest.AllJsTests
 
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 0f6b5f2..58450e72 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -546,6 +546,14 @@
       },
     },
   },
+  'pie_fleet': {
+    'swarming': {
+      'dimensions': {
+        'device_os': 'PQ3A.190801.002',
+        'device_os_flavor': 'google',
+      },
+    },
+  },
   'shamu': {
     # Nexus 6
     'swarming': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 00063461..dd57c2f 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4409,10 +4409,18 @@
       'services_unittests': {},
       'ozone_unittests': {},
       'ozone_x11_unittests': {},
-      'content_unittests': {
+      'headless_content_unittests': {
         'args': [
           '--ozone-platform=headless',
         ],
+        'test': 'content_unittests',
+      },
+      'x11_content_unittests': {
+        'experiment_percentage': 100,
+        'args': [
+          '--ozone-platform=x11',
+        ],
+        'test': 'content_unittests',
       },
     },
 
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 7859a749..3ba97fe 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -259,6 +259,17 @@
         'use_swarming': True,
         'os_type': 'android',
       },
+      'Android WebView P (dbg)': {
+        'mixins': [
+          'pie_fleet',
+          'walleye',
+        ],
+        'test_suites': {
+          'gtest_tests': 'webview_bot_all_gtests',
+        },
+        'use_swarming': True,
+        'os_type': 'android',
+      },
       'Android arm Builder (dbg)': {
         'additional_compile_targets': [
           'dump_syms',
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 6632c171..2bcaf7c 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -270,9 +270,10 @@
 const base::Feature kForbidSyncXHRInPageDismissal{
     "ForbidSyncXHRInPageDismissal", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Forces the redirect mode for prefetches to kManual. See crbug.com/988956.
-const base::Feature kPrefetchRedirectError{"PrefetchRedirectError",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
+// Prefetch request properties are updated to be privacy-preserving. See
+// crbug.com/988956.
+const base::Feature kPrefetchPrivacyChanges{"PrefetchPrivacyChanges",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
 const char kMixedContentAutoupgradeModeParamName[] = "mode";
 const char kMixedContentAutoupgradeModeBlockable[] = "blockable";
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 3293392..790ec12 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -159,10 +159,9 @@
     "platform/modules/peerconnection/audio_codec_factory.h",
     "platform/modules/peerconnection/rtc_event_log_output_sink.h",
     "platform/modules/peerconnection/rtc_event_log_output_sink_proxy_util.h",
-    "platform/modules/peerconnection/rtc_video_decoder_factory.h",
-    "platform/modules/peerconnection/rtc_video_encoder_factory.h",
+    "platform/modules/peerconnection/rtc_video_decoder_factory_util.h",
+    "platform/modules/peerconnection/rtc_video_encoder_factory_util.h",
     "platform/modules/peerconnection/two_keys_adapter_map.h",
-    "platform/modules/peerconnection/web_rtc_video_encoder_factory.h",
     "platform/modules/peerconnection/webrtc_audio_sink.h",
     "platform/modules/peerconnection/webrtc_util.h",
     "platform/modules/peerconnection/webrtc_video_track_source.h",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 3259d42..6b06668a 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -73,7 +73,7 @@
 BLINK_COMMON_EXPORT extern const base::Feature kNativeFileSystemAPI;
 BLINK_COMMON_EXPORT extern const base::Feature kFileHandlingAPI;
 BLINK_COMMON_EXPORT extern const base::Feature kForbidSyncXHRInPageDismissal;
-BLINK_COMMON_EXPORT extern const base::Feature kPrefetchRedirectError;
+BLINK_COMMON_EXPORT extern const base::Feature kPrefetchPrivacyChanges;
 
 BLINK_COMMON_EXPORT extern const char kMixedContentAutoupgradeModeParamName[];
 BLINK_COMMON_EXPORT extern const char kMixedContentAutoupgradeModeBlockable[];
diff --git a/third_party/blink/public/mojom/content_index/content_index.mojom b/third_party/blink/public/mojom/content_index/content_index.mojom
index 0195f91..23d7baa 100644
--- a/third_party/blink/public/mojom/content_index/content_index.mojom
+++ b/third_party/blink/public/mojom/content_index/content_index.mojom
@@ -19,6 +19,9 @@
 
   // An IO error occured while interacting with the database.
   STORAGE_ERROR,
+
+  // Service worker is missing or not activated yet.
+  NO_SERVICE_WORKER,
 };
 
 // These values are persisted and recorded, do not change or create gaps.
diff --git a/third_party/blink/public/mojom/service_worker/service_worker.mojom b/third_party/blink/public/mojom/service_worker/service_worker.mojom
index feca3aa..0e6fe9f 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker.mojom
@@ -250,16 +250,19 @@
                             mojo_base.mojom.TimeDelta timeout)
       => (ServiceWorkerEventStatus status);
   DispatchAbortPaymentEvent(
-      payments.mojom.PaymentHandlerResponseCallback result_of_abort_payment)
-          => (ServiceWorkerEventStatus status);
+      pending_remote<payments.mojom.PaymentHandlerResponseCallback>
+          result_of_abort_payment)
+      => (ServiceWorkerEventStatus status);
   DispatchCanMakePaymentEvent(
       payments.mojom.CanMakePaymentEventData event_data,
-      payments.mojom.PaymentHandlerResponseCallback result_of_can_make_payment)
-          => (ServiceWorkerEventStatus status);
+      pending_remote<payments.mojom.PaymentHandlerResponseCallback>
+          result_of_can_make_payment)
+      => (ServiceWorkerEventStatus status);
   DispatchPaymentRequestEvent(
       payments.mojom.PaymentRequestEventData request_data,
-      payments.mojom.PaymentHandlerResponseCallback response_callback)
-          => (ServiceWorkerEventStatus status);
+      pending_remote<payments.mojom.PaymentHandlerResponseCallback>
+          response_callback)
+      => (ServiceWorkerEventStatus status);
   DispatchExtendableMessageEvent(ExtendableMessageEvent event)
       => (ServiceWorkerEventStatus status);
   // Ref: https://github.com/rknoll/content-index
diff --git a/third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h b/third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory_util.h
similarity index 64%
copy from third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h
copy to third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory_util.h
index 0881d45..de64ea4d 100644
--- a/third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h
+++ b/third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory_util.h
@@ -2,29 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEB_RTC_VIDEO_ENCODER_FACTORY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEB_RTC_VIDEO_ENCODER_FACTORY_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_UTIL_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_UTIL_H_
 
 #include <memory>
 
-#include "media/base/video_codecs.h"
 #include "third_party/blink/public/platform/web_common.h"
 
-namespace webrtc {
-class VideoEncoder;
-}
-
 namespace media {
 class GpuVideoAcceleratorFactories;
 }
 
+namespace webrtc {
+class VideoDecoderFactory;
+}
+
 namespace blink {
 
 // TODO(crbug.com/787254): Remove this API when its clients are Onion souped.
-BLINK_PLATFORM_EXPORT std::unique_ptr<webrtc::VideoEncoder>
-CreateRTCVideoEncoder(media::VideoCodecProfile profile,
-                      media::GpuVideoAcceleratorFactories* gpu_factories);
+BLINK_PLATFORM_EXPORT std::unique_ptr<webrtc::VideoDecoderFactory>
+CreateRTCVideoDecoderFactory(
+    media::GpuVideoAcceleratorFactories* gpu_factories);
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEB_RTC_VIDEO_ENCODER_FACTORY_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_UTIL_H_
diff --git a/third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h b/third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory_util.h
similarity index 64%
rename from third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h
rename to third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory_util.h
index 0881d45..45bafd3f 100644
--- a/third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h
+++ b/third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory_util.h
@@ -2,29 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEB_RTC_VIDEO_ENCODER_FACTORY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEB_RTC_VIDEO_ENCODER_FACTORY_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_UTIL_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_UTIL_H_
 
 #include <memory>
 
-#include "media/base/video_codecs.h"
 #include "third_party/blink/public/platform/web_common.h"
 
-namespace webrtc {
-class VideoEncoder;
-}
-
 namespace media {
 class GpuVideoAcceleratorFactories;
 }
 
+namespace webrtc {
+class VideoEncoderFactory;
+}
+
 namespace blink {
 
 // TODO(crbug.com/787254): Remove this API when its clients are Onion souped.
-BLINK_PLATFORM_EXPORT std::unique_ptr<webrtc::VideoEncoder>
-CreateRTCVideoEncoder(media::VideoCodecProfile profile,
-                      media::GpuVideoAcceleratorFactories* gpu_factories);
+BLINK_PLATFORM_EXPORT std::unique_ptr<webrtc::VideoEncoderFactory>
+CreateRTCVideoEncoderFactory(
+    media::GpuVideoAcceleratorFactories* gpu_factories);
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEB_RTC_VIDEO_ENCODER_FACTORY_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_UTIL_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
index 91d6d78bb..fe15e880 100644
--- a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
+++ b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
@@ -55,7 +55,7 @@
   ScriptValue Call(ScriptValue value) override {
     String string_id;
     if (!value.ToString(string_id)) {
-      V8ThrowException::ThrowTypeError(value.GetIsolate(),
+      V8ThrowException::ThrowTypeError(GetScriptState()->GetIsolate(),
                                        "countUse requires a string argument");
       return ScriptValue();
     }
@@ -68,7 +68,7 @@
                      });
 
     if (it == std::end(web_feature_id_name_lookup_table)) {
-      V8ThrowException::ThrowTypeError(value.GetIsolate(),
+      V8ThrowException::ThrowTypeError(GetScriptState()->GetIsolate(),
                                        "unknown use counter");
       return ScriptValue();
     }
diff --git a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
index 4bd4625..9182773 100644
--- a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
+++ b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
@@ -60,12 +60,12 @@
   }
 
   // Isolated world CSPs don't support these directives: "sandbox",
-  // "treat-as-public-address", "trusted-types" and "upgrade-insecure-requests".
+  // "trusted-types" and "upgrade-insecure-requests".
+  //
   // These directives depend on ExecutionContext for their implementation and
   // since isolated worlds don't have their own ExecutionContext, these are not
   // supported.
   void SetSandboxFlags(SandboxFlags) override {}
-  void SetAddressSpace(network::mojom::IPAddressSpace) override {}
   void SetRequireTrustedTypes() override {}
   void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override {}
 
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise.h b/third_party/blink/renderer/bindings/core/v8/script_promise.h
index c840b5dc..555de6a 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise.h
@@ -82,7 +82,7 @@
 
   v8::Local<v8::Value> V8Value() const { return promise_.V8Value(); }
 
-  v8::Isolate* GetIsolate() const { return promise_.GetIsolate(); }
+  v8::Isolate* GetIsolate() const { return script_state_->GetIsolate(); }
 
   bool IsEmpty() const { return promise_.IsEmpty(); }
 
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
index 6b54dd83..58e9887 100644
--- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -233,40 +233,42 @@
 using CryptoKeyPair = std::pair<CryptoKey*, CryptoKey*>;
 
 template <typename T>
-T ConvertCryptoResult(const ScriptValue&);
+T ConvertCryptoResult(v8::Isolate*, const ScriptValue&);
 template <>
-CryptoKey* ConvertCryptoResult<CryptoKey*>(const ScriptValue& value) {
-  return V8CryptoKey::ToImplWithTypeCheck(value.GetIsolate(), value.V8Value());
+CryptoKey* ConvertCryptoResult<CryptoKey*>(v8::Isolate* isolate,
+                                           const ScriptValue& value) {
+  return V8CryptoKey::ToImplWithTypeCheck(isolate, value.V8Value());
 }
 template <>
-CryptoKeyPair ConvertCryptoResult<CryptoKeyPair>(const ScriptValue& value) {
+CryptoKeyPair ConvertCryptoResult<CryptoKeyPair>(v8::Isolate* isolate,
+                                                 const ScriptValue& value) {
   NonThrowableExceptionState exception_state;
-  Dictionary dictionary(value.GetIsolate(), value.V8Value(), exception_state);
+  Dictionary dictionary(isolate, value.V8Value(), exception_state);
   v8::Local<v8::Value> private_key, public_key;
   EXPECT_TRUE(dictionary.Get("publicKey", public_key));
   EXPECT_TRUE(dictionary.Get("privateKey", private_key));
-  return std::make_pair(
-      V8CryptoKey::ToImplWithTypeCheck(value.GetIsolate(), public_key),
-      V8CryptoKey::ToImplWithTypeCheck(value.GetIsolate(), private_key));
+  return std::make_pair(V8CryptoKey::ToImplWithTypeCheck(isolate, public_key),
+                        V8CryptoKey::ToImplWithTypeCheck(isolate, private_key));
 }
 template <>
-DOMException* ConvertCryptoResult<DOMException*>(const ScriptValue& value) {
-  return V8DOMException::ToImplWithTypeCheck(value.GetIsolate(),
-                                             value.V8Value());
+DOMException* ConvertCryptoResult<DOMException*>(v8::Isolate* isolate,
+                                                 const ScriptValue& value) {
+  return V8DOMException::ToImplWithTypeCheck(isolate, value.V8Value());
 }
 template <>
 WebVector<unsigned char> ConvertCryptoResult<WebVector<unsigned char>>(
+    v8::Isolate* isolate,
     const ScriptValue& value) {
   WebVector<unsigned char> vector;
-  if (DOMArrayBuffer* buffer = V8ArrayBuffer::ToImplWithTypeCheck(
-          value.GetIsolate(), value.V8Value())) {
+  if (DOMArrayBuffer* buffer =
+          V8ArrayBuffer::ToImplWithTypeCheck(isolate, value.V8Value())) {
     vector.Assign(reinterpret_cast<const unsigned char*>(buffer->Data()),
                   buffer->ByteLength());
   }
   return vector;
 }
 template <>
-bool ConvertCryptoResult<bool>(const ScriptValue& value) {
+bool ConvertCryptoResult<bool>(v8::Isolate*, const ScriptValue& value) {
   return value.V8Value()->IsTrue();
 }
 
@@ -279,7 +281,8 @@
 
  private:
   ScriptValue Call(ScriptValue value) final {
-    function_.Run(ConvertCryptoResult<T>(value));
+    function_.Run(
+        ConvertCryptoResult<T>(GetScriptState()->GetIsolate(), value));
     return ScriptValue::From(GetScriptState(), ToV8UndefinedGenerator());
   }
 
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index b2625dd0..95075238 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -615,6 +615,7 @@
     "font_face_cache_test.cc",
     "invalidation/invalidation_set_test.cc",
     "invalidation/pending_invalidations_test.cc",
+    "invalidation/style_invalidator_test.cc",
     "media_query_evaluator_test.cc",
     "media_query_list_test.cc",
     "media_query_matcher_test.cc",
diff --git a/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc b/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
index 7b78f500..ef7d851 100644
--- a/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
+++ b/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/html/html_slot_element.h"
 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
@@ -317,9 +318,12 @@
   //   could apply to the descendants.
   // * there are invalidation sets attached to descendants then we need to
   //   clear the flags on the nodes, whether we use the sets or not.
-  if ((!WholeSubtreeInvalid() && HasInvalidationSets()) ||
+  if ((!WholeSubtreeInvalid() && HasInvalidationSets() &&
+       element.GetComputedStyle()) ||
       element.ChildNeedsStyleInvalidation()) {
     InvalidateChildren(element);
+  } else {
+    ClearPendingNthSiblingInvalidationSets();
   }
 
   element.ClearChildNeedsStyleInvalidation();
diff --git a/third_party/blink/renderer/core/css/invalidation/style_invalidator.h b/third_party/blink/renderer/core/css/invalidation/style_invalidator.h
index 2d6823a3..ffc97ebe 100644
--- a/third_party/blink/renderer/core/css/invalidation/style_invalidator.h
+++ b/third_party/blink/renderer/core/css/invalidation/style_invalidator.h
@@ -81,8 +81,9 @@
   void PushNthSiblingInvalidationSets(SiblingData& sibling_data) {
     for (const auto* invalidation_set : pending_nth_sets_)
       sibling_data.PushInvalidationSet(*invalidation_set);
-    pending_nth_sets_.resize(0);
+    ClearPendingNthSiblingInvalidationSets();
   }
+  void ClearPendingNthSiblingInvalidationSets() { pending_nth_sets_.resize(0); }
 
   PendingInvalidationMap& pending_invalidation_map_;
   using DescendantInvalidationSets = Vector<const InvalidationSet*, 16>;
diff --git a/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc b/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc
new file mode 100644
index 0000000..7940afd
--- /dev/null
+++ b/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc
@@ -0,0 +1,96 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/invalidation/style_invalidator.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+
+namespace blink {
+
+class StyleInvalidatorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    dummy_page_holder_ = std::make_unique<DummyPageHolder>(IntSize(800, 600));
+  }
+
+  Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
+
+ private:
+  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+};
+
+TEST_F(StyleInvalidatorTest, SkipDisplayNone) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <div id="root">
+      <div style="display:none">
+        <div class="a"></div>
+        <div class="a"></div>
+      </div>
+    </div>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases(
+      DocumentLifecycle::LifecycleUpdateReason::kTest);
+
+  PendingInvalidations pending;
+  {
+    InvalidationLists lists;
+    scoped_refptr<InvalidationSet> set = DescendantInvalidationSet::Create();
+    set->AddClass("a");
+    lists.descendants.push_back(set);
+    pending.ScheduleInvalidationSetsForNode(
+        lists, *GetDocument().getElementById("root"));
+  }
+
+  StyleInvalidator invalidator(pending.GetPendingInvalidationMap());
+  invalidator.Invalidate(GetDocument(), GetDocument().body());
+
+  EXPECT_FALSE(GetDocument().NeedsLayoutTreeUpdate());
+}
+
+TEST_F(StyleInvalidatorTest, SkipDisplayNoneClearPendingNth) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <div id="none" style="display:none">
+      <div class="a"></div>
+      <div class="a"></div>
+    </div>
+    <div id="descendant">
+      <div class="a"></div>
+    </div>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases(
+      DocumentLifecycle::LifecycleUpdateReason::kTest);
+
+  PendingInvalidations pending;
+  {
+    InvalidationLists lists;
+    scoped_refptr<InvalidationSet> set = NthSiblingInvalidationSet::Create();
+    set->AddClass("a");
+    lists.siblings.push_back(set);
+    pending.ScheduleInvalidationSetsForNode(
+        lists, *GetDocument().getElementById("none"));
+  }
+  {
+    InvalidationLists lists;
+    scoped_refptr<InvalidationSet> set = DescendantInvalidationSet::Create();
+    set->AddClass("a");
+    lists.descendants.push_back(set);
+    pending.ScheduleInvalidationSetsForNode(
+        lists, *GetDocument().getElementById("descendant"));
+  }
+
+  StyleInvalidator invalidator(pending.GetPendingInvalidationMap());
+  invalidator.Invalidate(GetDocument(), GetDocument().body());
+
+  EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
+  EXPECT_FALSE(GetDocument().getElementById("none")->ChildNeedsStyleRecalc());
+  EXPECT_TRUE(
+      GetDocument().getElementById("descendant")->ChildNeedsStyleRecalc());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index 40d1d27..3aad34e99 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -566,6 +566,22 @@
     AdjustStyleForFirstLetter(style);
   }
 
+  if (element && RuntimeEnabledFeatures::DisplayLockingEnabled() &&
+      element->hasAttribute(html_names::kRendersubtreeAttr)) {
+    // The element has the rendersubtree attr, so we should add style and
+    // layout containment. If the attribute contains "invisible" we should
+    // also add size containment.
+    Containment contain = kContainsStyle | kContainsLayout;
+    SpaceSplitString tokens(
+        element->getAttribute(html_names::kRendersubtreeAttr).LowerASCII());
+    if (style.ContainsSize() || tokens.Contains("invisible")) {
+      contain |= kContainsSize;
+    }
+    if (style.ContainsPaint())
+      contain |= kContainsPaint;
+    style.SetContain(contain);
+  }
+
   if (style.IsColorInternalText()) {
     style.SetColor(
         LayoutTheme::GetTheme().RootElementColor(style.UsedColorScheme()));
diff --git a/third_party/blink/renderer/core/dom/decoded_data_document_parser.cc b/third_party/blink/renderer/core/dom/decoded_data_document_parser.cc
index e00c366..3dcebd4 100644
--- a/third_party/blink/renderer/core/dom/decoded_data_document_parser.cc
+++ b/third_party/blink/renderer/core/dom/decoded_data_document_parser.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/document_encoding_data.h"
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 25c79ca..6ec73933 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -156,6 +156,7 @@
 #include "third_party/blink/renderer/core/feature_policy/document_policy.h"
 #include "third_party/blink/renderer/core/feature_policy/feature_policy_parser.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h"
 #include "third_party/blink/renderer/core/frame/dom_timer.h"
 #include "third_party/blink/renderer/core/frame/dom_visual_viewport.h"
 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
@@ -8113,6 +8114,7 @@
   visitor->Trace(policy_);
   visitor->Trace(slot_assignment_engine_);
   visitor->Trace(viewport_data_);
+  visitor->Trace(navigation_initiator_);
   visitor->Trace(lazy_load_image_observer_);
   visitor->Trace(isolated_world_csp_map_);
   visitor->Trace(find_in_page_root_);
@@ -8215,6 +8217,14 @@
       mojom::FeaturePolicyFeature::kFocusWithoutUserActivation);
 }
 
+NavigationInitiatorImpl& Document::NavigationInitiator() {
+  if (!navigation_initiator_) {
+    navigation_initiator_ =
+        MakeGarbageCollected<NavigationInitiatorImpl>(*this);
+  }
+  return *navigation_initiator_;
+}
+
 LazyLoadImageObserver& Document::EnsureLazyLoadImageObserver() {
   if (!lazy_load_image_observer_)
     lazy_load_image_observer_ = MakeGarbageCollected<LazyLoadImageObserver>();
@@ -8362,37 +8372,6 @@
   isolated_world_csp_map_->erase(world_id);
 }
 
-void Document::SendViolationReport(
-    mojom::blink::CSPViolationParamsPtr violation_params) {
-  std::unique_ptr<SourceLocation> source_location =
-      std::make_unique<SourceLocation>(
-          violation_params->source_location->url,
-          violation_params->source_location->line_number,
-          violation_params->source_location->column_number, nullptr);
-
-  Vector<String> report_endpoints;
-  for (const WebString& end_point : violation_params->report_endpoints)
-    report_endpoints.push_back(end_point);
-
-  AddConsoleMessage(ConsoleMessage::Create(
-      mojom::ConsoleMessageSource::kSecurity,
-      mojom::ConsoleMessageLevel::kError, violation_params->console_message));
-  GetContentSecurityPolicy()->ReportViolation(
-      violation_params->directive,
-      ContentSecurityPolicy::GetDirectiveType(
-          violation_params->effective_directive),
-      violation_params->console_message, KURL(violation_params->blocked_url),
-      report_endpoints, violation_params->use_reporting_api,
-      violation_params->header,
-      static_cast<ContentSecurityPolicyHeaderType>(
-          violation_params->disposition),
-      ContentSecurityPolicy::ViolationType::kURLViolation,
-      std::move(source_location), nullptr /* LocalFrame */,
-      violation_params->after_redirect ? RedirectStatus::kFollowedRedirect
-                                       : RedirectStatus::kNoRedirect,
-      nullptr /* Element */);
-}
-
 bool Document::ChildrenCanHaveStyle() const {
   if (LayoutObject* view = GetLayoutView())
     return view->CanHaveChildren();
@@ -8522,10 +8501,6 @@
     loader->GetUseCounterHelper().ClearMeasurementForTesting(feature);
 }
 
-void Document::Dispose() {
-  navigation_initiator_receivers_.Clear();
-}
-
 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 1d3f649..0005f7f 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -35,9 +35,7 @@
 #include <utility>
 
 #include "base/memory/scoped_refptr.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
-#include "third_party/blink/public/mojom/frame/navigation_initiator.mojom-blink.h"
 #include "third_party/blink/public/platform/web_focus_type.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/core/accessibility/axid.h"
@@ -153,6 +151,7 @@
 class Location;
 class MediaQueryListListener;
 class MediaQueryMatcher;
+class NavigationInitiatorImpl;
 class NodeIterator;
 class NthIndexCache;
 class OriginAccessEntry;
@@ -258,11 +257,9 @@
                              public ExecutionContext,
                              public DocumentShutdownNotifier,
                              public SynchronousMutationNotifier,
-                             public Supplementable<Document>,
-                             public mojom::blink::NavigationInitiator {
+                             public Supplementable<Document> {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(Document);
-  USING_PRE_FINALIZER(Document, Dispose);
 
  public:
   // Factory for web-exposed Document constructor. The argument document must be
@@ -1499,12 +1496,7 @@
   bool IsLazyLoadPolicyEnforced() const;
   bool IsFocusAllowed() const;
 
-  void SendViolationReport(
-      mojom::blink::CSPViolationParamsPtr violation_params) override;
-  void BindNavigationInitiatorReceiver(
-      mojo::PendingReceiver<mojom::blink::NavigationInitiator> receiver) {
-    navigation_initiator_receivers_.Add(this, std::move(receiver));
-  }
+  NavigationInitiatorImpl& NavigationInitiator();
 
   LazyLoadImageObserver& EnsureLazyLoadImageObserver();
 
@@ -1763,8 +1755,6 @@
                                    Element* new_focused_element);
   void DisplayNoneChangedForFrame();
 
-  void Dispose();
-
   DocumentLifecycle lifecycle_;
 
   bool evaluate_media_queries_on_style_recalc_;
@@ -2070,12 +2060,7 @@
   // opposed to a PluginView.
   bool is_for_external_handler_ = false;
 
-  // A list of all the navigation_initiator receivers owned by this document.
-  // Used to report CSP violations that result from CSP blocking
-  // navigation requests that were initiated by this document.
-  mojo::ReceiverSet<mojom::blink::NavigationInitiator>
-      navigation_initiator_receivers_;
-
+  Member<NavigationInitiatorImpl> navigation_initiator_;
   Member<LazyLoadImageObserver> lazy_load_image_observer_;
 
   // Tracks which features have already been potentially violated in this
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 35996ad4..fc883e77 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2116,23 +2116,24 @@
       GetElementData()->presentation_attribute_style_is_dirty_ = true;
       SetNeedsStyleRecalc(kLocalStyleChange,
                           StyleChangeReasonForTracing::FromAttribute(name));
-
-      if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
-          name == html_names::kRendersubtreeAttr &&
-          params.old_value != params.new_value) {
-        SpaceSplitString tokens(params.new_value.LowerASCII());
-        const bool should_be_activatable = tokens.Contains("activatable");
-        EnsureDisplayLockContext().SetActivatable(should_be_activatable);
-        const bool should_be_invisible = tokens.Contains("invisible");
-        if (should_be_invisible) {
-          if (!GetDisplayLockContext()->IsLocked())
-            GetDisplayLockContext()->StartAcquire();
-        } else {
-          // Getting unlocked.
-          if (GetDisplayLockContext()->IsLocked())
-            GetDisplayLockContext()->StartCommit();
-        }
+    } else if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
+               name == html_names::kRendersubtreeAttr &&
+               params.old_value != params.new_value) {
+      SetNeedsStyleRecalc(kLocalStyleChange,
+                          StyleChangeReasonForTracing::FromAttribute(name));
+      SpaceSplitString tokens(params.new_value.LowerASCII());
+      const bool should_be_activatable = tokens.Contains("activatable");
+      EnsureDisplayLockContext().SetActivatable(should_be_activatable);
+      const bool should_be_invisible = tokens.Contains("invisible");
+      if (should_be_invisible) {
+        if (!GetDisplayLockContext()->IsLocked())
+          GetDisplayLockContext()->StartAcquire();
+      } else {
+        // Getting unlocked.
+        if (GetDisplayLockContext()->IsLocked())
+          GetDisplayLockContext()->StartCommit();
       }
+
     } else if (RuntimeEnabledFeatures::InvisibleDOMEnabled() &&
                name == html_names::kInvisibleAttr &&
                params.old_value != params.new_value) {
diff --git a/third_party/blink/renderer/core/dom/events/custom_event.cc b/third_party/blink/renderer/core/dom/events/custom_event.cc
index 2c4de684..be37dfd3 100644
--- a/third_party/blink/renderer/core/dom/events/custom_event.cc
+++ b/third_party/blink/renderer/core/dom/events/custom_event.cc
@@ -36,7 +36,7 @@
                          const CustomEventInit* initializer)
     : Event(type, initializer) {
   if (initializer->hasDetail()) {
-    detail_.SetAcrossWorld(initializer->detail().GetIsolate(),
+    detail_.SetAcrossWorld(script_state->GetIsolate(),
                            initializer->detail().V8Value());
   }
 }
@@ -50,7 +50,7 @@
                                   const ScriptValue& script_value) {
   initEvent(type, bubbles, cancelable);
   if (!IsBeingDispatched() && !script_value.IsEmpty())
-    detail_.SetAcrossWorld(script_value.GetIsolate(), script_value.V8Value());
+    detail_.SetAcrossWorld(script_state->GetIsolate(), script_value.V8Value());
 }
 
 ScriptValue CustomEvent::detail(ScriptState* script_state) const {
diff --git a/third_party/blink/renderer/core/events/error_event.cc b/third_party/blink/renderer/core/events/error_event.cc
index 655a599f..2a9f4bc6 100644
--- a/third_party/blink/renderer/core/events/error_event.cc
+++ b/third_party/blink/renderer/core/events/error_event.cc
@@ -65,8 +65,7 @@
       initializer->hasLineno() ? initializer->lineno() : 0,
       initializer->hasColno() ? initializer->colno() : 0, nullptr);
   if (initializer->hasError()) {
-    error_.Set(initializer->error().GetIsolate(),
-               initializer->error().V8Value());
+    error_.Set(script_state->GetIsolate(), initializer->error().V8Value());
   }
 }
 
diff --git a/third_party/blink/renderer/core/events/pop_state_event.cc b/third_party/blink/renderer/core/events/pop_state_event.cc
index c7190b0..1db86c7 100644
--- a/third_party/blink/renderer/core/events/pop_state_event.cc
+++ b/third_party/blink/renderer/core/events/pop_state_event.cc
@@ -42,8 +42,7 @@
     : Event(type, initializer), history_(nullptr) {
   if (initializer->hasState()) {
     world_ = WrapRefCounted(&script_state->World());
-    state_.Set(initializer->state().GetIsolate(),
-               initializer->state().V8Value());
+    state_.Set(script_state->GetIsolate(), initializer->state().V8Value());
   }
 }
 
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.cc b/third_party/blink/renderer/core/events/promise_rejection_event.cc
index 1c974474..d74b3c62 100644
--- a/third_party/blink/renderer/core/events/promise_rejection_event.cc
+++ b/third_party/blink/renderer/core/events/promise_rejection_event.cc
@@ -10,16 +10,15 @@
 namespace blink {
 
 PromiseRejectionEvent::PromiseRejectionEvent(
-    ScriptState* state,
+    ScriptState* script_state,
     const AtomicString& type,
     const PromiseRejectionEventInit* initializer)
-    : Event(type, initializer), world_(&state->World()) {
+    : Event(type, initializer), world_(&script_state->World()) {
   DCHECK(initializer->hasPromise());
   promise_.Set(initializer->promise().GetIsolate(),
                initializer->promise().V8Value());
   if (initializer->hasReason()) {
-    reason_.Set(initializer->reason().GetIsolate(),
-                initializer->reason().V8Value());
+    reason_.Set(script_state->GetIsolate(), initializer->reason().V8Value());
   }
 }
 
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.h b/third_party/blink/renderer/core/events/promise_rejection_event.h
index 78786ef7..7f3bb24 100644
--- a/third_party/blink/renderer/core/events/promise_rejection_event.h
+++ b/third_party/blink/renderer/core/events/promise_rejection_event.h
@@ -21,10 +21,10 @@
 
  public:
   static PromiseRejectionEvent* Create(
-      ScriptState* state,
+      ScriptState* script_state,
       const AtomicString& type,
       const PromiseRejectionEventInit* initializer) {
-    return MakeGarbageCollected<PromiseRejectionEvent>(state, type,
+    return MakeGarbageCollected<PromiseRejectionEvent>(script_state, type,
                                                        initializer);
   }
 
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index de2265ae..c26dcf9 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -34,6 +34,8 @@
 #include <utility>
 
 #include "base/time/time.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/common/frame/user_activation_update_type.h"
@@ -165,9 +167,10 @@
     mojo::ScopedMessagePipeHandle document_interface_broker_handle)
     : web_frame_(frame) {
   DCHECK(document_interface_broker_handle.is_valid());
-  document_interface_broker_.Bind(mojom::blink::DocumentInterfaceBrokerPtrInfo(
-      std::move(document_interface_broker_handle),
-      mojom::blink::DocumentInterfaceBroker::Version_));
+  document_interface_broker_.Bind(
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>(
+          std::move(document_interface_broker_handle),
+          mojom::blink::DocumentInterfaceBroker::Version_));
 }
 
 LocalFrameClientImpl::~LocalFrameClientImpl() = default;
@@ -441,16 +444,17 @@
   }
 
   if (web_frame_->Client()) {
-    mojom::blink::DocumentInterfaceBrokerRequest
-        document_interface_broker_request;
+    mojo::PendingReceiver<mojom::blink::DocumentInterfaceBroker>
+        document_interface_broker_receiver;
     if (global_object_reuse_policy != GlobalObjectReusePolicy::kUseExisting) {
-      document_interface_broker_request =
-          mojo::MakeRequest(&document_interface_broker_);
+      document_interface_broker_.reset();
+      document_interface_broker_receiver =
+          document_interface_broker_.BindNewPipeAndPassReceiver();
     }
 
     web_frame_->Client()->DidCommitProvisionalLoad(
         WebHistoryItem(item), commit_type,
-        document_interface_broker_request.PassMessagePipe());
+        document_interface_broker_receiver.PassPipe());
     if (web_frame_->GetFrame()->IsLocalRoot()) {
       // This update should be sent as soon as loading the new document begins
       // so that the browser and compositor could reset their states. However,
@@ -1124,24 +1128,23 @@
 
 void LocalFrameClientImpl::BindDocumentInterfaceBroker(
     mojo::ScopedMessagePipeHandle js_handle) {
-  document_interface_broker_bindings_.AddBinding(
-      this, mojom::blink::DocumentInterfaceBrokerRequest(std::move(js_handle)));
+  document_interface_broker_receivers_.Add(
+      this, mojo::PendingReceiver<mojom::blink::DocumentInterfaceBroker>(
+                std::move(js_handle)));
 }
 
 mojo::ScopedMessagePipeHandle
 LocalFrameClientImpl::SetDocumentInterfaceBrokerForTesting(
     mojo::ScopedMessagePipeHandle blink_handle) {
   // Ensure all pending calls get dispatched before the implementation swap
-  document_interface_broker_bindings_.FlushForTesting();
+  document_interface_broker_receivers_.FlushForTesting();
 
-  mojom::blink::DocumentInterfaceBrokerPtr test_broker(
-      mojom::blink::DocumentInterfaceBrokerPtrInfo(
-          std::move(blink_handle),
-          mojom::blink::DocumentInterfaceBroker::Version_));
+  mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker> test_broker(
+      std::move(blink_handle), mojom::blink::DocumentInterfaceBroker::Version_);
 
   mojo::ScopedMessagePipeHandle real_handle =
-      document_interface_broker_.PassInterface().PassHandle();
-  document_interface_broker_ = std::move(test_broker);
+      document_interface_broker_.Unbind().PassPipe();
+  document_interface_broker_.Bind(std::move(test_broker));
 
   return real_handle;
 }
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index e044fde..3da7b9c 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -37,6 +37,9 @@
 #include "base/memory/scoped_refptr.h"
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -357,20 +360,18 @@
   String user_agent_;
   blink::UserAgentMetadata user_agent_metadata_;
 
-  mojom::blink::DocumentInterfaceBrokerPtr document_interface_broker_;
+  mojo::Remote<mojom::blink::DocumentInterfaceBroker>
+      document_interface_broker_;
 
-  // |document_interface_broker_bindings_| basically just forwards the broker
+  // |document_interface_broker_receivers_| basically just forwards the broker
   // methods to GetDocumentInterfaceBroker()
   // via DocumentInterfaceBrokerForwarderTraits.
   // Used to connect JavaScript clients of DocumentInterfaceBroker with the same
   // implementation that |document_interface_broker_| is bound to.
-  using DocumentInterfaceBrokerBinding =
-      mojo::Binding<mojom::blink::DocumentInterfaceBroker,
-                    DocumentInterfaceBrokerForwarderTraits>;
-  mojo::BindingSetBase<mojom::blink::DocumentInterfaceBroker,
-                       DocumentInterfaceBrokerBinding,
-                       void>
-      document_interface_broker_bindings_;
+  mojo::ReceiverSetBase<mojo::Receiver<mojom::blink::DocumentInterfaceBroker,
+                                       DocumentInterfaceBrokerForwarderTraits>,
+                        void>
+      document_interface_broker_receivers_;
 };
 
 DEFINE_TYPE_CASTS(LocalFrameClientImpl,
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc
index 8fb33677..6f9d0fe 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc
@@ -30,6 +30,7 @@
 
 #include "third_party/blink/renderer/core/exported/local_frame_client_impl.h"
 
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -111,12 +112,11 @@
 }
 
 TEST_F(LocalFrameClientImplTest, TestDocumentInterfaceBrokerOverride) {
-  mojom::blink::DocumentInterfaceBrokerPtr doc;
+  mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker> doc;
   FrameHostTestDocumentInterfaceBroker frame_interface_broker(
       &MainFrame()->GetFrame()->GetDocumentInterfaceBroker(),
-      mojo::MakeRequest(&doc));
-  MainFrame()->GetFrame()->SetDocumentInterfaceBrokerForTesting(
-      doc.PassInterface().PassHandle());
+      doc.InitWithNewPipeAndPassReceiver());
+  MainFrame()->GetFrame()->SetDocumentInterfaceBrokerForTesting(doc.PassPipe());
 
   mojo::Remote<mojom::blink::FrameHostTestInterface> frame_test;
   MainFrame()
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index ce5b20b7..cd5ebee 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -43,6 +43,7 @@
 #include "gin/object_template_builder.h"
 #include "gin/wrappable.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
@@ -504,10 +505,12 @@
   EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
 
   frame_test_helpers::TestWebFrameClient web_frame_client;
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
       web_view, &web_frame_client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe(),
+      nullptr);
   web_frame_client.Bind(frame);
 
   {
@@ -2643,10 +2646,12 @@
                       /*compositing_enabled=*/false, nullptr));
   frame_test_helpers::TestWebFrameClient web_frame_client;
   frame_test_helpers::TestWebWidgetClient web_widget_client;
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame(
       web_view, &web_frame_client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe(),
+      nullptr);
   web_frame_client.Bind(local_frame);
   blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, local_frame);
 
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index 83e7fb42..2896125 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -24,6 +24,8 @@
     "csp/execution_context_csp_delegate.h",
     "csp/media_list_directive.cc",
     "csp/media_list_directive.h",
+    "csp/navigation_initiator_impl.cc",
+    "csp/navigation_initiator_impl.h",
     "csp/source_list_directive.cc",
     "csp/source_list_directive.h",
     "csp/string_list_directive.cc",
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.h b/third_party/blink/renderer/core/frame/ad_tracker.h
index 001981e..2543296 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker.h
+++ b/third_party/blink/renderer/core/frame/ad_tracker.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_AD_TRACKER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_AD_TRACKER_H_
 
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/probe/async_task_id.h"
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 9a85936..a8ea9d5d 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -28,7 +28,6 @@
 #include <memory>
 #include <utility>
 
-#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_url_request.h"
@@ -153,7 +152,6 @@
       script_hash_algorithms_used_(kContentSecurityPolicyHashAlgorithmNone),
       style_hash_algorithms_used_(kContentSecurityPolicyHashAlgorithmNone),
       sandbox_mask_(WebSandboxFlags::kNone),
-      treat_as_public_address_(false),
       require_trusted_types_(false),
       insecure_request_policy_(kLeaveInsecureRequestsAlone) {}
 
@@ -200,8 +198,6 @@
     Count(WebFeature::kSandboxViaCSP);
     delegate_->SetSandboxFlags(sandbox_mask_);
   }
-  if (treat_as_public_address_)
-    delegate_->SetAddressSpace(network::mojom::IPAddressSpace::kPublic);
 
   if (require_trusted_types_)
     delegate_->SetRequireTrustedTypes();
@@ -872,12 +868,6 @@
   sandbox_mask_ |= mask;
 }
 
-void ContentSecurityPolicy::TreatAsPublicAddress() {
-  if (!RuntimeEnabledFeatures::AddressSpaceEnabled())
-    return;
-  treat_as_public_address_ = true;
-}
-
 void ContentSecurityPolicy::RequireTrustedTypes() {
   // We store whether CSP demands a policy. The caller still needs to check
   // whether the feature is enabled in the first place.
@@ -1454,8 +1444,6 @@
       return "style-src-attr";
     case DirectiveType::kStyleSrcElem:
       return "style-src-elem";
-    case DirectiveType::kTreatAsPublicAddress:
-      return "treat-as-public-address";
     case DirectiveType::kUpgradeInsecureRequests:
       return "upgrade-insecure-requests";
     case DirectiveType::kWorkerSrc:
@@ -1525,8 +1513,6 @@
     return DirectiveType::kStyleSrcAttr;
   if (name == "style-src-elem")
     return DirectiveType::kStyleSrcElem;
-  if (name == "treat-as-public-address")
-    return DirectiveType::kTreatAsPublicAddress;
   if (name == "upgrade-insecure-requests")
     return DirectiveType::kUpgradeInsecureRequests;
   if (name == "worker-src")
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index f155b3b..3d4e153c2 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -97,7 +97,6 @@
 
   // Directives support.
   virtual void SetSandboxFlags(SandboxFlags) = 0;
-  virtual void SetAddressSpace(network::mojom::IPAddressSpace) = 0;
   virtual void SetRequireTrustedTypes() = 0;
   virtual void AddInsecureRequestPolicy(WebInsecureRequestPolicy) = 0;
 
@@ -185,7 +184,6 @@
     kStyleSrc,
     kStyleSrcAttr,
     kStyleSrcElem,
-    kTreatAsPublicAddress,
     kUndefined,
     kUpgradeInsecureRequests,
     kWorkerSrc,
@@ -412,7 +410,6 @@
   const KURL FallbackUrlForPlugin() const;
 
   void EnforceSandboxFlags(SandboxFlags);
-  void TreatAsPublicAddress();
   void RequireTrustedTypes();
   bool IsRequireTrustedTypes() const { return require_trusted_types_; }
   String EvalDisabledErrorMessage() const;
@@ -564,7 +561,6 @@
 
   // State flags used to configure the environment after parsing a policy.
   SandboxFlags sandbox_mask_;
-  bool treat_as_public_address_;
   bool require_trusted_types_;
   String disable_eval_error_message_;
   WebInsecureRequestPolicy insecure_request_policy_;
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index 24f006c..1675b87b 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 
-#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -100,34 +99,6 @@
   }
 }
 
-TEST_F(ContentSecurityPolicyTest, ParseEnforceTreatAsPublicAddressDisabled) {
-  ScopedAddressSpaceForTest address_space(false);
-  execution_context->SetAddressSpace(network::mojom::IPAddressSpace::kPrivate);
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
-            execution_context->AddressSpace());
-
-  csp->DidReceiveHeader("treat-as-public-address",
-                        kContentSecurityPolicyHeaderTypeEnforce,
-                        kContentSecurityPolicyHeaderSourceHTTP);
-  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
-            execution_context->AddressSpace());
-}
-
-TEST_F(ContentSecurityPolicyTest, ParseEnforceTreatAsPublicAddressEnabled) {
-  ScopedAddressSpaceForTest address_space(true);
-  execution_context->SetAddressSpace(network::mojom::IPAddressSpace::kPrivate);
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
-            execution_context->AddressSpace());
-
-  csp->DidReceiveHeader("treat-as-public-address",
-                        kContentSecurityPolicyHeaderTypeEnforce,
-                        kContentSecurityPolicyHeaderSourceHTTP);
-  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
-            execution_context->AddressSpace());
-}
-
 TEST_F(ContentSecurityPolicyTest, CopyStateFrom) {
   csp->DidReceiveHeader("script-src 'none'; plugin-types application/x-type-1",
                         kContentSecurityPolicyHeaderTypeReport,
@@ -1011,8 +982,6 @@
       {ContentSecurityPolicy::DirectiveType::kStyleSrc, "style-src"},
       {ContentSecurityPolicy::DirectiveType::kStyleSrcAttr, "style-src-attr"},
       {ContentSecurityPolicy::DirectiveType::kStyleSrcElem, "style-src-elem"},
-      {ContentSecurityPolicy::DirectiveType::kTreatAsPublicAddress,
-       "treat-as-public-address"},
       {ContentSecurityPolicy::DirectiveType::kUpgradeInsecureRequests,
        "upgrade-insecure-requests"},
       {ContentSecurityPolicy::DirectiveType::kWorkerSrc, "worker-src"},
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index ff18a796..a6b03bc 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -133,7 +133,6 @@
       has_sandbox_policy_(false),
       strict_mixed_content_checking_enforced_(false),
       upgrade_insecure_requests_(false),
-      treat_as_public_address_(false),
       require_sri_for_(RequireSRIForToken::kNone),
       use_reporting_api_(false) {}
 
@@ -1233,22 +1232,6 @@
     policy_->ReportInvalidSandboxFlags(invalid_tokens);
 }
 
-void CSPDirectiveList::TreatAsPublicAddress(const String& name,
-                                            const String& value) {
-  if (IsReportOnly()) {
-    policy_->ReportInvalidInReportOnly(name);
-    return;
-  }
-  if (treat_as_public_address_) {
-    policy_->ReportDuplicateDirective(name);
-    return;
-  }
-  treat_as_public_address_ = true;
-  policy_->TreatAsPublicAddress();
-  if (!value.IsEmpty())
-    policy_->ReportValueForEmptyDirective(name, value);
-}
-
 void CSPDirectiveList::RequireTrustedTypes(const String& name,
                                            const String& value) {
   if (trusted_types_) {
@@ -1360,9 +1343,6 @@
     SetCSPDirective<SourceListDirective>(name, value, manifest_src_);
   } else if (type == ContentSecurityPolicy::DirectiveType::kNavigateTo) {
     SetCSPDirective<SourceListDirective>(name, value, navigate_to_);
-  } else if (type ==
-             ContentSecurityPolicy::DirectiveType::kTreatAsPublicAddress) {
-    TreatAsPublicAddress(name, value);
   } else if (type == ContentSecurityPolicy::DirectiveType::kReportTo &&
              base::FeatureList::IsEnabled(network::features::kReporting)) {
     ParseReportTo(name, value);
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
index 264b22da..07a24d7 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
@@ -183,7 +183,6 @@
   void EnforceStrictMixedContentChecking(const String& name,
                                          const String& value);
   void EnableInsecureRequestsUpgrade(const String& name, const String& value);
-  void TreatAsPublicAddress(const String& name, const String& value);
   void RequireTrustedTypes(const String& name, const String& value);
 
   template <class CSPDirectiveType>
@@ -308,7 +307,6 @@
   bool strict_mixed_content_checking_enforced_;
 
   bool upgrade_insecure_requests_;
-  bool treat_as_public_address_;
 
   Member<MediaListDirective> plugin_types_;
   Member<SourceListDirective> base_uri_;
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
index 7d58873..8537246 100644
--- a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
@@ -64,11 +64,6 @@
   CHECK_EQ(flags | mask, flags);
 }
 
-void ExecutionContextCSPDelegate::SetAddressSpace(
-    network::mojom::IPAddressSpace space) {
-  GetSecurityContext().SetAddressSpace(space);
-}
-
 void ExecutionContextCSPDelegate::SetRequireTrustedTypes() {
   GetSecurityContext().SetRequireTrustedTypes();
 }
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
index 8cbee40..1f0e419 100644
--- a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
@@ -27,7 +27,6 @@
   const SecurityOrigin* GetSecurityOrigin() override;
   const KURL& Url() const override;
   void SetSandboxFlags(SandboxFlags) override;
-  void SetAddressSpace(network::mojom::IPAddressSpace) override;
   void SetRequireTrustedTypes() override;
   void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override;
   std::unique_ptr<SourceLocation> GetSourceLocation() override;
diff --git a/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc
new file mode 100644
index 0000000..00317ab
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc
@@ -0,0 +1,56 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+
+namespace blink {
+
+NavigationInitiatorImpl::NavigationInitiatorImpl(Document& document)
+    : document_(document) {}
+
+void NavigationInitiatorImpl::Trace(Visitor* visitor) {
+  visitor->Trace(document_);
+}
+
+void NavigationInitiatorImpl::SendViolationReport(
+    mojom::blink::CSPViolationParamsPtr violation_params) {
+  std::unique_ptr<SourceLocation> source_location =
+      std::make_unique<SourceLocation>(
+          violation_params->source_location->url,
+          violation_params->source_location->line_number,
+          violation_params->source_location->column_number, nullptr);
+
+  Vector<String> report_endpoints;
+  for (const String& end_point : violation_params->report_endpoints)
+    report_endpoints.push_back(end_point);
+
+  document_->AddConsoleMessage(ConsoleMessage::Create(
+      mojom::ConsoleMessageSource::kSecurity,
+      mojom::ConsoleMessageLevel::kError, violation_params->console_message));
+  document_->GetContentSecurityPolicy()->ReportViolation(
+      violation_params->directive,
+      ContentSecurityPolicy::GetDirectiveType(
+          violation_params->effective_directive),
+      violation_params->console_message, KURL(violation_params->blocked_url),
+      report_endpoints, violation_params->use_reporting_api,
+      violation_params->header,
+      static_cast<ContentSecurityPolicyHeaderType>(
+          violation_params->disposition),
+      ContentSecurityPolicy::ViolationType::kURLViolation,
+      std::move(source_location), nullptr /* LocalFrame */,
+      violation_params->after_redirect ? RedirectStatus::kFollowedRedirect
+                                       : RedirectStatus::kNoRedirect,
+      nullptr /* Element */);
+}
+
+void NavigationInitiatorImpl::Dispose() {
+  navigation_initiator_receivers_.Clear();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h
new file mode 100644
index 0000000..621b0a5d
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h
@@ -0,0 +1,47 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_NAVIGATION_INITIATOR_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_NAVIGATION_INITIATOR_IMPL_H_
+
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "third_party/blink/public/mojom/frame/navigation_initiator.mojom-blink.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class Document;
+
+class NavigationInitiatorImpl
+    : public GarbageCollectedFinalized<NavigationInitiatorImpl>,
+      public mojom::blink::NavigationInitiator {
+  USING_PRE_FINALIZER(NavigationInitiatorImpl, Dispose);
+
+ public:
+  explicit NavigationInitiatorImpl(Document& document);
+  void Trace(Visitor* visitor);
+
+  // mojom::blink::NavigationInitiator override:
+  void SendViolationReport(
+      mojom::blink::CSPViolationParamsPtr violation_params) override;
+
+  void BindReceiver(
+      mojo::PendingReceiver<mojom::blink::NavigationInitiator> receiver) {
+    navigation_initiator_receivers_.Add(this, std::move(receiver));
+  }
+
+ private:
+  void Dispose();
+
+  // A list of all the navigation_initiator receivers owned by the owner
+  // document. Used to report CSP violations that result from CSP blocking
+  // navigation requests that were initiated by the owner document.
+  mojo::ReceiverSet<mojom::blink::NavigationInitiator>
+      navigation_initiator_receivers_;
+
+  Member<Document> document_;
+};
+
+}  // namespace blink
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_NAVIGATION_INITIATOR_IMPL_H_
diff --git a/third_party/blink/renderer/core/frame/frame_test.cc b/third_party/blink/renderer/core/frame/frame_test.cc
index da40612..e3f800f3 100644
--- a/third_party/blink/renderer/core/frame/frame_test.cc
+++ b/third_party/blink/renderer/core/frame/frame_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/frame/frame.h"
 
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
@@ -188,12 +189,12 @@
 }
 
 TEST_F(FrameTest, TestDocumentInterfaceBrokerOverride) {
-  mojom::blink::DocumentInterfaceBrokerPtr doc;
+  mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker> doc;
   FrameHostTestDocumentInterfaceBroker frame_interface_broker(
       &GetDocument().GetFrame()->GetDocumentInterfaceBroker(),
-      mojo::MakeRequest(&doc));
+      doc.InitWithNewPipeAndPassReceiver());
   GetDocument().GetFrame()->SetDocumentInterfaceBrokerForTesting(
-      doc.PassInterface().PassHandle());
+      doc.PassPipe());
 
   mojo::Remote<mojom::blink::FrameHostTestInterface> frame_test;
   GetDocument()
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index c9aedfb1..a1f2e2a 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -37,6 +37,7 @@
 #include "cc/test/test_ukm_recorder_factory.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_settings.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/common/frame/frame_policy.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_data.h"
@@ -209,10 +210,11 @@
                                     TestWebFrameClient* client) {
   std::unique_ptr<TestWebFrameClient> owned_client;
   client = CreateDefaultClientIfNeeded(client, owned_client);
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
       scope, client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe()));
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe()));
   client->Bind(frame, std::move(owned_client));
   return frame;
 }
@@ -223,10 +225,11 @@
     std::unique_ptr<TestWebFrameClient> self_owned) {
   DCHECK(self_owned);
   TestWebFrameClient* client = self_owned.get();
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
       scope, client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe()));
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe()));
   client->Bind(frame, std::move(self_owned));
   return frame;
 }
@@ -235,10 +238,11 @@
                                      TestWebFrameClient* client) {
   std::unique_ptr<TestWebFrameClient> owned_client;
   client = CreateDefaultClientIfNeeded(client, owned_client);
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   auto* frame = To<WebLocalFrameImpl>(WebLocalFrame::CreateProvisional(
       client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(),
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe(),
       &old_frame, FramePolicy()));
   client->Bind(frame, std::move(owned_client));
   std::unique_ptr<TestWebWidgetClient> widget_client;
@@ -279,10 +283,11 @@
                                     TestWebWidgetClient* widget_client) {
   std::unique_ptr<TestWebFrameClient> owned_client;
   client = CreateDefaultClientIfNeeded(client, owned_client);
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
       WebTreeScopeType::kDocument, name, FramePolicy(), client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(),
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe(),
       previous_sibling, properties, FrameOwnerElementType::kIframe, nullptr));
   client->Bind(frame, std::move(owned_client));
 
@@ -343,10 +348,12 @@
   std::unique_ptr<TestWebFrameClient> owned_web_frame_client;
   web_frame_client =
       CreateDefaultClientIfNeeded(web_frame_client, owned_web_frame_client);
-  mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
   WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
       web_view_, web_frame_client, nullptr,
-      mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), opener);
+      mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker>()
+          .InitWithNewPipeAndPassReceiver()
+          .PassPipe(),
+      opener);
   web_frame_client->Bind(frame, std::move(owned_web_frame_client));
 
   test_web_widget_client_ = CreateDefaultClientIfNeeded(
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index 7c7c782..a6f6cb34 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -30,11 +30,9 @@
 #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
 #include "third_party/blink/renderer/bindings/core/v8/string_treat_null_as_empty_string_or_trusted_script.h"
 #include "third_party/blink/renderer/core/css/css_color_value.h"
-#include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_markup.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
-#include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/dom/document_fragment.h"
@@ -246,9 +244,7 @@
   if (name == kAlignAttr || name == kContenteditableAttr ||
       name == kHiddenAttr || name == kLangAttr ||
       name.Matches(xml_names::kLangAttr) || name == kDraggableAttr ||
-      name == kDirAttr ||
-      (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
-       name == kRendersubtreeAttr))
+      name == kDirAttr)
     return true;
   return Element::IsPresentationAttribute(name);
 }
@@ -337,18 +333,6 @@
     // xml:lang has a higher priority than lang.
     if (!FastHasAttribute(xml_names::kLangAttr))
       MapLanguageAttributeToLocale(value, style);
-  } else if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
-             name == kRendersubtreeAttr) {
-    // Add contain: style layout size.
-    CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-    list->Append(*CSSIdentifierValue::Create(CSSValueID::kStyle));
-    list->Append(*CSSIdentifierValue::Create(CSSValueID::kLayout));
-    if (EqualIgnoringASCIICase(value, "invisible") ||
-        EqualIgnoringASCIICase(value, "invisible-activatable")) {
-      list->Append(*CSSIdentifierValue::Create(CSSValueID::kSize));
-    }
-    AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kContain,
-                                            *list);
   } else {
     Element::CollectStyleForPresentationAttribute(name, value, style);
   }
diff --git a/third_party/blink/renderer/core/loader/empty_clients.cc b/third_party/blink/renderer/core/loader/empty_clients.cc
index 17515b3..dff1b8c 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -29,6 +29,7 @@
 
 #include <memory>
 #include "cc/layers/layer.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider_client.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -129,21 +130,19 @@
 mojom::blink::DocumentInterfaceBroker*
 EmptyLocalFrameClient::GetDocumentInterfaceBroker() {
   if (!document_interface_broker_.is_bound())
-    mojo::MakeRequest(&document_interface_broker_);
+    ignore_result(document_interface_broker_.BindNewPipeAndPassReceiver());
   return document_interface_broker_.get();
 }
 
 mojo::ScopedMessagePipeHandle
 EmptyLocalFrameClient::SetDocumentInterfaceBrokerForTesting(
     mojo::ScopedMessagePipeHandle blink_handle) {
-  mojom::blink::DocumentInterfaceBrokerPtr test_broker(
-      mojom::blink::DocumentInterfaceBrokerPtrInfo(
-          std::move(blink_handle),
-          mojom::blink::DocumentInterfaceBroker::Version_));
+  mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker> test_broker(
+      std::move(blink_handle), mojom::blink::DocumentInterfaceBroker::Version_);
 
   mojo::ScopedMessagePipeHandle real_handle =
-      document_interface_broker_.PassInterface().PassHandle();
-  document_interface_broker_ = std::move(test_broker);
+      document_interface_broker_.Unbind().PassPipe();
+  document_interface_broker_.Bind(std::move(test_broker));
 
   return real_handle;
 }
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index ceb7ed3..07e9f09 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -34,6 +34,7 @@
 #include "base/macros.h"
 #include "cc/paint/paint_canvas.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -432,7 +433,8 @@
   WebTextCheckClient* text_check_client_;
 
   service_manager::InterfaceProvider interface_provider_;
-  mojom::blink::DocumentInterfaceBrokerPtr document_interface_broker_;
+  mojo::Remote<mojom::blink::DocumentInterfaceBroker>
+      document_interface_broker_;
 
   DISALLOW_COPY_AND_ASSIGN(EmptyLocalFrameClient);
 };
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 128e78a5..aad6eaef 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -62,6 +62,7 @@
 #include "third_party/blink/renderer/core/dom/ignore_opens_during_unload_count_incrementer.h"
 #include "third_party/blink/renderer/core/events/page_transition_event.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -678,7 +679,7 @@
                              ->ExperimentalFeaturesEnabled()) {
     initiator_csp = origin_document->GetContentSecurityPolicy()
                         ->ExposeForNavigationalChecks();
-    origin_document->BindNavigationInitiatorReceiver(
+    origin_document->NavigationInitiator().BindReceiver(
         navigation_initiator.InitWithNewPipeAndPassReceiver());
   }
 
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index b6fc922..b18063ba 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -550,24 +550,26 @@
                          LinkLoaderModulePreloadTest,
                          testing::ValuesIn(kModulePreloadTestParams));
 
-class LinkLoaderTestPrefetchRedirect
+class LinkLoaderTestPrefetchPrivacyChanges
+
     : public testing::Test,
       public testing::WithParamInterface<bool> {
  public:
-  LinkLoaderTestPrefetchRedirect() : redirect_mode_is_error_(GetParam()) {}
+  LinkLoaderTestPrefetchPrivacyChanges()
+      : privacy_changes_enabled_(GetParam()) {}
   void SetUp() override {
     std::vector<base::Feature> enable_features;
     std::vector<base::Feature> disabled_features;
     if (GetParam()) {
-      enable_features.push_back(features::kPrefetchRedirectError);
+      enable_features.push_back(features::kPrefetchPrivacyChanges);
     } else {
-      disabled_features.push_back(features::kPrefetchRedirectError);
+      disabled_features.push_back(features::kPrefetchPrivacyChanges);
     }
     feature_list_.InitWithFeatures(enable_features, disabled_features);
   }
 
  protected:
-  const bool redirect_mode_is_error_;
+  const bool privacy_changes_enabled_;
   ScopedTestingPlatformSupport<TestingPlatformSupportWithNetworkHintsMock>
       platform_;
 
@@ -575,11 +577,11 @@
   base::test::ScopedFeatureList feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(LinkLoaderTestPrefetchRedirect,
-                         LinkLoaderTestPrefetchRedirect,
-                         testing::Values(true, false));
+INSTANTIATE_TEST_SUITE_P(LinkLoaderTestPrefetchPrivacyChanges,
+                         LinkLoaderTestPrefetchPrivacyChanges,
+                         testing::Values(false, true));
 
-TEST_P(LinkLoaderTestPrefetchRedirect, PrefetchRedirect) {
+TEST_P(LinkLoaderTestPrefetchPrivacyChanges, PrefetchPrivacyChanges) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(500, 500));
   dummy_page_holder->GetFrame().GetSettings()->SetScriptEnabled(true);
   Persistent<MockLinkLoaderClient> loader_client =
@@ -598,12 +600,16 @@
   Resource* resource = loader->GetResourceForTesting();
   EXPECT_TRUE(resource);
 
-  if (redirect_mode_is_error_) {
+  if (privacy_changes_enabled_) {
     EXPECT_EQ(resource->GetResourceRequest().GetRedirectMode(),
               network::mojom::RedirectMode::kError);
+    EXPECT_EQ(resource->GetResourceRequest().GetReferrerPolicy(),
+              network::mojom::ReferrerPolicy::kNever);
   } else {
     EXPECT_EQ(resource->GetResourceRequest().GetRedirectMode(),
               network::mojom::RedirectMode::kFollow);
+    EXPECT_EQ(resource->GetResourceRequest().GetReferrerPolicy(),
+              network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade);
   }
 
   platform_->GetURLLoaderMockFactory()->UnregisterAllURLsAndClearMemoryCache();
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
index f65ffb1..86a7606 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
@@ -342,6 +342,7 @@
 void ModuleTreeLinker::FetchDescendants(const ModuleScript* module_script) {
   DCHECK(module_script);
 
+  // TODO(crbug.com/1000152): Replace ScriptState::Scope with v8::HandleScope
   ScriptState::Scope scope(modulator_->GetScriptState());
   // [nospec] Abort the steps if the browsing context is discarded.
   if (!modulator_->HasValidContext()) {
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index be34009..2e6ca0e 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -483,9 +483,6 @@
     UseCounter::Count(document, WebFeature::kLinkRelPrefetch);
 
     ResourceRequest resource_request(params.href);
-    if (base::FeatureList::IsEnabled(features::kPrefetchRedirectError)) {
-      resource_request.SetRedirectMode(network::mojom::RedirectMode::kError);
-    }
 
     // TODO(domfarolino): When SplitCache is enabled by default and we can
     // remove this feature check, also remove the exceptions in
@@ -500,6 +497,14 @@
     resource_request.SetFetchImportanceMode(
         GetFetchImportanceAttributeValue(params.importance));
 
+    if (base::FeatureList::IsEnabled(features::kPrefetchPrivacyChanges)) {
+      resource_request.SetRedirectMode(network::mojom::RedirectMode::kError);
+      resource_request.SetReferrerPolicy(
+          network::mojom::ReferrerPolicy::kNever);
+      // TODO(domfarolino): Implement more privacy-preserving prefetch changes.
+      // See crbug.com/988956.
+    }
+
     ResourceLoaderOptions options;
     options.initiator_info.name = fetch_initiator_type_names::kLink;
 
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/virtual-scroller/visibility-manager.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/virtual-scroller/visibility-manager.mjs
index 14362f0b..05239e4 100644
--- a/third_party/blink/renderer/core/script/resources/layered_api/elements/virtual-scroller/visibility-manager.mjs
+++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/virtual-scroller/visibility-manager.mjs
@@ -207,8 +207,8 @@
         // which would involve an unknown number of forced layouts, we
         // come back next frame and try to make it better. We know we can
         // stop when we didn't hide or reveal any elements.
-        if (this.#syncRevealed(newRevealed) +
-            this.#syncObserved(newObserved) > 0) {
+        if (this.#syncRevealed(newRevealed) + this.#syncObserved(newObserved) >
+            0) {
           this.scheduleSync();
         }
       }
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc b/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
index 517c6f91..c803bc8 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
@@ -22,7 +22,7 @@
   explicit ReadableStreamDefaultControllerWrapper(ScriptState* script_state,
                                                   ScriptValue controller)
       : ReadableStreamDefaultControllerInterface(script_state),
-        js_controller_(controller.GetIsolate(), controller.V8Value()) {
+        js_controller_(script_state->GetIsolate(), controller.V8Value()) {
     js_controller_.SetPhantom();
   }
 
diff --git a/third_party/blink/renderer/core/testing/test_document_interface_broker.h b/third_party/blink/renderer/core/testing/test_document_interface_broker.h
index 7ab058e..5786f31 100644
--- a/third_party/blink/renderer/core/testing/test_document_interface_broker.h
+++ b/third_party/blink/renderer/core/testing/test_document_interface_broker.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_TEST_DOCUMENT_INTERFACE_BROKER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_TEST_DOCUMENT_INTERFACE_BROKER_H_
 
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink-test-utils.h"
 
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 363e526..bb65fed 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -81,7 +81,6 @@
   // off-the-main-thread shared worker/service worker top-level script fetch.
   // https://crbug.com/924041 https://crbug.com/924043
   void SetSandboxFlags(SandboxFlags) override {}
-  void SetAddressSpace(network::mojom::IPAddressSpace) override {}
   void SetRequireTrustedTypes() override {}
   void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override {}
   void DisableEval(const String& error_message) override {}
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js
index a76a687..73136c19 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js
@@ -36,19 +36,21 @@
   }
 
   /**
-   * @return {boolean}
+   * @return {!Promise<boolean>}
    */
-  start() {
+  async start() {
+    const promises = [];
     if (this._cssModel) {
       // Note there's no JS coverage since JS won't ever return
       // coverage twice, even after it's restarted.
       this._clearCSS();
-      this._cssModel.startCoverage();
+      promises.push(this._cssModel.startCoverage());
     }
     if (this._cpuProfilerModel) {
       this._bestEffortCoveragePromise = this._cpuProfilerModel.bestEffortCoverage();
-      this._cpuProfilerModel.startPreciseCoverage();
+      promises.push(this._cpuProfilerModel.startPreciseCoverage());
     }
+    await Promise.all(promises);
     return !!(this._cssModel || this._cpuProfilerModel);
   }
 
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
index 319717f0..6df185d 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
@@ -8,8 +8,8 @@
 
     /** @type {?Coverage.CoverageModel} */
     this._model = null;
-    /** @type {number|undefined} */
-    this._pollTimer;
+    /** @type {?number} */
+    this._pollTimer = null;
     /** @type {?Coverage.CoverageDecorationManager} */
     this._decorationManager = null;
     /** @type {?SDK.ResourceTreeModel} */
@@ -116,22 +116,25 @@
   /**
    * @param {boolean} reload
    */
-  _startRecording(reload) {
+  async _startRecording(reload) {
     this._reset();
     const mainTarget = SDK.targetManager.mainTarget();
     if (!mainTarget)
       return;
+
     if (!this._model || reload)
-      this._model = new Coverage.CoverageModel(mainTarget);
+      this._model = new Coverage.CoverageModel(/** @type {!SDK.Target} */ (mainTarget));
     Host.userMetrics.actionTaken(Host.UserMetrics.Action.CoverageStarted);
-    if (!this._model.start())
+    const success = await this._model.start();
+    if (!success)
       return;
     this._resourceTreeModel = /** @type {?SDK.ResourceTreeModel} */ (mainTarget.model(SDK.ResourceTreeModel));
     if (this._resourceTreeModel) {
       this._resourceTreeModel.addEventListener(
           SDK.ResourceTreeModel.Events.MainFrameNavigated, this._onMainFrameNavigated, this);
     }
-    this._decorationManager = new Coverage.CoverageDecorationManager(this._model);
+    this._decorationManager =
+        new Coverage.CoverageDecorationManager(/** @type {!Coverage.CoverageModel} */ (this._model));
     this._toggleRecordAction.setToggled(true);
     this._clearButton.setEnabled(false);
     if (this._startWithReloadButton)
@@ -147,7 +150,11 @@
   }
 
   async _poll() {
-    delete this._pollTimer;
+    if (this._pollTimer) {
+      clearTimeout(this._pollTimer);
+      // Clear until this._model.poll() finishes.
+      this._pollTimer = null;
+    }
     const updates = await this._model.poll();
     this._updateViews(updates);
     this._pollTimer = setTimeout(() => this._poll(), 700);
@@ -156,7 +163,7 @@
   async _stopRecording() {
     if (this._pollTimer) {
       clearTimeout(this._pollTimer);
-      delete this._pollTimer;
+      this._pollTimer = null;
     }
     if (this._resourceTreeModel) {
       this._resourceTreeModel.removeEventListener(
diff --git a/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js b/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
index c944baf..a7914e31 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
@@ -7,10 +7,10 @@
  * @suppress {accessControls}
  */
 
-CoverageTestRunner.startCoverage = function() {
+CoverageTestRunner.startCoverage = async function() {
   UI.viewManager.showView('coverage');
   const coverageView = self.runtime.sharedInstance(Coverage.CoverageView);
-  coverageView._startRecording();
+  await coverageView._startRecording();
 };
 
 /**
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/AcornTokenizer.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/AcornTokenizer.js
index 5121188..e20b79d2 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/AcornTokenizer.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/AcornTokenizer.js
@@ -11,7 +11,8 @@
   constructor(content) {
     this._content = content;
     this._comments = [];
-    this._tokenizer = acorn.tokenizer(this._content, {ecmaVersion: 8, onComment: this._comments});
+    this._tokenizer =
+        acorn.tokenizer(this._content, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION, onComment: this._comments});
     this._textCursor = new TextUtils.TextCursor(this._content.computeLineEndings());
     this._tokenLineStart = 0;
     this._tokenLineEnd = 0;
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
index 19bb1105..debe39f 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
@@ -27,6 +27,9 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
+FormatterWorker.ACORN_ECMA_VERSION = 2018;
+
 /**
  * @param {string} mimeType
  * @return {function(string, function(string, ?string, number, number):(!Object|undefined))}
@@ -109,7 +112,7 @@
  * @param {string} content
  */
 FormatterWorker.evaluatableJavaScriptSubstring = function(content) {
-  const tokenizer = acorn.tokenizer(content, {ecmaVersion: 9});
+  const tokenizer = acorn.tokenizer(content, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
   let result = '';
   try {
     let token = tokenizer.getToken();
@@ -155,7 +158,7 @@
   let root;
   let body;
   try {
-    root = acorn.parse(wrapped, {ecmaVersion: 10});
+    root = acorn.parse(wrapped, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
     body = root.body[0].expression.callee.body;
   } catch (e) {
     postMessage('');
@@ -251,7 +254,7 @@
 FormatterWorker.javaScriptIdentifiers = function(content) {
   let root = null;
   try {
-    root = acorn.parse(content, {ranges: false, ecmaVersion: 9});
+    root = acorn.parse(content, {ranges: false, ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
   } catch (e) {
   }
 
@@ -351,7 +354,7 @@
   if (content.length > 10000)
     return null;
   try {
-    const tokenizer = acorn.tokenizer(content, {ecmaVersion: 9});
+    const tokenizer = acorn.tokenizer(content, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
     while (tokenizer.getToken().type !== acorn.tokTypes.eof) {
     }
   } catch (e) {
@@ -396,13 +399,13 @@
   let parsed = null;
   try {
     // Try to parse as a function, anonymous function, or arrow function.
-    parsed = acorn.parse(`(${content})`, {ecmaVersion: 9});
+    parsed = acorn.parse(`(${content})`, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
   } catch (e) {
   }
   if (!parsed) {
     try {
       // Try to parse as a method.
-      parsed = acorn.parse(`({${content}})`, {ecmaVersion: 9});
+      parsed = acorn.parse(`({${content}})`, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
     } catch (e) {
     }
   }
@@ -457,7 +460,7 @@
   if (content.length > 10000)
     return null;
   try {
-    const tokenizer = acorn.tokenizer(content, {ecmaVersion: 9});
+    const tokenizer = acorn.tokenizer(content, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
     while (tokenizer.getToken().type !== acorn.tokTypes.eof) {
     }
   } catch (e) {
@@ -466,7 +469,7 @@
 
   const suffix = '.DEVTOOLS';
   try {
-    acorn.parse(content + suffix, {ecmaVersion: 9});
+    acorn.parse(content + suffix, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
   } catch (parseError) {
     // If this is an invalid location for a '.', don't attempt to give autocomplete
     if (parseError.message.startsWith('Unexpected token') && parseError.pos === content.length)
@@ -494,7 +497,7 @@
     try {
       // Wrap content in paren to successfully parse object literals
       parsedContent = content[i] === '{' ? `(${content.substring(i)})${suffix}` : `${content.substring(i)}${suffix}`;
-      ast = acorn.parse(parsedContent, {ecmaVersion: 9});
+      ast = acorn.parse(parsedContent, {ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
       break;
     } catch (e) {
     }
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptFormatter.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptFormatter.js
index b702a6db..2ef7b32 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptFormatter.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptFormatter.js
@@ -51,7 +51,8 @@
     this._content = text.substring(this._fromOffset, this._toOffset);
     this._lastLineNumber = 0;
     this._tokenizer = new FormatterWorker.AcornTokenizer(this._content);
-    const ast = acorn.parse(this._content, {ranges: false, ecmaVersion: 8, preserveParens: true});
+    const ast = acorn.parse(
+        this._content, {ranges: false, ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION, preserveParens: true});
     const walker = new FormatterWorker.ESTreeWalker(this._beforeVisit.bind(this), this._afterVisit.bind(this));
     walker.walk(ast);
   }
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
index 7c45d38..8e3787f 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
@@ -11,9 +11,9 @@
 
   let ast;
   try {
-    ast = acorn.parse(content, {ranges: false, ecmaVersion: 8});
+    ast = acorn.parse(content, {ranges: false, ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
   } catch (e) {
-    ast = acorn.loose.parse(content, {ranges: false, ecmaVersion: 8});
+    ast = acorn.loose.parse(content, {ranges: false, ecmaVersion: FormatterWorker.ACORN_ECMA_VERSION});
   }
 
   const textCursor = new TextUtils.TextCursor(content.computeLineEndings());
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js b/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js
index 506d30b..755da8e 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js
@@ -58,6 +58,9 @@
     /** @type {!Map.<!SDK.CSSStyleSheetHeader, !Promise<?string>>} */
     this._originalStyleSheetText = new Map();
 
+    /** @type {boolean} */
+    this._isRuleUsageTrackingEnabled = false;
+
     this._sourceMapManager.setEnabled(Common.moduleSetting('cssSourceMapsEnabled').get());
     Common.moduleSetting('cssSourceMapsEnabled')
         .addChangeListener(event => this._sourceMapManager.setEnabled(/** @type {boolean} */ (event.data)));
@@ -172,7 +175,8 @@
   }
 
   startCoverage() {
-    this._agent.startRuleUsageTracking();
+    this._isRuleUsageTrackingEnabled = true;
+    return this._agent.startRuleUsageTracking();
   }
 
   /**
@@ -186,6 +190,7 @@
    * @return {!Promise}
    */
   stopCoverage() {
+    this._isRuleUsageTrackingEnabled = false;
     return this._agent.stopRuleUsageTracking();
   }
 
@@ -210,6 +215,8 @@
   async _enable() {
     await this._agent.enable();
     this._isEnabled = true;
+    if (this._isRuleUsageTrackingEnabled)
+      await this.startCoverage();
     this.dispatchEventToListeners(SDK.CSSModel.Events.ModelWasEnabled);
   }
 
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js
index b76899d..73e76be2 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineController.js
@@ -184,6 +184,9 @@
    * @return {!Promise<!Object>}
    */
   async _startRecordingWithCategories(categories, enableJSSampling) {
+    // There might be a significant delay in the beginning of timeline recording
+    // caused by starting CPU profiler, that needs to traverse JS heap to collect
+    // all the functions data.
     SDK.targetManager.suspendAllTargets();
     if (enableJSSampling && Runtime.queryParam('timelineTracingJSProfileDisabled'))
       await this._startProfilingOnAllModels();
diff --git a/third_party/blink/renderer/modules/content_index/content_index.cc b/third_party/blink/renderer/modules/content_index/content_index.cc
index 59cbf63c..a8b4d6f7 100644
--- a/third_party/blink/renderer/modules/content_index/content_index.cc
+++ b/third_party/blink/renderer/modules/content_index/content_index.cc
@@ -167,6 +167,10 @@
       // The renderer should have been killed.
       NOTREACHED();
       return;
+    case mojom::blink::ContentIndexError::NO_SERVICE_WORKER:
+      resolver->Reject(V8ThrowException::CreateTypeError(
+          script_state->GetIsolate(), "Service worker must be active"));
+      return;
   }
 }
 
@@ -209,6 +213,10 @@
       // The renderer should have been killed.
       NOTREACHED();
       return;
+    case mojom::blink::ContentIndexError::NO_SERVICE_WORKER:
+      // This value shouldn't apply to this callback.
+      NOTREACHED();
+      return;
   }
 }
 
@@ -257,6 +265,10 @@
       // The renderer should have been killed.
       NOTREACHED();
       return;
+    case mojom::blink::ContentIndexError::NO_SERVICE_WORKER:
+      // This value shouldn't apply to this callback.
+      NOTREACHED();
+      return;
   }
 }
 
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
index 18ba4aa..72be464 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -131,12 +132,12 @@
       : dummy_context_(KURL("https://example.test")) {
     dummy_context_.GetDocument().SetSecureContextStateForTesting(
         SecureContextState::kSecure);
-    mojom::blink::DocumentInterfaceBrokerPtr doc;
+    mojo::PendingRemote<mojom::blink::DocumentInterfaceBroker> doc;
     broker_ = std::make_unique<MockCredentialManagerDocumentInterfaceBroker>(
         &dummy_context_.GetFrame().GetDocumentInterfaceBroker(),
-        mojo::MakeRequest(&doc), mock_credential_manager);
+        doc.InitWithNewPipeAndPassReceiver(), mock_credential_manager);
     dummy_context_.GetFrame().SetDocumentInterfaceBrokerForTesting(
-        doc.PassInterface().PassHandle());
+        doc.PassPipe());
   }
 
   Document* GetDocument() { return &dummy_context_.GetDocument(); }
diff --git a/third_party/blink/renderer/modules/payments/payment_instruments.cc b/third_party/blink/renderer/modules/payments/payment_instruments.cc
index 5003acb..20350d57 100644
--- a/third_party/blink/renderer/modules/payments/payment_instruments.cc
+++ b/third_party/blink/renderer/modules/payments/payment_instruments.cc
@@ -139,7 +139,7 @@
 };
 
 PaymentInstruments::PaymentInstruments(
-    const payments::mojom::blink::PaymentManagerPtr& manager)
+    const mojo::Remote<payments::mojom::blink::PaymentManager>& manager)
     : manager_(manager) {}
 
 ScriptPromise PaymentInstruments::deleteInstrument(
diff --git a/third_party/blink/renderer/modules/payments/payment_instruments.h b/third_party/blink/renderer/modules/payments/payment_instruments.h
index 363cea0..13e9824 100644
--- a/third_party/blink/renderer/modules/payments/payment_instruments.h
+++ b/third_party/blink/renderer/modules/payments/payment_instruments.h
@@ -27,7 +27,8 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit PaymentInstruments(const payments::mojom::blink::PaymentManagerPtr&);
+  explicit PaymentInstruments(
+      const mojo::Remote<payments::mojom::blink::PaymentManager>&);
 
   ScriptPromise deleteInstrument(ScriptState*, const String& instrument_key);
   ScriptPromise get(ScriptState*, const String& instrument_key);
@@ -61,7 +62,7 @@
   void onClearPaymentInstruments(ScriptPromiseResolver*,
                                  payments::mojom::blink::PaymentHandlerStatus);
 
-  const payments::mojom::blink::PaymentManagerPtr& manager_;
+  const mojo::Remote<payments::mojom::blink::PaymentManager>& manager_;
 
   mojo::Remote<mojom::blink::PermissionService> permission_service_;
 
diff --git a/third_party/blink/renderer/modules/payments/payment_manager.cc b/third_party/blink/renderer/modules/payments/payment_manager.cc
index 8d92b02..0952de3 100644
--- a/third_party/blink/renderer/modules/payments/payment_manager.cc
+++ b/third_party/blink/renderer/modules/payments/payment_manager.cc
@@ -45,14 +45,13 @@
   DCHECK(registration);
 
   if (ExecutionContext* context = registration->GetExecutionContext()) {
-    auto request = mojo::MakeRequest(
-        &manager_, context->GetTaskRunner(TaskType::kUserInteraction));
     if (auto* interface_provider = context->GetInterfaceProvider()) {
-      interface_provider->GetInterface(std::move(request));
+      interface_provider->GetInterface(manager_.BindNewPipeAndPassReceiver(
+          context->GetTaskRunner(TaskType::kUserInteraction)));
     }
   }
 
-  manager_.set_connection_error_handler(WTF::Bind(
+  manager_.set_disconnect_handler(WTF::Bind(
       &PaymentManager::OnServiceConnectionError, WrapWeakPersistent(this)));
   manager_->Init(registration_->GetExecutionContext()->Url(),
                  registration_->scope());
diff --git a/third_party/blink/renderer/modules/payments/payment_manager.h b/third_party/blink/renderer/modules/payments/payment_manager.h
index c75ee67e..edd7cc80 100644
--- a/third_party/blink/renderer/modules/payments/payment_manager.h
+++ b/third_party/blink/renderer/modules/payments/payment_manager.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_MANAGER_H_
 
 #include "base/macros.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/payments/payment_app.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -36,7 +37,7 @@
   void OnServiceConnectionError();
 
   Member<ServiceWorkerRegistration> registration_;
-  payments::mojom::blink::PaymentManagerPtr manager_;
+  mojo::Remote<payments::mojom::blink::PaymentManager> manager_;
   Member<PaymentInstruments> instruments_;
   String user_hint_;
 
diff --git a/third_party/blink/renderer/modules/payments/payment_method_change_event.cc b/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
index 05f90cd1..1a3b8e6 100644
--- a/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
+++ b/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
@@ -47,7 +47,7 @@
                                 init),
       method_name_(init->methodName()) {
   if (init->hasMethodDetails()) {
-    method_details_.Set(init->methodDetails().GetIsolate(),
+    method_details_.Set(script_state->GetIsolate(),
                         init->methodDetails().V8Value());
   }
 }
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 295e9ce..8bae474 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -362,12 +362,13 @@
 }
 
 // Parses Android Pay data to avoid parsing JSON in the browser.
-void SetAndroidPayMethodData(const ScriptValue& input,
+void SetAndroidPayMethodData(v8::Isolate* isolate,
+                             const ScriptValue& input,
                              PaymentMethodDataPtr& output,
                              ExceptionState& exception_state) {
   AndroidPayMethodData* android_pay = AndroidPayMethodData::Create();
-  V8AndroidPayMethodData::ToImpl(input.GetIsolate(), input.V8Value(),
-                                 android_pay, exception_state);
+  V8AndroidPayMethodData::ToImpl(isolate, input.V8Value(), android_pay,
+                                 exception_state);
   if (exception_state.HadException())
     return;
 
@@ -416,7 +417,7 @@
   // data asynchronously. Do not throw exceptions here.
   if (supported_method == kGooglePayMethod ||
       supported_method == kAndroidPayMethod) {
-    SetAndroidPayMethodData(input, output, exception_state);
+    SetAndroidPayMethodData(isolate, input, output, exception_state);
     if (exception_state.HadException())
       exception_state.ClearException();
   }
@@ -621,7 +622,6 @@
           execution_context.GetIsolate(),
           payment_method_data->supportedMethod(), payment_method_data->data(),
           output.back(), exception_state);
-
       if (exception_state.HadException())
         continue;
 
@@ -982,7 +982,7 @@
   ExceptionState exception_state(v8::Isolate::GetCurrent(),
                                  ExceptionState::kConstructionContext,
                                  "PaymentDetailsUpdate");
-  V8PaymentDetailsUpdate::ToImpl(details_script_value.GetIsolate(),
+  V8PaymentDetailsUpdate::ToImpl(resolver->GetScriptState()->GetIsolate(),
                                  details_script_value.V8Value(), details,
                                  exception_state);
   if (exception_state.HadException()) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
index 405419f..4fff53a 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
@@ -106,9 +106,9 @@
 
   ~ExpectDOMException() override = default;
 
-  void operator()(ScriptState* state, ScriptValue value) const override {
+  void operator()(ScriptState* script_state, ScriptValue value) const override {
     DOMException* exception = V8DOMException::ToImplWithTypeCheck(
-        value.GetIsolate(), value.V8Value());
+        script_state->GetIsolate(), value.V8Value());
     EXPECT_TRUE(exception) << "the value should be a DOMException";
     if (!exception)
       return;
@@ -129,9 +129,9 @@
 
   ~ExpectTypeError() override = default;
 
-  void operator()(ScriptState* state, ScriptValue value) const override {
-    v8::Isolate* isolate = value.GetIsolate();
-    v8::Local<v8::Context> context = state->GetContext();
+  void operator()(ScriptState* script_state, ScriptValue value) const override {
+    v8::Isolate* isolate = script_state->GetIsolate();
+    v8::Local<v8::Context> context = script_state->GetContext();
     v8::Local<v8::Object> error_object =
         value.V8Value()->ToObject(context).ToLocalChecked();
     v8::Local<v8::Value> name =
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 4a4ae32e..d25c87dc 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -1083,8 +1083,8 @@
                           TRACE_ID_LOCAL(event_id)),
       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
   DCHECK(abort_payment_result_callbacks_.Contains(event_id));
-  payments::mojom::blink::PaymentHandlerResponseCallbackPtr result_callback =
-      abort_payment_result_callbacks_.Take(event_id);
+  mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>
+      result_callback = abort_payment_result_callbacks_.Take(event_id);
   result_callback->OnResponseForAbortPayment(payment_aborted);
 }
 
@@ -1113,8 +1113,8 @@
                           TRACE_ID_LOCAL(event_id)),
       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
   DCHECK(can_make_payment_result_callbacks_.Contains(event_id));
-  payments::mojom::blink::PaymentHandlerResponseCallbackPtr result_callback =
-      can_make_payment_result_callbacks_.Take(event_id);
+  mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>
+      result_callback = can_make_payment_result_callbacks_.Take(event_id);
   result_callback->OnResponseForCanMakePayment(can_make_payment);
 }
 
@@ -1143,8 +1143,8 @@
                           TRACE_ID_LOCAL(payment_event_id)),
       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
   DCHECK(payment_response_callbacks_.Contains(payment_event_id));
-  payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback =
-      payment_response_callbacks_.Take(payment_event_id);
+  mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>
+      response_callback = payment_response_callbacks_.Take(payment_event_id);
   response_callback->OnResponseForPaymentRequest(std::move(response));
 }
 
@@ -1801,13 +1801,17 @@
 }
 
 void ServiceWorkerGlobalScope::DispatchAbortPaymentEvent(
-    payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback,
+    mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback>
+        response_callback,
     DispatchAbortPaymentEventCallback callback) {
   DCHECK(IsContextThread());
   int event_id = timeout_timer_->StartEvent(
       CreateAbortCallback(&abort_payment_event_callbacks_));
   abort_payment_event_callbacks_.Set(event_id, std::move(callback));
-  abort_payment_result_callbacks_.Set(event_id, std::move(response_callback));
+  abort_payment_result_callbacks_.Set(
+      event_id,
+      mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>(
+          std::move(response_callback)));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchAbortPaymentEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -1830,14 +1834,17 @@
 
 void ServiceWorkerGlobalScope::DispatchCanMakePaymentEvent(
     payments::mojom::blink::CanMakePaymentEventDataPtr event_data,
-    payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback,
+    mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback>
+        response_callback,
     DispatchCanMakePaymentEventCallback callback) {
   DCHECK(IsContextThread());
   int event_id = timeout_timer_->StartEvent(
       CreateAbortCallback(&can_make_payment_event_callbacks_));
   can_make_payment_event_callbacks_.Set(event_id, std::move(callback));
-  can_make_payment_result_callbacks_.Set(event_id,
-                                         std::move(response_callback));
+  can_make_payment_result_callbacks_.Set(
+      event_id,
+      mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>(
+          std::move(response_callback)));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchCanMakePaymentEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -1862,13 +1869,17 @@
 
 void ServiceWorkerGlobalScope::DispatchPaymentRequestEvent(
     payments::mojom::blink::PaymentRequestEventDataPtr event_data,
-    payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback,
+    mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback>
+        response_callback,
     DispatchPaymentRequestEventCallback callback) {
   DCHECK(IsContextThread());
   int event_id = timeout_timer_->StartEvent(
       CreateAbortCallback(&payment_request_event_callbacks_));
   payment_request_event_callbacks_.Set(event_id, std::move(callback));
-  payment_response_callbacks_.Set(event_id, std::move(response_callback));
+  payment_response_callbacks_.Set(
+      event_id,
+      mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>(
+          std::move(response_callback)));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPaymentRequestEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index ea4ce27..daeae831 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -423,17 +423,20 @@
       base::TimeDelta timeout,
       DispatchPeriodicSyncEventCallback callback) override;
   void DispatchAbortPaymentEvent(
-      payments::mojom::blink::PaymentHandlerResponseCallbackPtr
+      mojo::PendingRemote<
+          payments::mojom::blink::PaymentHandlerResponseCallback>
           response_callback,
       DispatchAbortPaymentEventCallback callback) override;
   void DispatchCanMakePaymentEvent(
       payments::mojom::blink::CanMakePaymentEventDataPtr event_data,
-      payments::mojom::blink::PaymentHandlerResponseCallbackPtr
+      mojo::PendingRemote<
+          payments::mojom::blink::PaymentHandlerResponseCallback>
           response_callback,
       DispatchCanMakePaymentEventCallback callback) override;
   void DispatchPaymentRequestEvent(
       payments::mojom::blink::PaymentRequestEventDataPtr event_data,
-      payments::mojom::blink::PaymentHandlerResponseCallbackPtr
+      mojo::PendingRemote<
+          payments::mojom::blink::PaymentHandlerResponseCallback>
           response_callback,
       DispatchPaymentRequestEventCallback callback) override;
   void DispatchCookieChangeEvent(
@@ -493,7 +496,8 @@
   HashMap<int, DispatchSyncEventCallback> sync_event_callbacks_;
   HashMap<int, DispatchPeriodicSyncEventCallback>
       periodic_sync_event_callbacks_;
-  HashMap<int, payments::mojom::blink::PaymentHandlerResponseCallbackPtr>
+  HashMap<int,
+          mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>>
       abort_payment_result_callbacks_;
   HashMap<int, DispatchCanMakePaymentEventCallback>
       abort_payment_event_callbacks_;
@@ -517,9 +521,11 @@
   // Maps for response callbacks.
   // These are mapped from an event id to the Mojo interface pointer which is
   // passed from the relevant DispatchSomeEvent() method.
-  HashMap<int, payments::mojom::blink::PaymentHandlerResponseCallbackPtr>
+  HashMap<int,
+          mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>>
       can_make_payment_result_callbacks_;
-  HashMap<int, payments::mojom::blink::PaymentHandlerResponseCallbackPtr>
+  HashMap<int,
+          mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>>
       payment_response_callbacks_;
   HashMap<int, mojo::Remote<mojom::blink::ServiceWorkerFetchResponseCallback>>
       fetch_response_callbacks_;
diff --git a/third_party/blink/renderer/modules/wake_lock/README.md b/third_party/blink/renderer/modules/wake_lock/README.md
new file mode 100644
index 0000000..f30e0a38
--- /dev/null
+++ b/third_party/blink/renderer/modules/wake_lock/README.md
@@ -0,0 +1,133 @@
+# modules/wake_lock
+
+[TOC]
+
+This directory contains an implementation of the [Wake Lock specification], a Web API that allows script authors to prevent both the screen from turning off ("screen wake locks") as well as the CPU from entering a deep power state ("system wake locks"). There are platform implementations for ChromeOS, Linux (X11), Mac, Android, and Windows.
+
+At the time of writing (August 2019), system wake lock requests are always denied, as allowing them depends on a proper permission model for the requests being figured out first.
+
+The code required to implement the Wake Lock API is spread across multiple Chromium subsystems: Blink, `//content`, `//services` and `//chrome`. This document focuses on the Blink part, and the other subsystems are mentioned when necessary but without much detail.
+
+## High level overview
+
+Wake Lock's API surface is fairly small; the `WakeLock` IDL interface only has static methods, and there is no state that can be easily inspected. Additionally, all the parts that actually communicate with platform APIs are implemented elsewhere, so the Blink side only exposes the JavaScript API to script authors, validates API calls and manages [state records].
+
+The three main Blink classes implementing the spec are:
+
+* [`WakeLock`](wake_lock.h): implements the API bindings following the spec. Like its IDL counterpart, it only has static methods. Permission request and lock acquisition calls are all forwarded to `WakeLockController`.
+* [`WakeLockController`](wake_lock_controller.h): per-`ExecutionContext` class. It implements all permission management required by the spec, as well as the [Wake Lock management] tasks that apply to documents and/or workers (e.g. page visibility handling). Its `state_records_` array contains per-wake lock type `WakeLockStateRecord` instances, so all wake lock types are managed independently.
+* [`WakeLockStateRecord`](wake_lock_state_record.h): Owned by `WakeLockController`. This is an implementation of the [state records] Wake Lock concept in a per-type fashion. Like in the spec, it keeps track of all active locks of a certain type, and it is also responsible for communicating with the `//content` and `//services` layers to request and cancel wake locks.
+
+Furthermore, [`wake_lock.mojom`](../../../public/mojom/wake_lock/wake_lock.mojom) defines the Mojo interface implemented by `//content`'s [`WakeLockServiceImpl`](/content/browser/wake_lock/wake_lock_service_impl.h) that `WakeLockStateRecord` uses to obtain a [`device::mojom::blink::WakeLock`](/services/device/public/mojom/wake_lock.mojom) and request/cancel a wake lock.
+
+The rest of the implementation is found in the following directories:
+
+* `content/browser/wake_lock` [implements](/content/browser/wake_lock/wake_lock_service_impl.cc) the [`WakeLockService`](../../../public/mojom/wake_lock/wake_lock.mojom) Mojo interface defined in Blink. It is responsible for communicating with Blink and connecting Blink to `services/device/wake_lock`.
+* `services/device/wake_lock` contains the [platform-specific parts of the implementation](../../../../../services/device/wake_lock/power_save_blocker) and implements the Wake Lock [Mojo interfaces].
+* `chrome/browser/wake_lock` contains the Chrome-specific side of permission management for Wake Locks. When the Blink implementation needs to either query or request permission for wake locks, the request bubbles up to this directory, where the decision is made based on the wake lock type (for testing purposes, `content_shell` always grants screen wake locks and denies system wake locks in [`shell_permission_manager.cc`](/content/shell/browser/web_test/web_test_message_filter.cc)).
+
+[Mojo interfaces]: ../../../../../services/device/public/mojom/
+[Wake Lock management]: https://w3c.github.io/wake-lock/#managing-wake-locks
+[Wake Lock specification]: https://w3c.github.io/wake-lock/
+[state records]: https://w3c.github.io/wake-lock/#dfn-state-record
+
+### Testing
+
+Validation, exception types, feature policy integration and general IDL compliance are tested in [web platform tests], while Chromium-specific implementation details (e.g. permission handling) are tested in [web tests].
+
+Larger parts of the Blink implementation are tested as browser and unit tests:
+
+* `*_test.cc` and `wake_lock_test_utils.{cc,h}` are built as part of the `blink_unittests` GN target, and attempt to have coverage over most of the code in this directory.
+* The unit tests in `services/device/wake_lock` test the service side of the API implementation.
+* `chrome/browser/wake_lock` has unit tests for `WakeLockPermissionContext`, and browser tests for end-to-end behavior testing.
+* content_shell implements its own permission logic that mimics what is done in `//chrome` in [`shell_permission_manager.cc`](/content/shell/browser/shell_permission_manager.cc).
+
+[web platform tests]: ../../../web_tests/external/wpt/wake-lock/
+[web tests]: ../../../web_tests/wake-lock/
+
+## Example workflows
+
+### Wake Lock acquisition
+
+This section describes how the classes described above interact when the following excerpt is run in the browser:
+
+``` javascript
+const abortController = new AbortController();
+const lockPromise = WakeLock.request("screen", { signal: abortController.signal });
+```
+
+1. `WakeLock::request()` performs all the validation steps described in [the spec](https://w3c.github.io/wake-lock/#request-static-method).
+1. Since an [AbortSignal] was passed in the JavaScript call, `WakeLock::request()` will call [`AbortSignal::AddAlgorithm()`](../../core/dom/abort_signal.h) and add `WakeLockController::ReleaseWakeLock()` to its list of algorithms [n.b. see below the section below for what happens if `abortController.abort()` is called].
+1. If all checks have passed, it calls `WakeLockController::From()` to either create or obtain a `WakeLockController` attached to the given execution context (i.e. a `Document` or `DedicatedWorkerGlobalScope`).
+1. `WakeLockController::RequestWakeLock()` is called, and `WakeLock::request()` then returns a promise. `RequestWakeLock()` is a small method that just verifies some invariants and calls `WakeLockController::ObtainPermission()`.
+1. `WakeLockController::ObtainPermission()` connects to the [permission service](../../../public/mojom/permissions/permission.mojom) and asynchronously requests permission for a screen wake lock.
+1. In the browser process, the permission request bubbles up through `//content` and reaches `//chrome`'s [`WakeLockPermissionContext`](/chrome/browser/wake_lock/wake_lock_permission_context.cc), where `WakeLockPermissionContext::GetPermissionStatusInternal()` always grants `CONTENT_SETTINGS_TYPE_WAKE_LOCK_SCREEN` permission requests.
+1. Back in Blink, the permission request callback in this case is `WakeLockController::DidReceivePermissionResponse()`. It performs some sanity checks such as verifying the wake lock's corresponding [AbortSignal] has not been triggered. If any of the checks fail, the `ScriptPromiseResolver` instance created earlier by `WakeLock::request()` is rejected and we stop here. If everything went well, calls `WakeLockController::AcquireWakeLock()`.
+1. `WakeLockController::AcquireWakeLock()` is a wrapper that invokes `WakeLockStateRecord::AcquireWakeLock()`.
+1. If there are no existing screen wake locks, `WakeLockStateRecord::AcquireWakeLock()` will connect to the `WakeLockService` Mojo interface, invoke its `GetWakeLock()` method to obtain a `device::mojom::blink::WakeLock` and call its `RequestWakeLock()` method.
+1. Otherwise, if there is at least one existing screen lock, `WakeLockStateRecord::AcquireWakeLock()` will simply add the `ScriptPromiseResolver` to its set of [active locks].
+
+[AbortSignal]: https://dom.spec.whatwg.org/#interface-AbortSignal
+[active locks]: https://w3c.github.io/wake-lock/#dfn-activelocks
+
+### Wake Lock cancellation
+
+Given the excerpt below:
+
+``` javascript
+const abortController = new AbortController();
+const lockPromise = WakeLock.request("screen", { signal: abortController.signal });
+abortController.abort();
+```
+
+This section describes what happens when `abortController.abort()` is called.
+
+1. `abortController.abort()` causes `AbortSignal` to go through its list of algorithms, and `WakeLockController::ReleaseWakeLock()` is eventually called.
+1. `WakeLockController::ReleaseWakeLock()` itself is a small function that simply calls `WakeLockStateRecord::ReleaseWakeLock()`.
+1. `WakeLockStateRecord::ReleaseWakeLock()` implements the spec's [release wake lock algorithm]. One interesting aspect is that it rejects any `ScriptPromiseResolver` passed to it, even if it is not in its active locks list. This is caused by the fact that `WakeLock.request()` contains parallel steps, and script authors have access to the promise it returns before a lock has actually been requested and added to `WakeLockStateRecord`'s active locks list.
+1. If the given wake lock is in `WakeLockStateRecord`'s `active_locks_`, it will be removed and, if the list is empty, `WakeLockStateRecord` will communicate with its `device::mojom::blink::WakeLock` instance and call its `CancelWakeLock()` method.
+
+[release wake lock algorithm]: https://w3c.github.io/wake-lock/#release-wake-lock-algorithm
+
+## Other Wake Lock usage in Chromium
+
+### Inside Blink
+
+Video playback via the `<video>` tag currently uses a screen wake lock behind the scenes to prevent the screen from turning off while a video is being played. The implementation can be found in the [`VideoWakeLock`](../../core/html/media/video_wake_lock.h) class.
+
+This is an implementation detail, but the code handling wake locks in `VideoWakeLock` is similar to `WakeLockStateRecord`'s, where Blink needs to talk to `//content` to connect to a `WakeLockServiceImpl` and use that to get to a `device::mojom::blink::WakeLock`.
+
+**Note:** when writing new code that uses Wake Locks in Blink, it is recommended to follow the same pattern outlined above. That is, connect to `WakeLockService` via the `//content` layer and request a `device::mojom::blink::WakeLock` via `WakeLockService::GetWakeLock()`. Do not go through the classes in this module, and [**do not connect to the Wake Lock services directly**](/docs/servicification.md#Frame-Scoped-Connections). See the example below:
+
+```c++
+mojo::Remote<mojom::blink::WakeLockService> wake_lock_service;
+device::mojom::blink::WakeLockPtr wake_lock;
+execution_context->GetInterface(wake_lock_service.BindNewPipeAndPassReceiver());
+wake_lock_service->GetWakeLock(..., mojo::MakeRequest(&wake_lock));
+wake_lock_->RequestWakeLock();
+```
+
+### Outside Blink
+
+The [Wake Lock service](/services/device/wake_lock) is also used by multiple parts of Chromium outside Blink. In other words, it is possible to use the Wake Lock service and prevent screen and CPU from entering a deep power state directly from the browser side.
+
+In fact, this is why [`WakeLockProvider::GetWakeLockWithoutContext()`](/services/device/public/mojom/wake_lock_provider.mojom) exists in the first place. One consequence is that one needs to bear in mind these other usages when changing the public API exposed by the Wake Lock service.
+
+**Note:** Avoid using `WakeLockProvider::GetWakeLockWithoutContext()` whenever possible. By design, it does not work on Android.
+
+Example usage outside Blink includes:
+
+* ChromeOS's [encryption migration screen handler](/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc)
+* Media capture code in [content/browser](/content/browser/media/capture/desktop_capture_device.cc)
+* The Google Drive [component](/components/drive/drive_uploader.cc)
+* The `chrome.power` [extension API](/extensions/browser/api/power/power_api.cc)
+
+## Permission Model
+
+The Wake Lock API spec checks for user activation in the context of [wake lock permission requests](https://w3c.github.io/wake-lock/#dfn-obtain-permission), either as a result of a call to either `WakeLock.requestPermission()` or `WakeLock.request()`. If a user agent is configured to prompt a user when a wake lock is requested, user activation is required, otherwise the request will be denied.
+
+In the Chromium implementation, there currently is no "prompt" state, and no permission UI or settings: wake lock requests are either always granted or always denied:
+
+* Screen wake lock request are always granted without prompting or user activation checks. This is based on the existing precedent of the `<video>` tag's use of `VideoWakeLock`s: they are always requested and granted transparently, so even if the Wake Lock API implementation in Chromium started requiring stricter checks, malicious actors could still embed a `<video>` tag and prevent the screen from turning off without any user interaction.
+
+* System wake lock requests are always denied in `chrome/browser/wake_lock/wake_lock_permission_context.cc`. This means the entirety of the code is present and enabled in Blink, but all calls to `WakeLock.request('system')` currently return a promise that will be rejected with a `NotAllowedError`. Changing that requires figuring out a permission model for system wake lock requests, which, at the moment, is future work.
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index d2fcb71..701e902 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1239,9 +1239,11 @@
     "peerconnection/rtc_video_decoder_adapter.cc",
     "peerconnection/rtc_video_decoder_adapter.h",
     "peerconnection/rtc_video_decoder_factory.cc",
+    "peerconnection/rtc_video_decoder_factory.h",
     "peerconnection/rtc_video_encoder.cc",
     "peerconnection/rtc_video_encoder.h",
     "peerconnection/rtc_video_encoder_factory.cc",
+    "peerconnection/rtc_video_encoder_factory.h",
     "peerconnection/rtc_void_request.h",
     "peerconnection/webrtc_audio_sink.cc",
     "peerconnection/webrtc_video_track_source.cc",
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
index 9c7aedc..ba2a0ab10 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h"
 
 #include <memory>
 
@@ -10,6 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "media/video/gpu_video_accelerator_factories.h"
+#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory_util.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h"
 
 namespace blink {
@@ -58,6 +59,11 @@
 
 }  // namespace
 
+std::unique_ptr<webrtc::VideoDecoderFactory> CreateRTCVideoDecoderFactory(
+    media::GpuVideoAcceleratorFactories* gpu_factories) {
+  return std::make_unique<RTCVideoDecoderFactory>(gpu_factories);
+}
+
 RTCVideoDecoderFactory::RTCVideoDecoderFactory(
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : gpu_factories_(gpu_factories) {
diff --git a/third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory.h b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h
similarity index 65%
rename from third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory.h
rename to third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h
index 54e9bf7..ff639c4 100644
--- a/third_party/blink/public/platform/modules/peerconnection/rtc_video_decoder_factory.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_H_
 
 #include "base/macros.h"
-#include "third_party/blink/public/platform/web_common.h"
 #include "third_party/webrtc/api/video_codecs/video_decoder_factory.h"
 #include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h"
 
@@ -21,11 +20,7 @@
 namespace blink {
 
 // TODO(wuchengli): add unittest.
-//
-// TODO(crbug.com/787254): Move this class out of the Blink exposed API when its
-// clients get Onion soup'ed. Also, switch away from using std::vector.
-class BLINK_PLATFORM_EXPORT RTCVideoDecoderFactory
-    : public webrtc::VideoDecoderFactory {
+class RTCVideoDecoderFactory : public webrtc::VideoDecoderFactory {
  public:
   explicit RTCVideoDecoderFactory(
       media::GpuVideoAcceleratorFactories* gpu_factories);
@@ -46,4 +41,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_FACTORY_H_
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index 30f76ab..0e5c1612 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -29,7 +29,6 @@
 #include "media/video/h264_parser.h"
 #include "media/video/video_encode_accelerator.h"
 #include "mojo/public/cpp/base/shared_memory_utils.h"
-#include "third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -884,12 +883,6 @@
   UseOutputBitstreamBufferId(bitstream_buffer_id);
 }
 
-std::unique_ptr<webrtc::VideoEncoder> CreateRTCVideoEncoder(
-    media::VideoCodecProfile profile,
-    media::GpuVideoAcceleratorFactories* gpu_factories) {
-  return std::make_unique<RTCVideoEncoder>(profile, gpu_factories);
-}
-
 RTCVideoEncoder::RTCVideoEncoder(
     media::VideoCodecProfile profile,
     media::GpuVideoAcceleratorFactories* gpu_factories)
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.cc
index 05253dc..a0943b8 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.h"
 
 #include <memory>
 
@@ -11,7 +11,8 @@
 #include "media/media_buildflags.h"
 #include "media/video/gpu_video_accelerator_factories.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/platform/modules/peerconnection/web_rtc_video_encoder_factory.h"
+#include "third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory_util.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h"
 #include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
 #include "third_party/webrtc/api/video_codecs/video_encoder.h"
 #include "third_party/webrtc/common_video/h264/profile_level_id.h"
@@ -103,6 +104,11 @@
 
 }  // anonymous namespace
 
+std::unique_ptr<webrtc::VideoEncoderFactory> CreateRTCVideoEncoderFactory(
+    media::GpuVideoAcceleratorFactories* gpu_factories) {
+  return std::make_unique<RTCVideoEncoderFactory>(gpu_factories);
+}
+
 RTCVideoEncoderFactory::RTCVideoEncoderFactory(
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : gpu_factories_(gpu_factories) {
@@ -124,7 +130,7 @@
     const webrtc::SdpVideoFormat& format) {
   for (size_t i = 0; i < supported_formats_.size(); ++i) {
     if (IsSameFormat(format, supported_formats_[i])) {
-      return blink::CreateRTCVideoEncoder(profiles_[i], gpu_factories_);
+      return std::make_unique<RTCVideoEncoder>(profiles_[i], gpu_factories_);
     }
   }
   return nullptr;
diff --git a/third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory.h b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.h
similarity index 72%
rename from third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory.h
rename to third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.h
index 8dc853c8..0623609 100644
--- a/third_party/blink/public/platform/modules/peerconnection/rtc_video_encoder_factory.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory.h
@@ -2,15 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_H_
 
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "media/base/video_codecs.h"
-#include "third_party/blink/public/platform/web_common.h"
 #include "third_party/webrtc/api/video_codecs/video_encoder_factory.h"
 
 namespace media {
@@ -21,11 +20,7 @@
 
 // This class creates RTCVideoEncoder instances (each wrapping a
 // media::VideoEncodeAccelerator) on behalf of the WebRTC stack.
-//
-// TODO(crbug.com/787254): Move this class out of the Blink exposed API
-// when all users of it have been Onion souped.
-class BLINK_PLATFORM_EXPORT RTCVideoEncoderFactory
-    : public webrtc::VideoEncoderFactory {
+class RTCVideoEncoderFactory : public webrtc::VideoEncoderFactory {
  public:
   explicit RTCVideoEncoderFactory(
       media::GpuVideoAcceleratorFactories* gpu_factories);
@@ -52,4 +47,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_ENCODER_FACTORY_H_
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
index e0072930..56ecedc 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -101,7 +101,6 @@
   // accessed only on the main thread.
   DCHECK(IsMainThread());
 
-  base::PartitionAllocMemoryReclaimer::Instance()->DeprecatedReclaim();
   FastMallocPartition()->DumpStats("fast_malloc", is_light_dump,
                                    partition_stats_dumper);
   ArrayBufferPartition()->DumpStats("array_buffer", is_light_dump,
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.h b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
index 33c6bd7b..830fa61 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.h
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
@@ -34,7 +34,6 @@
 #include <string.h>
 #include <memory>
 
-#include "base/allocator/partition_allocator/memory_reclaimer.h"
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
diff --git a/third_party/blink/renderer/platform/wtf/decimal.cc b/third_party/blink/renderer/platform/wtf/decimal.cc
index abc86ec..c6d881d 100644
--- a/third_party/blink/renderer/platform/wtf/decimal.cc
+++ b/third_party/blink/renderer/platform/wtf/decimal.cc
@@ -787,6 +787,7 @@
         }
 
         HandleCharAndBreak('0', kStateZero);
+        HandleCharAndBreak('.', kStateDot);
         return Nan();
 
       case kStateStart:
diff --git a/third_party/blink/renderer/platform/wtf/decimal_test.cc b/third_party/blink/renderer/platform/wtf/decimal_test.cc
index 62a3468..3c10d0e 100644
--- a/third_party/blink/renderer/platform/wtf/decimal_test.cc
+++ b/third_party/blink/renderer/platform/wtf/decimal_test.cc
@@ -668,6 +668,8 @@
   EXPECT_EQ(Encode(3, 0, kPositive), FromString("+3"));
   EXPECT_EQ(Encode(0, 3, kPositive), FromString("0E3"));
   EXPECT_EQ(Encode(5, -1, kPositive), FromString(".5"));
+  EXPECT_EQ(Encode(5, -1, kPositive), FromString("+.5"));
+  EXPECT_EQ(Encode(5, -1, kNegative), FromString("-.5"));
   EXPECT_EQ(Encode(100, 0, kPositive), FromString("100"));
   EXPECT_EQ(Encode(100, 0, kNegative), FromString("-100"));
   EXPECT_EQ(Encode(123, -2, kPositive), FromString("1.23"));
diff --git a/third_party/blink/web_tests/ASANExpectations b/third_party/blink/web_tests/ASANExpectations
index e8a7c2dd..b7bd39f 100644
--- a/third_party/blink/web_tests/ASANExpectations
+++ b/third_party/blink/web_tests/ASANExpectations
@@ -57,7 +57,6 @@
 crbug.com/464065 [ Linux ] media/track/css-cue-for-video-in-shadow-2.html [ Timeout ]
 crbug.com/572723 [ Linux ] http/tests/devtools/sources/debugger/debugger-completions-on-call-frame.js [ Timeout Pass ]
 crbug.com/700795 [ Linux ] http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Skip ]
-crbug.com/928941 [ Linux ] external/wpt/background-fetch/fetch.https.window.html [ Timeout ]
 
 # Intentionally failed allocations, via partitionAllocGenericFlags()
 crbug.com/577889 [ Linux ] fast/js/typed-array-allocation-failure.html [ Crash ]
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index d7d76ba1..9a55f9d2 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -91,9 +91,19 @@
 crbug.com/996235 [ Linux ] media/controls/doubletap-to-jump-backwards-at-start.html [ Pass Leak ]
 crbug.com/996235 [ Linux ] virtual/audio-service/media/controls/doubletap-to-jump-backwards-at-start.html [ Pass Leak ]
 
-crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/elements/event-listeners-a11y-test.js [ Leak ]
-crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js  [ Leak ]
-crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/sources/source-navigator-filesystem-a11y-test.js [ Leak ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/application-panel/app-manifest-view-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/audits-start-view-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/basic-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/console-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/devices-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/elements/event-listeners-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/memory/heap-profiler-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/network/network-condition-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js  [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/sources/source-navigator-filesystem-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/settings/geolocations-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/sources/source-navigator-network-a11y-test.js [ Leak Pass ]
+crbug.com/1000512 [ Linux ] http/tests/devtools/a11y-axe-core/sources/sources-editor-pane-a11y-test.js [ Leak Pass ]
 
 ###########################################################################
 # WARNING: Memory leaks must be fixed asap. Sheriff is expected to revert #
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index 5aa1c1f..9a855dc 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -192,14 +192,6 @@
 crbug.com/856601 [ Linux ] external/wpt/wake-lock/idlharness.https.any.worker.html [ Pass Timeout ]
 crbug.com/856601 [ Linux ] virtual/omt-worker-fetch/external/wpt/fetch/api/idl.any.sharedworker.html [ Pass Timeout ]
 
-# background-fetch tests crash on MSAN
-crbug.com/869818 [ Linux ] external/wpt/background-fetch/fetch.https.window.html [ Pass Crash ]
-crbug.com/869818 [ Linux ] external/wpt/background-fetch/get-ids.https.window.html [ Pass Crash ]
-crbug.com/869818 [ Linux ] external/wpt/background-fetch/get.https.window.html [ Pass Crash ]
-crbug.com/869818 [ Linux ] external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.html [ Pass Crash ]
-crbug.com/869818 [ Linux ] external/wpt/background-fetch/port-blocking.https.window.html [ Pass Crash ]
-crbug.com/869818 [ Linux ] http/tests/background_fetch/block-cors-preflights.https.html [ Pass Crash ]
-
 # Disabled by sheriff due to repeated flakes
 crbug.com/873045 [ Linux ] external/wpt/WebCryptoAPI/idlharness.https.any.worker.html [ Pass Failure Timeout ]
 crbug.com/873045 [ Linux ] external/wpt/picture-in-picture/idlharness.window.html [ Pass Failure Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b4acc15..1c2d89c2 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2987,9 +2987,11 @@
 # non-deterministic order.
 crbug.com/705125 fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html [ Failure ]
 
-# Skip the non-virtualized CORS-RFC1918 tests:
-crbug.com/763830 http/tests/security/cors-rfc1918/ [ Skip ]
-crbug.com/763830 virtual/blink-cors/http/tests/security/cors-rfc1918/ [ Skip ]
+# Skip the non-virtualized CORS-RFC1918 blocking tests (`.addressSpace` tests are fine):
+crbug.com/763830 http/tests/security/cors-rfc1918/external-to-internal-fetch.php [ Skip ]
+crbug.com/763830 http/tests/security/cors-rfc1918/external-to-internal-xhr.php [ Skip ]
+crbug.com/763830 virtual/blink-cors/http/tests/security/cors-rfc1918/external-to-internal-fetch.php [ Skip ]
+crbug.com/763830 virtual/blink-cors/http/tests/security/cors-rfc1918/external-to-internal-xhr.php [ Skip ]
 
 crbug.com/831729 external/wpt/event-timing/crossiframe.html [ Timeout ]
 crbug.com/831729 external/wpt/event-timing/observer-manual.html [ Skip ]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations
index 138e0849..f462ea6 100644
--- a/third_party/blink/web_tests/WPTOverrideExpectations
+++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -99,16 +99,6 @@
 crbug.com/lpz external/wpt/animation-worklet/worklet-animation-creation.https.html [ Failure ]
 crbug.com/lpz external/wpt/animation-worklet/worklet-animation-with-effects-from-different-frames.https.html [ Failure ]
 crbug.com/lpz external/wpt/audio-output/setSinkId.https.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/abort.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/fetch-uploads.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/fetch.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/get-ids.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/get.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/idlharness.https.any.serviceworker.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/match.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/port-blocking.https.window.html [ Failure ]
-crbug.com/lpz external/wpt/background-fetch/update-ui.https.window.html [ Failure ]
 crbug.com/lpz external/wpt/battery-status/battery-iframe.https.html [ Failure ]
 crbug.com/lpz external/wpt/battery-status/battery-insecure-context.html [ Failure ]
 crbug.com/lpz external/wpt/beacon/beacon-basic-blob.html [ Failure ]
diff --git a/third_party/blink/web_tests/device_orientation/motion/add-during-dispatch.html b/third_party/blink/web_tests/device_orientation/motion/add-during-dispatch.html
index 768114c..9aee041 100644
--- a/third_party/blink/web_tests/device_orientation/motion/add-during-dispatch.html
+++ b/third_party/blink/web_tests/device_orientation/motion/add-during-dispatch.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const motionData = generateMotionData(1, 2, 3,
                                         4, 5, 6,
                                         7, 8, 9);
diff --git a/third_party/blink/web_tests/device_orientation/motion/add-listener-from-callback.html b/third_party/blink/web_tests/device_orientation/motion/add-listener-from-callback.html
index d136f08e5..f92d4a8 100644
--- a/third_party/blink/web_tests/device_orientation/motion/add-listener-from-callback.html
+++ b/third_party/blink/web_tests/device_orientation/motion/add-listener-from-callback.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const motionData = generateMotionData(1.1, 2.1, 3.1,
                                         1.2, 2.2, 3.2,
                                         1.3, 2.3, 3.3);
diff --git a/third_party/blink/web_tests/device_orientation/motion/multiple-event-listeners.html b/third_party/blink/web_tests/device_orientation/motion/multiple-event-listeners.html
index 11c507a7..e5177f8 100644
--- a/third_party/blink/web_tests/device_orientation/motion/multiple-event-listeners.html
+++ b/third_party/blink/web_tests/device_orientation/motion/multiple-event-listeners.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const motionData1 = generateMotionData(1, 2, 3,
                                          4, 5, 6,
                                          7, 8, 9);
diff --git a/third_party/blink/web_tests/device_orientation/motion/null-values.html b/third_party/blink/web_tests/device_orientation/motion/null-values.html
index a29b810..eb563958 100644
--- a/third_party/blink/web_tests/device_orientation/motion/null-values.html
+++ b/third_party/blink/web_tests/device_orientation/motion/null-values.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const motionData1 = generateMotionData(1, 2, 3,
                                          null, null, null,
                                          null, null, null);
diff --git a/third_party/blink/web_tests/device_orientation/motion/page-visibility.html b/third_party/blink/web_tests/device_orientation/motion/page-visibility.html
index 7b60d3f9..233d673 100644
--- a/third_party/blink/web_tests/device_orientation/motion/page-visibility.html
+++ b/third_party/blink/web_tests/device_orientation/motion/page-visibility.html
@@ -14,7 +14,7 @@
   return new Promise(resolve => window.setTimeout(resolve, time_ms));
 }
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const motionData = generateMotionData(0, 0, 0,
                                         0, 0, 0,
                                         0, 0, 0);
diff --git a/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html b/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
index 7da9b4b..b1b9863 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData = generateOrientationData(1.1, 2.2, 3.3, true);
 
   // Make the relative orientation sensor unavailable and set mock data for
diff --git a/third_party/blink/web_tests/device_orientation/orientation/add-listener-from-callback.html b/third_party/blink/web_tests/device_orientation/orientation/add-listener-from-callback.html
index 6481f5aa..6c485379 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/add-listener-from-callback.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/add-listener-from-callback.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData = generateOrientationData(1.1, 2.2, 3.3, false);
 
   let firstListener = null;
diff --git a/third_party/blink/web_tests/device_orientation/orientation/basic-operation-absolute.html b/third_party/blink/web_tests/device_orientation/orientation/basic-operation-absolute.html
index c81f8478..bff0931 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/basic-operation-absolute.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/basic-operation-absolute.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData = generateOrientationData(1.1, 2.2, 3.3, true);
 
   setMockOrientationData(sensorProvider, orientationData);
diff --git a/third_party/blink/web_tests/device_orientation/orientation/basic-operation.html b/third_party/blink/web_tests/device_orientation/orientation/basic-operation.html
index 5dc8064..533a1284 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/basic-operation.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/basic-operation.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData = generateOrientationData(1.1, 2.2, 3.3, false);
 
   setMockOrientationData(sensorProvider, orientationData);
diff --git a/third_party/blink/web_tests/device_orientation/orientation/multiple-event-listeners.html b/third_party/blink/web_tests/device_orientation/orientation/multiple-event-listeners.html
index b3ac43b..10d23660 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/multiple-event-listeners.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/multiple-event-listeners.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData1 = generateOrientationData(1, 2, 3, false);
   const orientationData2 = generateOrientationData(11, 12, 13, false);
 
diff --git a/third_party/blink/web_tests/device_orientation/orientation/no-synchronous-events.html b/third_party/blink/web_tests/device_orientation/orientation/no-synchronous-events.html
index b18efda..d57b1c9 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/no-synchronous-events.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/no-synchronous-events.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   var orientationData = generateOrientationData(1.1, 2.2, 3.3, false);
 
   let setMockDataPromise = setMockOrientationData(sensorProvider, orientationData);
diff --git a/third_party/blink/web_tests/device_orientation/orientation/null-values.html b/third_party/blink/web_tests/device_orientation/orientation/null-values.html
index a2adc33..ec8dfab 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/null-values.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/null-values.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData1 = generateOrientationData(1.1, null, null, false);
   const orientationData2 = generateOrientationData(null, 2.2, null, false);
   const orientationData3 = generateOrientationData(null, null, 3.3, false);
diff --git a/third_party/blink/web_tests/device_orientation/orientation/page-visibility.html b/third_party/blink/web_tests/device_orientation/orientation/page-visibility.html
index 595fe31..7cb614fb 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/page-visibility.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/page-visibility.html
@@ -14,7 +14,7 @@
   return new Promise(resolve => window.setTimeout(resolve, time_ms));
 }
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData = generateOrientationData(1, 2, 3, false);
 
   setMockOrientationData(sensorProvider, orientationData);
diff --git a/third_party/blink/web_tests/device_orientation/orientation/updates.html b/third_party/blink/web_tests/device_orientation/orientation/updates.html
index d814f75..ba06a6a 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/updates.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/updates.html
@@ -10,7 +10,7 @@
 <script>
 'use strict';
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const orientationData1 = generateOrientationData(1.1, 2.2, 3.3, false);
   const orientationData2 = generateOrientationData(11.1, 22.2, 33.3, false);
 
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html
index ca423ef..fedf2ea 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html
@@ -106,7 +106,8 @@
         {conditions: {max: "5", value: "1abc"}, expected: false, name: "[target] The value is not a number"},
         {conditions: {max: "5", value: "6"}, expected: true, name: "[target] The value is greater than max(integer)"},
         {conditions: {max: "-5.5", value: "-5.4"}, expected: true, name: "[target] The value is greater than max(floating number)"},
-        {conditions: {max: "-5e-1", value: "5e+2"}, expected: true, name: "[target] The value is greater than max(scientific notation)"}
+        {conditions: {max: "-1", value: "-.8"}, expected: true, name: "[target] The value is greater than max(special floating number)"},
+        {conditions: {max: "-5e-1", value: "5e+2"}, expected: true, name: "[target] The value is greater than max(scientific notation)"},
       ]
     }
    ];
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeUnderflow.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeUnderflow.html
index d6bf860..8ac3aae1 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeUnderflow.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-rangeUnderflow.html
@@ -104,6 +104,7 @@
         {conditions: {min: "5", value: "6abc"}, expected: false, name: "[target] The value is not a number"},
         {conditions: {min: "6", value: "5"}, expected: true, name: "[target] The value is less than min(integer)"},
         {conditions: {min: "-5.4", value: "-5.5"}, expected: true, name: "[target] The value is less than min(floating number)"},
+        {conditions: {min: "1", value: "-.8"}, expected: true, name: "[target] The value is less than min(special floating number)"},
         {conditions: {min: "5e+2", value: "-5e-1"}, expected: true, name: "[target] The value is less than min(scientific notation)"}
       ]
     }
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-stepMismatch.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-stepMismatch.html
index 174ecaf..6d8192b 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-stepMismatch.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-stepMismatch.html
@@ -66,7 +66,8 @@
       types: ["number"],
       testData: [
         {conditions: {step: "", value: "1"}, expected: false, name: "[target] The step attribute is not set"},
-        {conditions: {step: 2 * 1 * 1, value: ""}, expected: false, name: "[target] The value attibute is empty string"},
+        {conditions: {step: "", value: "-.8"}, expected: true, name: "[target] The step attribute is not set and the value attribute is a floating number"},
+        {conditions: {step: 2 * 1 * 1, value: ""}, expected: false, name: "[target] The value attribute is empty string"},
         {conditions: {step: 2 * 1 * 1, value: "2"}, expected: false, name: "[target] The value must match the step"},
         {conditions: {step: 2 * 1 * 1, value: "3"}, expected: true, name: "[target] The value must mismatch the step"}
       ]
diff --git a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow-expected.txt b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow-expected.txt
index bf81e60..c1c7af44 100644
--- a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow-expected.txt
@@ -15,6 +15,7 @@
 PASS The value "101" overflows the maximum value "100".
 PASS The value "-99" overflows the maximum value "-100".
 PASS The value "101" overflows the maximum value "1E+2".
+PASS The value "-.8" overflows the maximum value "-1".
 PASS The value "101" overflows the maximum value "100".
 PASS The value "101" doesn't overflow the maximum value "1E+2" when disabled.
 PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow.html b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow.html
index 2d0f7f74..2d67197 100644
--- a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow.html
+++ b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeoverflow.html
@@ -57,6 +57,8 @@
 checkOverflow('101', '100');
 checkOverflow('-99', '-100');
 checkOverflow('101', '1E+2');
+input.min = '-2';
+checkOverflow('-.8', '-1');
 input.min = '200';  // value < min && value > max
 checkOverflow('101', '100');
 
diff --git a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow-expected.txt b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow-expected.txt
index 784a80f..f88fe69 100644
--- a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow-expected.txt
@@ -16,6 +16,7 @@
 PASS The value "-101" undeflows the minimum value "-100".
 PASS The value "99" undeflows the minimum value "1E+2".
 PASS The value "101" undeflows the minimum value "200".
+PASS The value "-.8" undeflows the minimum value "1".
 PASS The value "99" doesn't underflow the minimum value "1E+2" when disabled.
 PASS successfullyParsed is true
 
diff --git a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow.html b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow.html
index 0e33875e..0e04f56 100644
--- a/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow.html
+++ b/third_party/blink/web_tests/fast/forms/number/number-validity-rangeunderflow.html
@@ -61,6 +61,7 @@
 checkUnderflow('99', '1E+2');
 input.max = '100';  // value < min && value > max
 checkUnderflow('101', '200');
+checkUnderflow('-.8', '1');
 
 // Disabled
 checkNotUnderflow('99', '1E+2', true);
diff --git a/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch-expected.txt b/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch-expected.txt
index f9ea8a96..eaa68ad0 100644
--- a/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch-expected.txt
@@ -27,6 +27,7 @@
 PASS stepMismatchFor("0.9", "0.1000001", "") is true
 PASS stepMismatchFor("0.9", "0.1000000000000001", "") is false
 PASS stepMismatchFor("1.0", "0.3333333333333333", "") is false
+PASS stepMismatchFor("-.8", null, "-1") is true
 Rounding
 PASS stepMismatchFor("5.005", "0.005", "4") is false
 Disabled
diff --git a/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch.html b/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch.html
index 2e72bd6..136dfe04 100644
--- a/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch.html
+++ b/third_party/blink/web_tests/fast/forms/number/number-validity-stepmismatch.html
@@ -45,6 +45,7 @@
 shouldBe('stepMismatchFor("0.9", "0.1000001", "")', 'true');
 shouldBe('stepMismatchFor("0.9", "0.1000000000000001", "")', 'false');
 shouldBe('stepMismatchFor("1.0", "0.3333333333333333", "")', 'false');
+shouldBe('stepMismatchFor("-.8", null, "-1")', 'true');
 debug('Rounding');
 shouldBe('stepMismatchFor("5.005", "0.005", "4")', 'false');
 debug('Disabled');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js
index 789d57d..39818fb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js
@@ -7,7 +7,7 @@
   await TestRunner.loadModule('coverage_test_runner');
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   const report = JSON.parse(await CoverageTestRunner.exportReport());
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js
index a61a401..586983e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js
@@ -11,21 +11,21 @@
     `);
   await TestRunner.addStylesheetTag('resources/highlight-in-source.css');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.addScriptTag('resources/coverage.js');
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   TestRunner.addResult('Initial');
   CoverageTestRunner.dumpCoverageListView();
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await CoverageTestRunner.stopCoverage();
   TestRunner.addResult('After second session');
   CoverageTestRunner.dumpCoverageListView();
 
   var coverageView = self.runtime.sharedInstance(Coverage.CoverageView);
   coverageView._clear();
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await CoverageTestRunner.stopCoverage();
   TestRunner.addResult('After clear');
   CoverageTestRunner.dumpCoverageListView();
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js
index 9b93a305..e8e8017 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js
@@ -6,7 +6,7 @@
   TestRunner.addResult(`Tests the filter is properly applied to coverage list view.\n`);
   await TestRunner.loadModule('coverage_test_runner');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js
index 976ee74..1dcbc71a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js
@@ -8,7 +8,7 @@
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
 
   await TestRunner.evaluateInPagePromise('performActions()');
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await CoverageTestRunner.pollCoverage();
   CoverageTestRunner.dumpCoverageListView();
   TestRunner.addResult('Reloading Page');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/decorations-after-script-formatter.js b/third_party/blink/web_tests/http/tests/devtools/coverage/decorations-after-script-formatter.js
index 989dbfff..97bbf54 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/decorations-after-script-formatter.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/decorations-after-script-formatter.js
@@ -10,7 +10,7 @@
     `);
   await TestRunner.addScriptTag('resources/coverage.js');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   await UI.inspectorView.showPanel('sources');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-css.js b/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-css.js
index 30c5b9ce..2d4774c2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-css.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-css.js
@@ -10,7 +10,7 @@
     `);
   await TestRunner.addStylesheetTag('resources/highlight-in-source.css');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   await CoverageTestRunner.dumpDecorations('highlight-in-source.css');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-html.js b/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-html.js
index 82e3075..6141654 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-html.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-html.js
@@ -7,7 +7,7 @@
   await TestRunner.loadModule('coverage_test_runner');
   await TestRunner.navigatePromise(TestRunner.url('resources/document.html'));
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   await CoverageTestRunner.dumpDecorations('document.html');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-js.js b/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-js.js
index 5137c51e..586a2a26 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-js.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/gutter-js.js
@@ -7,7 +7,7 @@
   await TestRunner.loadModule('coverage_test_runner');
   await TestRunner.addScriptTag('resources/coverage.js');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   await CoverageTestRunner.dumpDecorations('coverage.js');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/multiple-instances-merge.js b/third_party/blink/web_tests/http/tests/devtools/coverage/multiple-instances-merge.js
index 2d161c1..a965408 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/multiple-instances-merge.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/multiple-instances-merge.js
@@ -6,7 +6,7 @@
   TestRunner.addResult(`Tests the coverage list view after finishing recording in the Coverage view.\n`);
   await TestRunner.loadModule('coverage_test_runner');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.loadHTML(`
       <iframe src="resources/subframe.html"></iframe>
       <p class="class">
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/reveal-autoformat.js b/third_party/blink/web_tests/http/tests/devtools/coverage/reveal-autoformat.js
index f2faa8f..34be7c42 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/reveal-autoformat.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/reveal-autoformat.js
@@ -11,7 +11,7 @@
   await TestRunner.addStylesheetTag('resources/decorations-after-inplace-formatter.css');
   await TestRunner.addStylesheetTag('resources/long-mangled.css');
 
-  CoverageTestRunner.startCoverage();
+  await CoverageTestRunner.startCoverage();
   await TestRunner.evaluateInPagePromise('performActions()');
   await CoverageTestRunner.stopCoverage();
   var node = CoverageTestRunner.findCoverageNodeForURL('long-mangled.css');
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10-expected.txt
new file mode 100644
index 0000000..5999afb7
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10-expected.txt
@@ -0,0 +1,15 @@
+Verifies JavaScript pretty-printing functionality.
+
+
+Running: objectSpread
+====== 8< ------
+const a = {
+    a: 4,
+    ...{
+        a: 5,
+        b: 42
+    }
+};
+
+------ >8 ======
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10.js
new file mode 100644
index 0000000..dd401786
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10.js
@@ -0,0 +1,18 @@
+// Copyright 2019 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.
+
+(async function() {
+  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
+  await TestRunner.loadModule('sources_test_runner');
+  await TestRunner.showPanel('sources');
+
+  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
+
+  TestRunner.runTestSuite([
+    function objectSpread(next) {
+      var mappingQueries = [];
+      testJSFormatter('const a = {a:4,...{a: 5,b: 42}};', mappingQueries, next);
+    },
+  ]);
+})();
diff --git a/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js b/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
index b5029a4..89605bbc7 100644
--- a/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
+++ b/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
@@ -462,14 +462,14 @@
 }
 
 function sensor_test(func, name, properties) {
-  promise_test(async () => {
+  promise_test(async t => {
     const sensorProvider = sensorMocks();
 
     // Clean up and reset mock sensor stubs asynchronously, so that the blink
     // side closes its proxies and notifies JS sensor objects before new test is
     // started.
     try {
-      await func(sensorProvider);
+      await func(t, sensorProvider);
     } finally {
       sensorProvider.reset();
       await new Promise(resolve => { setTimeout(resolve, 0); });
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/addressspace-document-csp.html b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/addressspace-document-csp.html
index e3bf605..04bbaf2 100644
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/addressspace-document-csp.html
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/addressspace-document-csp.html
@@ -6,7 +6,6 @@
     window.onload = function () {
         addressSpaceTest("http://localhost:8000", "document+csp", "public");
         addressSpaceTest("http://127.0.0.1:8000", "document+csp", "public");
-        addressSpaceTest("http://example.test:8000", "document+csp", "public");
     };
 </script>
 
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-fetch.html b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-fetch.php
similarity index 90%
rename from third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-fetch.html
rename to third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-fetch.php
index 268d50f8..3c64b24 100644
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-fetch.html
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-fetch.php
@@ -1,7 +1,8 @@
-<!doctype html>
+<?php
+  header("Content-Security-Policy: treat-as-public-address");
+?><!doctype html>
 <html>
 <head>
-    <meta http-equiv="Content-Security-Policy" content="treat-as-public-address">
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="./resources/preflight.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-xhr.html b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-xhr.php
similarity index 93%
rename from third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-xhr.html
rename to third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-xhr.php
index e4c3fef..306e583 100644
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-xhr.html
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/external-to-internal-xhr.php
@@ -1,7 +1,8 @@
-<!doctype html>
+<?php
+  header("Content-Security-Policy: treat-as-public-address");
+?><!doctype html>
 <html>
 <head>
-    <meta http-equiv="Content-Security-Policy" content="treat-as-public-address">
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="./resources/preflight.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/addressspace-test.js b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/addressspace-test.js
index 5e95c3e..a6988830 100644
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/addressspace-test.js
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/addressspace-test.js
@@ -1,13 +1,13 @@
 function createIFrame(origin, type) {
     var file;
     if (type == "document") {
-        file = "post-addressspace-to-parent.html";
+        file = "post-addressspace-to-parent.php";
     } else if (type == "document+csp") {
-        file = "post-addressspace-to-parent.html?csp";
+        file = "post-addressspace-to-parent.php?csp";
     } else if (type == "document+appcache") {
-        file = "post-addressspace-to-parent-with-appcache.html";
+        file = "post-addressspace-to-parent-with-appcache.php";
     } else if (type == "document+appcache+csp") {
-        file = "post-addressspace-to-parent-with-appcache.html?csp";
+        file = "post-addressspace-to-parent-with-appcache.php?csp";
     } else if (type == "worker") {
         file = "post-addressspace-from-worker.html";
     } else if (type == "sharedworker") {
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/appcache.php b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/appcache.php
index 7265cb2..e2edab6 100644
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/appcache.php
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/appcache.php
@@ -1,5 +1,5 @@
 <?php
 header("Content-Type: text/cache-manifest");
 print("CACHE MANIFEST\n\n");
-print("post-addressspace-to-parent-with-appcache.html");
+print("post-addressspace-to-parent-with-appcache.php");
 ?>
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.html b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.html
deleted file mode 100644
index cf75676..0000000
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<html manifest="/security/cors-rfc1918/resources/appcache.php">
-<script>
-    if (window.location.search == "?csp") {
-        var m = document.createElement("meta");
-        m.setAttribute("http-equiv", "Content-Security-Policy");
-        m.setAttribute("content", "treat-as-public-address");
-        document.head.appendChild(m);
-    }
-
-    window.applicationCache.oncached = window.applicationCache.onnoupdate = function (e) {
-        window.parent.postMessage({
-            "origin": window.location.origin,
-            "addressSpace": document.addressSpace
-        }, "*");
-    }
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.php b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.php
new file mode 100644
index 0000000..4a47e649
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.php
@@ -0,0 +1,13 @@
+<?php
+  if (isset($_GET["csp"]))
+    header("Content-Security-Policy: treat-as-public-address");
+?>
+<html manifest="/security/cors-rfc1918/resources/appcache.php">
+<script>
+    window.applicationCache.oncached = window.applicationCache.onnoupdate = function (e) {
+        window.parent.postMessage({
+            "origin": window.location.origin,
+            "addressSpace": document.addressSpace
+        }, "*");
+    }
+</script>
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent.html b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent.html
deleted file mode 100644
index e7758a5..0000000
--- a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<script>
-    if (window.location.search == "?csp") {
-        var m = document.createElement("meta");
-        m.setAttribute("http-equiv", "Content-Security-Policy");
-        m.setAttribute("content", "treat-as-public-address");
-        document.head.appendChild(m);
-    }
-
-    window.parent.postMessage({
-        "origin": window.location.origin,
-        "addressSpace": document.addressSpace
-    }, "*");
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent.php b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent.php
new file mode 100644
index 0000000..bc1c4bf
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent.php
@@ -0,0 +1,9 @@
+<?php
+  if (isset($_GET["csp"]))
+    header("Content-Security-Policy: treat-as-public-address");
+?><script>
+    window.parent.postMessage({
+        "origin": window.location.origin,
+        "addressSpace": document.addressSpace
+    }, "*");
+</script>
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html
index 72e04a1..e46ee412 100644
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html
@@ -36,7 +36,7 @@
     assert_false('ondeviceorientationabsolute' in window);
   }, 'Event interfaces and event handlers are not exposed on `window`.');
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     const FAKE_ACCELERATION_DATA = [1, 2, 3];
     const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6];
     const FAKE_GYROSCOPE_DATA = [7, 8, 9];
@@ -47,14 +47,14 @@
     return waitForLackOfEvent('devicemotion');
   }, 'addEventListener() for `devicemotion` does not crash but the handler never fires.');
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
     setMockSensorDataForType(sensorProvider, 'RelativeOrientationEulerAngles', FAKE_ORIENTATION_DATA);
 
     return waitForLackOfEvent('deviceorientation');
   }, 'addEventListener() for `deviceorientation` does not crash but the handler never fires.');
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
     setMockSensorDataForType(sensorProvider, 'AbsoluteOrientationEulerAngles', FAKE_ORIENTATION_DATA);
 
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
index ef22996..5f21be2f 100644
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
@@ -17,7 +17,7 @@
   assert_true('DeviceMotionEventRotationRate' in window);
 }, 'Event handlers as well as interfaces are exposed on `window`.');
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const FAKE_ACCELERATION_DATA = [1, 2, 3];
   const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6];
   const FAKE_GYROSCOPE_DATA = [7, 8, 9];
@@ -46,7 +46,7 @@
   }));
 }, 'DeviceMotionEvent fires.');
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
   setMockSensorDataForType(sensorProvider, 'RelativeOrientationEulerAngles', FAKE_ORIENTATION_DATA);
 
@@ -58,7 +58,7 @@
   }));
 }, 'DeviceOrientationEvent fires.');
 
-sensor_test(async sensorProvider => {
+sensor_test(async (t, sensorProvider) => {
   const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
   setMockSensorDataForType(sensorProvider, 'AbsoluteOrientationEulerAngles', FAKE_ORIENTATION_DATA);
 
diff --git a/third_party/blink/web_tests/sensor/orientation-sensor.html b/third_party/blink/web_tests/sensor/orientation-sensor.html
index aa311eb7..ef7cd83 100644
--- a/third_party/blink/web_tests/sensor/orientation-sensor.html
+++ b/third_party/blink/web_tests/sensor/orientation-sensor.html
@@ -88,7 +88,7 @@
     verifyQuatSensorReading,
     ['accelerometer', 'gyroscope', 'magnetometer']);
 
-sensor_test(sensorProvider => {
+sensor_test((t, sensorProvider) => {
   return checkPopulateMatrix(
       sensorProvider,
       AbsoluteOrientationSensor);
@@ -100,7 +100,7 @@
     verifyQuatSensorReading,
     ['accelerometer', 'gyroscope']);
 
-sensor_test(sensorProvider => {
+sensor_test((t, sensorProvider) => {
   return checkPopulateMatrix(
       sensorProvider,
       RelativeOrientationSensor);
diff --git a/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js b/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
index 6a74b8f..b079f3c 100644
--- a/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
+++ b/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
@@ -64,7 +64,7 @@
     }
   }
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     sensorProvider.getSensorTypeSettings(sensorType.name).unavailable = true;
     let sensorObject = new sensorType;
     sensorObject.start();
@@ -80,7 +80,7 @@
     });
   }, `${sensorType.name}: Test that onerror is sent when sensor is not supported.`);
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     sensorProvider.getSensorTypeSettings(sensorType.name).shouldDenyRequests = true;
     let sensorObject = new sensorType;
     sensorObject.start();
@@ -96,7 +96,7 @@
     });
   }, `${sensorType.name}: Test that onerror is sent when permissions are not granted.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 560});
     sensorObject.start();
 
@@ -115,7 +115,7 @@
     });
   }, `${sensorType.name}: Test that onerror is send when start() call has failed.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType();
     sensorObject.start();
 
@@ -125,7 +125,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that no pending configuration left after start() failure.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 560});
     sensorObject.start();
 
@@ -144,7 +144,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that frequency is capped to allowed maximum.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType();
     sensorObject.start();
     let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name);
@@ -163,7 +163,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that configuration is removed for a stopped sensor.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     const maxSupportedFrequency = 5;
     sensorProvider.setMaximumSupportedFrequency(maxSupportedFrequency);
     let sensorObject = new sensorType({frequency: 50});
@@ -184,7 +184,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that frequency is capped to the maximum supported from frequency.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     const minSupportedFrequency = 2;
     sensorProvider.setMinimumSupportedFrequency(minSupportedFrequency);
     let sensorObject = new sensorType({frequency: -1});
@@ -205,7 +205,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that frequency is limited to the minimum supported from frequency.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 60});
     assert_false(sensorObject.activated);
     sensorObject.start();
@@ -225,7 +225,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that sensor can be successfully created and its states are correct.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType();
     sensorObject.start();
 
@@ -244,7 +244,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that sensor can be constructed with default configuration.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 60});
     sensorObject.start();
 
@@ -288,15 +288,15 @@
     return mockSensor.removeConfigurationCalled();
   }
 
-  sensor_test(sensorProvider => checkOnReadingIsCalledAndReadingIsValid(sensorProvider),
+  sensor_test((t, sensorProvider) => checkOnReadingIsCalledAndReadingIsValid(sensorProvider),
   `${sensorType.name}: Test that onreading is called and sensor reading is valid (onchange reporting).`);
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     sensorProvider.setContinuousReportingMode();
     return checkOnReadingIsCalledAndReadingIsValid(sensorProvider);
   }, `${sensorType.name}: Test that onreading is called and sensor reading is valid (continuous reporting).`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 60});
     sensorObject.start();
 
@@ -323,7 +323,7 @@
   }, `${sensorType.name}: Test that sensor receives suspend / resume notifications when page\
  visibility changes.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 60});
     sensorObject.start();
 
@@ -358,7 +358,7 @@
   }, `${sensorType.name}: Test that sensor receives suspend / resume notifications when\
  cross-origin subframe is focused`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensor1 = new sensorType({frequency: 60});
     sensor1.start();
 
@@ -445,15 +445,15 @@
     return mockSensor.removeConfigurationCalled();
   }
 
-  sensor_test(sensorProvider => checkFrequencyHintWorks(sensorProvider),
+  sensor_test((t, sensorProvider) => checkFrequencyHintWorks(sensorProvider),
   `${sensorType.name}: Test that frequency hint works (onchange reporting).`);
 
-  sensor_test(sensorProvider => {
+  sensor_test((t, sensorProvider) => {
     sensorProvider.setContinuousReportingMode();
     return checkFrequencyHintWorks(sensorProvider);
   }, `${sensorType.name}: Test that frequency hint works (continuous reporting).`);
 
-  promise_test(() => {
+  promise_test(t => {
     return new Promise((resolve,reject) => {
       let iframe = document.createElement('iframe');
       iframe.allow = featurePolicies.join(' \'none\'; ') + ' \'none\';';
@@ -481,7 +481,7 @@
     });
   }, `${sensorType.name}: Test that sensor cannot be constructed within iframe disallowed to use feature policy.`);
 
-  promise_test(() => {
+  promise_test(t => {
     return new Promise((resolve,reject) => {
       let iframe = document.createElement('iframe');
       iframe.allow = featurePolicies.join(';') + ';';
@@ -509,7 +509,7 @@
     });
   }, `${sensorType.name}: Test that sensor can be constructed within an iframe allowed to use feature policy.`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     let sensorObject = new sensorType({frequency: 60});
     let timestamp = 0;
     sensorObject.start();
@@ -553,7 +553,7 @@
     return mockSensor.removeConfigurationCalled();
   }, `${sensorType.name}: Test that fresh reading is fetched on start().`);
 
-  sensor_test(async sensorProvider => {
+  sensor_test(async (t, sensorProvider) => {
     if (!expectedRemappedReadings) {
       // The sensorType does not represent a spatial sensor.
       return;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html
index f5b53606..2001cdd0 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-only-style-containment.html
@@ -4,7 +4,7 @@
 <title>Display Locking: acquire, containment got overridden</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-contain-style-only-with-child-ref.html">
+<link rel="match" href="pass-containment-added-ref.html">
 <script src="/common/reftest-wait.js"></script>
 <script src="../resources/utils.js"></script>
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html
index 3b7463e..07b97be 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/acquire-overridden-containment.html
@@ -4,7 +4,7 @@
 <title>Display Locking: acquire, containment got overridden</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-containment-style-layout-ref.html">
+<link rel="match" href="pass-containment-added-ref.html">
 <script src="/common/reftest-wait.js"></script>
 <script src="../resources/utils.js"></script>
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-contain-style-only-with-child-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-contain-style-only-with-child-ref.html
deleted file mode 100644
index 3b74a582..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-contain-style-only-with-child-ref.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: pass, container with child</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-<!-- TODO(rakina): Make this actually lock/not render the subtree even without layout containment -->
-<div id="log">PASS, contain: style</div>
-<div id="container"><div id="child"></div></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html
index 7cb48fd..6ed199df 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-added-ref.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html>
 <meta charset="utf8">
-<title>Display Locking: pass, no containment (reference)</title>
+<title>Display Locking: pass, added containment (reference)</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-style-layout-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-style-layout-ref.html
deleted file mode 100644
index 21f6e605..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/pass-containment-style-layout-ref.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: pass, no containment (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-</style>
-
-<div id="log">PASS, contain: layout style</div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html
index 36a13da1..2bae9bf1 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html
@@ -14,6 +14,7 @@
 <script>
 function setUp() {
   container.removeAttribute("rendersubtree");
+  container.style = "";
   assert_equals(getComputedStyle(container).contain, "none");
 }
 
@@ -25,29 +26,45 @@
 
 test(() => {
   setUp();
-  container.setAttribute("rendersubtree", "invisible-activatable");
+  container.setAttribute("rendersubtree", "invisible activatable");
   assert_equals(getComputedStyle(container).contain, "size layout style");
-}, "rendersubtree=invisible-activatable adds contain: size layout style;");
+}, "rendersubtree='invisible activatable' adds contain: size layout style;");
 
 test(() => {
   setUp();
-  container.setAttribute("rendersubtree", "visible");
-  assert_equals(getComputedStyle(container).contain, "layout style");
-}, "rendersubtree=visible adds contain: layout style;");
+  container.setAttribute("rendersubtree", "InVisible");
+  assert_equals(getComputedStyle(container).contain, "size layout style");
+}, "rendersubtree=InVisible adds contain: size layout style;");
 
 test(() => {
   setUp();
   container.setAttribute("rendersubtree", "invalid");
   assert_equals(getComputedStyle(container).contain, "layout style");
-}, "rendersubtree=invalid adds contain: layout style;");
-
+  container.style = "contain: size;";
+  assert_equals(getComputedStyle(container).contain, "size layout style");
+  container.style = "contain: paint;";
+  assert_equals(getComputedStyle(container).contain, "layout style paint");
+}, "rendersubtree=invalid adds contain: layout style, keeps size and paint if exists");
 
 test(() => {
   setUp();
   container.setAttribute("rendersubtree", "invisible");
   container.style = "contain: style;";
-  assert_equals(getComputedStyle(container).contain, "style");
+  assert_equals(getComputedStyle(container).contain, "size layout style");
+  container.style = "contain: style layout;";
+  assert_equals(getComputedStyle(container).contain, "size layout style");
   container.style = "";
   assert_equals(getComputedStyle(container).contain, "size layout style");
-}, "rendersubtree=invisible adds contain: size layout style, but can be overridden");
+}, "rendersubtree=invisible adds contain: size layout style, can't be overridden");
+
+test(() => {
+  setUp();
+  container.setAttribute("rendersubtree", "invisible");
+  container.style = "contain: paint;";
+  assert_equals(getComputedStyle(container).contain, "size layout style paint");
+  container.style = "contain: strict;";
+  assert_equals(getComputedStyle(container).contain, "size layout style paint");
+  container.style = "contain: content;";
+  assert_equals(getComputedStyle(container).contain, "size layout style paint");
+}, "rendersubtree adds contain: size layout style and keeps paint if it exists");
 </script>
diff --git a/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/helpers.mjs b/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/helpers.mjs
index 5699b23..cc7eaf6 100644
--- a/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/helpers.mjs
+++ b/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/helpers.mjs
@@ -25,8 +25,8 @@
  */
 export function largeDiv(id) {
   const large = div(id);
-  large.style.height = "5000px";
-  large.style.border = "solid";
+  large.style.height = '5000px';
+  large.style.border = 'solid';
   return large;
 }
 
@@ -60,7 +60,7 @@
  *
  * This includes a hack to wait 1s to give the virtual-scroller
  * elements time to settle.
-*/
+ */
 export function stopWaiting() {
   setTimeout(() => {
     document.documentElement.classList.remove('reftest-wait');
@@ -81,7 +81,7 @@
 /**
  * Allow the next |n| frames to end and then call |callback| ASAP in
  * the following frame.
-*/
+ */
 export function inNFrames(n, callback) {
   if (n == 0) {
     window.setTimeout(callback, 0);
@@ -95,7 +95,7 @@
 /**
  * Allow the current frame to end and then call |callback| asap in the
  * next frame.
-*/
+ */
 export function nextFrame(callback) {
   inNFrames(1, callback);
 }
diff --git a/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/ref-tests.mjs b/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/ref-tests.mjs
index 602a84ec..8777782 100644
--- a/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/ref-tests.mjs
+++ b/third_party/blink/web_tests/wpt_internal/virtual-scroller/resources/ref-tests.mjs
@@ -33,9 +33,9 @@
   // page reloads.
   document.body.scrollTo(0, 0);
   helpers.nextFrame(() => {
-    const largeChild = helpers.largeDiv("largeChild");
+    const largeChild = helpers.largeDiv('largeChild');
     target.appendChild(largeChild);
-    const child = helpers.div("child");
+    const child = helpers.div('child');
     target.appendChild(child);
 
     // Give the scroller time to settle.
@@ -53,11 +53,11 @@
   // page reloads.
   document.body.scrollTo(0, 0);
   helpers.nextFrame(() => {
-    const largeChild = helpers.largeDiv("largeChild");
+    const largeChild = helpers.largeDiv('largeChild');
     target.appendChild(largeChild);
     // Ensure that non-element nodes don't cause problems.
-    target.appendChild(document.createComment("comment"));
-    target.appendChild(helpers.div("child"));
+    target.appendChild(document.createComment('comment'));
+    target.appendChild(helpers.div('child'));
 
     // Give the scroller time to settle.
     helpers.inNFrames(10, () => {
@@ -114,9 +114,9 @@
   helpers.nextFrame(() => {
     // The page is a large element (much bigger than the page)
     // followed by the scroller. We then scroll down to the scroller.
-    const largeSibling = helpers.largeDiv("large");
+    const largeSibling = helpers.largeDiv('large');
     target.before(largeSibling);
-    const child = helpers.div("child");
+    const child = helpers.div('child');
     target.appendChild(child);
 
     // Give the scroller time to settle.
@@ -130,18 +130,18 @@
 /**
  * Runs |test| with a <virtual-scroller>, waiting until the custom element is
  * defined.
-*/
+ */
 export function withVirtualScroller(test) {
   customElements.whenDefined('virtual-scroller').then(() => {
-    runTest("virtual-scroller", test);
+    runTest('virtual-scroller', test);
   });
 }
 
 /**
  * Runs |test| with a <div>.
-*/
+ */
 export function withDiv(test) {
-  runTest("div", test);
+  runTest('div', test);
 }
 
 function runTest(elementName, test) {
diff --git a/third_party/closure_compiler/js_unit_test.py b/third_party/closure_compiler/js_unit_test.py
deleted file mode 100644
index 1d907a4c7..0000000
--- a/third_party/closure_compiler/js_unit_test.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-This script takes in a file created by js_library.py and any supplementary js
-files to build an html file used for js unit tests.
-"""
-
-from argparse import ArgumentParser
-from js_binary import CrawlDepsTree
-
-def Flatten(deps):
-  """
-  Recursively follows a list of dep files and returns source files in
-  dependency order. Ignores externs.
-  """
-  sources, externs = CrawlDepsTree(deps)
-  return sources
-
-def main():
-  parser = ArgumentParser()
-  parser.add_argument('-i', '--input',
-                      help='Input dependency file generated by js_library.py')
-  parser.add_argument('-m', '--mocks', nargs='*', default=[],
-                      help='List of additional js files to load before others')
-  parser.add_argument('-o', '--output',
-                      help='Generated html output with flattened dependencies')
-  parser.add_argument('-I', '--include_prefix', default='',
-                      help='Prefix added to src= paths to find .js files')
-  args = parser.parse_args()
-
-  uniquedeps = Flatten([args.input])
-  with open(args.output, 'w') as out:
-    out.write('<!DOCTYPE html>\n<html>\n<body>\n')
-    out.write(
-"""
-<script>
-// Basic include checker.
-window.addEventListener('error', function(e) {
-  if ((e.target instanceof HTMLScriptElement)) {
-    console.log('ERROR loading <script> element (does it exist?):\\n\\t' +
-                e.srcElement.src + '\\n\\tIncluded from: ' +
-                e.srcElement.baseURI);
-  }
-}, true /* useCapture */);
-</script>
-
-""")
-    for file in args.mocks:
-      out.write('<script src="%s%s"></script>\n' % (args.include_prefix, file))
-    for file in uniquedeps:
-      out.write('<script src="%s%s"></script>\n' % (args.include_prefix, file))
-    out.write('</body>\n</html>\n')
-
-if __name__ == '__main__':
-  main()
diff --git a/third_party/closure_compiler/js_unit_tests.gni b/third_party/closure_compiler/js_unit_tests.gni
index e1ed1e4..4e7fb29 100644
--- a/third_party/closure_compiler/js_unit_tests.gni
+++ b/third_party/closure_compiler/js_unit_tests.gni
@@ -4,103 +4,6 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 
-# Describes a list of js_library targets that will each have an html file
-# written listing all its (flattened) js dependencies, for loading as a test.
-#
-# A companion group target with a "_type_check" suffix is also generated with
-# this template. This depends on a list of js_type_check(..) targets -- one for
-# each test -- that will type check the test js file and its dependency subtree.
-#
-# Must be declared after the js_library targets it depends on.
-#
-# Note js_type_check(..) is a no-op unless `closure_compile` is set in gn args.
-#
-# Variables:
-#   deps:
-#     List of js_library targets to depend on
-#
-#   mocks:
-#     An optional list of .js files to load before any other scripts
-#
-# Example:
-#   js_unit_tests("folder_tests") {
-#     deps = [
-#       ":foo_unittest",
-#       ":bar_unittest",
-#       ":baz_unittest",
-#     ]
-#     mocks = [ "my_mocks.js" ]
-#   }
-#   group("closure_compile") {
-#     # ...
-#     ":folder_tests_type_check".
-#   }
-#   test("browser_tests") {
-#     # ...
-#     data_deps += [ "//folder:folder_tests" ]
-#   }
-
-template("js_unit_tests") {
-  html_gen_target_name = target_name + "_html_gen"
-  action_foreach(html_gen_target_name) {
-    script_path = "//third_party/closure_compiler"
-    script = "$script_path/js_unit_test.py"
-    forward_variables_from(invoker,
-                           [
-                             "deps",
-                             "mocks",
-                           ])
-    testonly = true
-    sources = []
-    foreach(dep, deps) {
-      sources += get_target_outputs(dep)
-    }
-
-    outputs = [
-      "$target_gen_dir/{{source_name_part}}.html",
-    ]
-    args = [ "--output" ] + rebase_path(outputs, root_build_dir)
-    args += [ "--input" ] + [ "{{source}}" ]
-
-    # js_unit_test.py needs to walk .js_library dependency files relative to the
-    # gen_dir, but we'd like to reference the corresponding .js source files
-    # in the source dir, not the gen dir. Pass a prefix to remap --input args.
-    args += [
-      "--include_prefix",
-      rebase_path("//", "{{root_gen_dir}}", "//"),
-    ]
-
-    if (defined(mocks)) {
-      args += [ "--mocks" ] + rebase_path(mocks, root_build_dir)
-      data = mocks
-    }
-  }
-  type_check_deps = []
-  foreach(dep, invoker.deps) {
-    type_check_target_name = target_name + "_" + dep + "_type_check"
-    type_check_deps += [ ":$type_check_target_name" ]
-    js_type_check(type_check_target_name) {
-      testonly = true
-      forward_variables_from(invoker, [ "closure_flags" ])
-      deps = [
-        dep,
-      ]
-    }
-  }
-  type_check_group_name = target_name + "_type_check"
-  group(type_check_group_name) {
-    testonly = true
-    deps = type_check_deps
-  }
-  group(target_name) {
-    data = get_target_outputs(":$html_gen_target_name")
-    testonly = true
-    deps = [
-      ":$html_gen_target_name",
-    ]
-  }
-}
-
 # Simple wrapper around js_library to describe a unit test.
 template("js_unittest") {
   js_library(target_name) {
diff --git a/tools/android/native_lib_memory/parse_smaps.py b/tools/android/native_lib_memory/parse_smaps.py
index 6113b2a1..99c16d70 100755
--- a/tools/android/native_lib_memory/parse_smaps.py
+++ b/tools/android/native_lib_memory/parse_smaps.py
@@ -21,6 +21,7 @@
 
 class Mapping(object):
   """A single entry (mapping) in /proc/[pid]/smaps."""
+
   def __init__(self, start, end, permissions, offset, pathname):
     """Initializes an instance.
 
@@ -163,6 +164,17 @@
   _PrintMappingsMetric(mappings, 'Swap')
 
 
+def _FootprintForAnonymousMapping(mapping):
+  assert mapping.pathname.startswith('[anon:')
+  if (mapping.pathname == '[anon:libc_malloc]'
+      and mapping.fields['Shared_Dirty'] != 0):
+    # libc_malloc mappings can come from the zygote. In this case, the shared
+    # dirty memory is likely dirty in the zygote, don't count it.
+    return mapping.fields['Rss']
+  else:
+    return mapping.fields['Private_Dirty']
+
+
 def _PrintEstimatedFootprintStats(mappings, page_table_kb):
   print 'Private Dirty:'
   _PrintMappingsMetric(mappings, 'Private_Dirty')
@@ -178,7 +190,12 @@
 
 
 def _ComputeEstimatedFootprint(mappings, page_table_kb):
-  """Returns the estimated footprint in kiB."""
+  """Returns the estimated footprint in kiB.
+
+  Args:
+    mappings: ([Mapping]) all process mappings.
+    page_table_kb: (int) Sizeof the page tables in kiB.
+  """
   footprint = page_table_kb
   for mapping in mappings:
     # Chrome shared memory.
@@ -187,12 +204,8 @@
     # account for its entirety.
     if mapping.pathname.startswith('/dev/ashmem/shared_memory'):
       footprint += mapping.fields['Rss']
-    elif mapping.pathname.startswith('[anon:libc_malloc]'):
-      if mapping.fields['Shared_Dirty'] == 0:
-        footprint += mapping.fields['Rss']
-      else:
-        footprint += mapping.fields['Private_Dirty']  # Shared dirty is likely
-                                                      # from the zygote.
+    elif mapping.pathname.startswith('[anon'):
+      footprint += _FootprintForAnonymousMapping(mapping)
     # Mappings without a name are most likely Chrome's native memory allocators:
     # v8, PartitionAlloc, Oilpan.
     # All of it should be charged to our process.
@@ -208,6 +221,21 @@
   return footprint
 
 
+def _ShowAllocatorFootprint(mappings, allocator):
+  """Shows the total footprint from a specific allocator.
+
+  Args:
+    mappings: ([Mapping]) all process mappings.
+    allocator: (str) Allocator name.
+  """
+  total_footprint = 0
+  pathname = '[anon:%s]' % allocator
+  for mapping in mappings:
+    if mapping.pathname == pathname:
+      total_footprint += _FootprintForAnonymousMapping(mapping)
+  print '\tFootprint from %s: %d kB' % (allocator, total_footprint)
+
+
 def _CreateArgumentParser():
   parser = argparse.ArgumentParser()
   parser.add_argument('--pid', help='PID.', required=True, type=int)
@@ -216,6 +244,10 @@
                       action='store_true')
   parser.add_argument('--store-smaps', help='Store the smaps file locally',
                       action='store_true')
+  parser.add_argument('--show-allocator-footprint',
+                      help='Show the footprint from a given allocator',
+                      choices=['v8', 'libc_malloc', 'partition_alloc'],
+                      nargs='+')
   return parser
 
 
@@ -239,6 +271,11 @@
   else:
     _PrintSwapStats(mappings)
 
+  if args.show_allocator_footprint:
+    print '\n\nMemory Allocators footprint:'
+    for allocator in args.show_allocator_footprint:
+      _ShowAllocatorFootprint(mappings, allocator)
+
 
 if __name__ == '__main__':
   main()
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 6501ddd..534f388 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -5334,37 +5334,44 @@
 </action>
 
 <action name="DevTools_InspectAndroidPage">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="DevTools_InspectAndroidWebView">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="DevTools_InspectElement">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="DevTools_InspectRenderer">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="DevTools_InspectWorker">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="DevTools_ToggleConsole">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="DevTools_ToggleWindow">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
@@ -21973,12 +21980,14 @@
 </action>
 
 <action name="ToggleDevTools">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="ToggleDevToolsConsole">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 10570af..3134d7f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -8050,6 +8050,9 @@
 </enum>
 
 <enum name="ChromePrimaryAccountStateInGaiaCookies">
+  <obsolete>
+    Deprecated as of 09/2019.
+  </obsolete>
   <int value="0" label="No Chrome primary account."/>
   <int value="1"
       label="Chrome primary account is the first account in Gaia cookies."/>
@@ -8058,6 +8061,11 @@
   <int value="3" label="Chrome primary account is not in Gaia cookies."/>
 </enum>
 
+<enum name="ChromeSignInPageHashSaved">
+  <int value="0" label="A password was typed, a hash is not saved"/>
+  <int value="1" label="A hash is saved"/>
+</enum>
+
 <enum name="ChromiumAndroidLinkerBrowserState">
   <obsolete>
     Deprecated as of 06/2019.
@@ -36094,6 +36102,7 @@
   <int value="19815558" label="EnableSettingsShortcutSearch:disabled"/>
   <int value="21055794" label="OpenXR:enabled"/>
   <int value="23556595" label="MarkHttpAs:enabled"/>
+  <int value="24124916" label="PrefetchPrivacyChanges:enabled"/>
   <int value="26875005" label="disable-explicit-dma-fences"/>
   <int value="27507364" label="apps-keep-chrome-alive"/>
   <int value="29212695" label="OfflineIndicator:enabled"/>
@@ -36694,7 +36703,6 @@
   <int value="879992337" label="disable-pull-to-refresh-effect"/>
   <int value="880510010" label="enable-permissions-bubbles"/>
   <int value="884106779" label="supervised-user-safesites"/>
-  <int value="885357190" label="force-use-chrome-camera"/>
   <int value="885971656" label="EnablePlayStoreAppSearch:enabled"/>
   <int value="886907524" label="autoplay-policy"/>
   <int value="887011602" label="enable-spelling-auto-correct"/>
@@ -36791,6 +36799,7 @@
   <int value="1033412163" label="OmniboxDisplayTitleForCurrentUrl:enabled"/>
   <int value="1033597574" label="disable-layer-squashing"/>
   <int value="1036068554" label="enable-android-pay-integration-v2"/>
+  <int value="1038234679" label="PrefetchPrivacyChanges:disabled"/>
   <int value="1043291220" label="OverviewSwipeToClose:disabled"/>
   <int value="1043334401" label="disable-slimming-paint-invalidation"/>
   <int value="1044928476"
@@ -37057,7 +37066,6 @@
   <int value="1373777956" label="disable-threaded-gpu-rasterization"/>
   <int value="1375165388" label="LazyFrameLoading:enabled"/>
   <int value="1376437124" label="show-cert-link"/>
-  <int value="1376535351" label="PrefetchRedirectError:enabled"/>
   <int value="1377056573" label="browser-side-navigation:enabled"/>
   <int value="1378310092" label="disable-suggestions-service"/>
   <int value="1379944457" label="EnableMessagesWebPush:disabled"/>
@@ -37178,7 +37186,6 @@
   <int value="1559034872" label="AutofillPrefilledFields:enabled"/>
   <int value="1560188739" label="reader-mode-heuristics"/>
   <int value="1563255033" label="memlog-stack-mode"/>
-  <int value="1566084951" label="PrefetchRedirectError:disabled"/>
   <int value="1567839560"
       label="ChromeHomePersonalizedOmniboxSuggestions:disabled"/>
   <int value="1570178909" label="NewOverviewLayout:enabled"/>
@@ -55381,6 +55388,9 @@
 </enum>
 
 <enum name="SigninTokenStateTransition">
+  <obsolete>
+    Deprecated as of 09/2019.
+  </obsolete>
   <int value="0" label="None to Invalid"/>
   <int value="1" label="None to Regular"/>
   <int value="2" label="Invalid to Regular"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a0d0143d..f96bcd6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -24316,6 +24316,16 @@
   </summary>
 </histogram>
 
+<histogram name="Cras.HfpWidebandSpeechPacketLoss" expires_after="2020-08-26">
+  <owner>enshuo@chromium.org</owner>
+  <owner>chromeos-audio@google.com</owner>
+  <summary>
+    For each HFP audio device supporting WBS record how many packets are lost
+    per 1000 packets when the device is closed. This is for tracking how bad the
+    packet loss can be for WBS in real world.
+  </summary>
+</histogram>
+
 <histogram name="Cras.HfpWidebandSpeechSupported" units="BooleanSupported"
     expires_after="2020-02-23">
   <owner>hychao@chromium.org</owner>
@@ -28840,14 +28850,16 @@
 
 <histogram name="DevTools.ActionTaken" enum="DevToolsAction">
   <owner>alph@chromium.org</owner>
-  <owner>pfeldman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>Specified DevTools action has been taken.</summary>
 </histogram>
 
 <histogram name="DevTools.BackgroundService.ClearEvents"
     enum="ServiceWorkerStatusCode" expires_after="M80">
-  <owner>dgozman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>
     The result of clearing all stored events for a Background Service feature.
     This is called if a developer clicks on a delete button in a Background
@@ -28857,8 +28869,9 @@
 
 <histogram name="DevTools.BackgroundService.GetEvents"
     enum="ServiceWorkerStatusCode" expires_after="M80">
-  <owner>dgozman@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>
     The result of loading all stored events for a Background Service feature.
     This is called when the a Bakground Service DevTools panel is opened.
@@ -28867,8 +28880,9 @@
 
 <histogram name="DevTools.BackgroundService.LogEvent"
     enum="ServiceWorkerStatusCode" expires_after="M80">
-  <owner>dgozman@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>
     The result of logging a Background Service event. An event is logged if
     `Recording` mode is on and a relevant Background Service event is taking
@@ -28878,7 +28892,8 @@
 
 <histogram name="DevTools.BackgroundService.StartRecording"
     enum="DevToolsBackgroundService" expires_after="M80">
-  <owner>dgozman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <summary>
     Records the Background Service for which `Recording` mode was enabled. This
@@ -28889,7 +28904,8 @@
 
 <histogram name="DevTools.InspectElement" units="ms">
   <owner>alph@chromium.org</owner>
-  <owner>pfeldman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>
     Time to load Developer Tools when user clicks Inspect Element in the context
     menu.
@@ -28899,7 +28915,8 @@
 <histogram base="true" name="DevTools.Launch" units="ms">
 <!-- Name completed by histogram_suffixes name="DevToolsLaunchPanels" -->
 
-  <owner>pfeldman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>
     Measures the time until a given tool is interactive during a cold start of
     the DevTools.
@@ -28908,13 +28925,15 @@
 
 <histogram name="DevTools.PanelShown" enum="DevToolsPanel">
   <owner>alph@chromium.org</owner>
-  <owner>pfeldman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>Specified DevTools panel was shown.</summary>
 </histogram>
 
 <histogram name="DevTools.SettingChanged" enum="DevToolsSetting">
   <owner>alph@chromium.org</owner>
-  <owner>pfeldman@chromium.org</owner>
+  <owner>yangguo@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
   <summary>Specified DevTools setting was changed.</summary>
 </histogram>
 
@@ -98185,6 +98204,16 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.ChromeSignInPageHashSaved"
+    enum="ChromeSignInPageHashSaved" expires_after="M86">
+  <owner>dvadym@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Records whether a password hash was saved or not on Chrome sign-in page.
+    Recorded whenever the user types a password on Chrome sign-in page.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.CleanedUpPasswords">
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -129200,9 +129229,10 @@
 </histogram>
 
 <histogram name="SignedExchange.CertificateFetch.CacheHit"
-    enum="BooleanCacheHit" expires_after="2019-10-01">
+    enum="BooleanCacheHit" expires_after="2020-04-01">
+  <owner>ksakamoto@chromium.org</owner>
   <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     Records if the fetched Signed Exchange certchain was served from HTTP cache
     or not.
@@ -129210,20 +129240,20 @@
 </histogram>
 
 <histogram name="SignedExchange.CertVerificationResult" enum="NetErrorCodes"
-    expires_after="2019-09-20">
-  <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+    expires_after="2020-04-01">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     Reports the result of Signed Exchange cert verification, including success.
   </summary>
 </histogram>
 
 <histogram name="SignedExchange.CTVerificationResult" enum="CTComplianceStatus"
-    expires_after="2019-09-20">
-  <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+    expires_after="2020-04-01">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     Reports the result of Signed Exchange CT verification, including success.
   </summary>
@@ -129244,10 +129274,10 @@
 </histogram>
 
 <histogram name="SignedExchange.LoadResult2" enum="SignedExchangeLoadResult"
-    expires_after="2019-09-20">
-  <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+    expires_after="2020-04-01">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     Records the result of loading a resource from Signed HTTP Exchange. Emitted
     each time a response is handled as Signed Exchange.
@@ -129255,10 +129285,10 @@
 </histogram>
 
 <histogram name="SignedExchange.OCSPResponseStatus" enum="OCSPResponseStatus"
-    expires_after="2019-09-20">
-  <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+    expires_after="2020-04-01">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     The status of OCSP response in Signed Exchange certificates. Reported each
     time Signed Exchange's OCSP check is performed.
@@ -129266,10 +129296,10 @@
 </histogram>
 
 <histogram name="SignedExchange.OCSPRevocationStatus"
-    enum="OCSPRevocationStatus" expires_after="2019-09-20">
-  <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+    enum="OCSPRevocationStatus" expires_after="2020-04-01">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     Reports the revocation status of OCSP response in Signed Exchange
     certificates. Emitted when Signed Exchange's OCSP check is performed, but
@@ -129335,10 +129365,10 @@
 </histogram>
 
 <histogram name="SignedExchange.SignatureVerificationError.NotYetValid"
-    units="seconds" expires_after="2019-09-20">
-  <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+    units="seconds" expires_after="2020-04-01">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     Recorded when Signed Exchange signature was not yet valid. Records the time
     delta between current time and signature's &quot;date&quot; value.
@@ -129357,9 +129387,10 @@
 </histogram>
 
 <histogram name="SignedExchange.Time.CertificateFetch.Failure" units="ms"
-    expires_after="2019-10-01">
+    expires_after="2020-04-01">
+  <owner>ksakamoto@chromium.org</owner>
   <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     The amount of time elapsed to fetch certificate chain from certUrl, for
     which the fetch has failed.
@@ -129367,9 +129398,10 @@
 </histogram>
 
 <histogram name="SignedExchange.Time.CertificateFetch.Success" units="ms"
-    expires_after="2019-10-01">
+    expires_after="2020-04-01">
+  <owner>ksakamoto@chromium.org</owner>
   <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     The amount of time elapsed to fetch certificate chain from certUrl, for
     which the fetch has succeeded.
@@ -129377,9 +129409,10 @@
 </histogram>
 
 <histogram name="SignedExchange.Time.SignatureVerify" units="ms"
-    expires_after="2019-10-01">
+    expires_after="2020-04-01">
+  <owner>ksakamoto@chromium.org</owner>
   <owner>kinuko@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+  <owner>horo@chromium.org</owner>
   <summary>
     The amount of time that elapsed during
     SignedExchangeSignatureVerifier::Verify.
@@ -129602,13 +129635,15 @@
 </histogram>
 
 <histogram name="Signin.ChromePrimaryAccountStateOnWebSignout"
-    enum="ChromePrimaryAccountStateInGaiaCookies" expires_after="M77">
+    enum="ChromePrimaryAccountStateInGaiaCookies">
+  <obsolete>
+    Deprecated 2019-09. No longer useful after Dice is launched.
+  </obsolete>
   <owner>droger@chromium.org</owner>
   <summary>
     Logs the state of the Chrome account when the user signs out on the web.
     This assumes that a logout of the web is always a complete logout of all the
-    web accounts (e.g. single session signout is not supported). TODO(droger):
-    make this histogram obsolete when Dice is launched.
+    web accounts (e.g. single session signout is not supported).
   </summary>
 </histogram>
 
@@ -130313,8 +130348,10 @@
   </summary>
 </histogram>
 
-<histogram name="Signin.TokenStateTransition" enum="SigninTokenStateTransition"
-    expires_after="M77">
+<histogram name="Signin.TokenStateTransition" enum="SigninTokenStateTransition">
+  <obsolete>
+    Deprecated 2019-09. Obsolete after Dice is launched.
+  </obsolete>
   <owner>droger@chromium.org</owner>
   <summary>
     Tracks the changes of refresh token states for all accounts. Tokens can have
@@ -161342,6 +161379,7 @@
 
 <histogram_suffixes name="ContentIndexDatabaseTask" separator=".">
   <suffix name="Add" label="Register content"/>
+  <suffix name="ClearCorruptedData" label="Clear data in SW"/>
   <suffix name="Delete" label="Delete content"/>
   <suffix name="GetAllEntries" label="Get all entries"/>
   <suffix name="GetDescriptions" label="Get registered content"/>
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index fccc654..07b064b7 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -56,16 +56,16 @@
 group("unit_test_data") {
   testonly = true
   deps = [
-    "base/js:unit_tests",
+    "base/js:js_test_gen_html",
     "file_manager/background/js:js_test_gen_html",
     "file_manager/common/js:js_test_gen_html",
     "file_manager/foreground/elements:js_test_gen_html",
     "file_manager/foreground/js:js_test_gen_html",
     "file_manager/foreground/js/metadata:js_test_gen_html",
     "file_manager/foreground/js/ui:js_test_gen_html",
-    "gallery/js:unit_tests",
-    "gallery/js/image_editor:unit_tests",
-    "image_loader:unit_tests",
-    "video_player/js:unit_tests",
+    "gallery/js:js_test_gen_html",
+    "gallery/js/image_editor:js_test_gen_html",
+    "image_loader:js_test_gen_html",
+    "video_player/js:js_test_gen_html",
   ]
 }
diff --git a/ui/file_manager/base/gn/js_test_gen_html.py b/ui/file_manager/base/gn/js_test_gen_html.py
index 0658161e..29551d91 100644
--- a/ui/file_manager/base/gn/js_test_gen_html.py
+++ b/ui/file_manager/base/gn/js_test_gen_html.py
@@ -136,9 +136,9 @@
 
   # Append closure path to sys.path to be able to import js_unit_test.
   sys.path.append(os.path.join(args.src_path, 'third_party/closure_compiler'))
-  from js_unit_test import Flatten
+  from js_binary import CrawlDepsTree
 
-  deps = Flatten([args.input])
+  deps, _ = CrawlDepsTree([args.input])
 
   return _process(deps, args.output, args.mocks, args.html_import,
                   args.target_name)
diff --git a/ui/file_manager/base/js/BUILD.gn b/ui/file_manager/base/js/BUILD.gn
index 5d852f1..216a438 100644
--- a/ui/file_manager/base/js/BUILD.gn
+++ b/ui/file_manager/base/js/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
+import("//ui/file_manager/base/gn/js_test_gen_html.gni")
 
 visibility = [ "//ui/file_manager/*" ]
 
@@ -11,6 +12,7 @@
   testonly = true
   deps = [
     ":closure_compile_module",
+    ":js_test_gen_html_type_check_auto",
     ":test_support_type_check",
   ]
 }
@@ -78,7 +80,7 @@
   ]
 }
 
-js_unit_tests("unit_tests") {
+js_test_gen_html("js_test_gen_html") {
   deps = [
     ":volume_manager_types_unittest",
   ]
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 76699ce2..ad35aa2 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -100,6 +100,7 @@
   display: flex;
   flex: 1 1 auto;
   margin-top: 8px;
+  position: relative;
 }
 
 .dialog-navigation-list-footer {
@@ -124,7 +125,11 @@
   bottom: 0;
   flex: none;
   left: 0;
-  min-width: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;   /* TODO(adanilo): crbug.com/212268 still needed? */
+  right: 0;
+  top: 0;
 }
 
 #directory-tree .tree-row {
@@ -161,17 +166,6 @@
   text-overflow: ellipsis;
 }
 
-#directory-tree .tree-item > .tree-row.ejectable {
-  position: inherit;
-}
-
-#directory-tree .tree-row.ejectable > .label {
-  left: 48px;
-  position: absolute;
-  right: 48px;
-  width: calc(100% - 48px - 40px - 3px);
-}
-
 #directory-tree .tree-row .rename-placeholder {
   display: block;
   flex: auto;
@@ -223,9 +217,7 @@
   cursor: pointer;
   flex: none;
   height: 40px;
-  left: calc(100% - 40px - 3px);
-  position: absolute;
-  right: calc(100% - 40px - 3px);
+  position: relative;
   width: 40px;
   z-index: 1;  /* Make sure the icon is on upper layer than paper-ripple. */
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 5cf81d8..ccf265c 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -676,15 +676,6 @@
     // Add the eject button as the last element of the tree row content.
     const parent = rowElement.querySelector('.label').parentElement;
     assert(parent).appendChild(ejectButton);
-
-    // Mark the tree row element with CSS class .ejectable.
-    rowElement.classList.add('ejectable');
-
-    // Disable paper-ripple on this rowElement, crbug.com/965382.
-    const rowRipple = rowElement.querySelector('paper-ripple');
-    if (rowRipple) {
-      rowRipple.setAttribute('style', 'visibility:hidden');
-    }
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index e8419ce..0f2242f 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -237,7 +237,7 @@
    * @override
    */
   mergeItems(beginIndex, endIndex) {
-    super.mergeItems(beginIndex, endIndex);
+    cr.ui.List.prototype.mergeItems.call(this, beginIndex, endIndex);
 
     const afterFiller = this.afterFiller_;
     const columns = this.columns;
diff --git a/ui/file_manager/gallery/js/BUILD.gn b/ui/file_manager/gallery/js/BUILD.gn
index 0481768..471e4906 100644
--- a/ui/file_manager/gallery/js/BUILD.gn
+++ b/ui/file_manager/gallery/js/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
+import("//ui/file_manager/base/gn/js_test_gen_html.gni")
 
 js_type_check("closure_compile_module") {
   deps = [
@@ -225,7 +226,7 @@
   ]
 }
 
-js_unit_tests("unit_tests") {
+js_test_gen_html("js_test_gen_html") {
   deps = [
     ":dimmable_ui_controller_unittest",
     ":entry_list_watcher_unittest",
@@ -241,6 +242,6 @@
   testonly = true
   deps = [
     ":closure_compile_module",
-    ":unit_tests_type_check",
+    ":js_test_gen_html_type_check_auto",
   ]
 }
diff --git a/ui/file_manager/gallery/js/image_editor/BUILD.gn b/ui/file_manager/gallery/js/image_editor/BUILD.gn
index f535e77..c426567 100644
--- a/ui/file_manager/gallery/js/image_editor/BUILD.gn
+++ b/ui/file_manager/gallery/js/image_editor/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
+import("//ui/file_manager/base/gn/js_test_gen_html.gni")
 
 js_type_check("closure_compile_module") {
   deps = [
@@ -197,7 +198,7 @@
   ]
 }
 
-js_unit_tests("unit_tests") {
+js_test_gen_html("js_test_gen_html") {
   deps = [
     ":exif_encoder_unittest",
     ":image_encoder_unittest",
@@ -210,6 +211,6 @@
   testonly = true
   deps = [
     ":closure_compile_module",
-    ":unit_tests_type_check",
+    ":js_test_gen_html_type_check_auto",
   ]
 }
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn
index 93be6b7f..c7abbf0 100644
--- a/ui/file_manager/image_loader/BUILD.gn
+++ b/ui/file_manager/image_loader/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
+import("//ui/file_manager/base/gn/js_test_gen_html.gni")
 
 js_type_check("closure_compile_module") {
   closure_flags = default_closure_args + [ "jscomp_error=strictCheckTypes" ]
@@ -124,7 +125,7 @@
   ]
 }
 
-js_unit_tests("unit_tests") {
+js_test_gen_html("js_test_gen_html") {
   closure_flags = default_closure_args + [ "jscomp_error=strictCheckTypes" ]
   deps = [
     ":cache_unittest",
@@ -138,6 +139,6 @@
   testonly = true
   deps = [
     ":closure_compile_module",
-    ":unit_tests_type_check",
+    ":js_test_gen_html_type_check_auto",
   ]
 }
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree.js b/ui/file_manager/integration_tests/file_manager/directory_tree.js
new file mode 100644
index 0000000..8f74e54
--- /dev/null
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree.js
@@ -0,0 +1,73 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+(() => {
+  /**
+   * Tests that the directory tree can be vertically scrolled.
+   */
+  testcase.directoryTreeVerticalScroll = async () => {
+    // Add directory entries to overflow the directory tree container.
+    let folders = [ENTRIES.photos];
+    for (let i = 0; i < 30; i++) {
+      folders.push(new TestEntryInfo({
+        type: EntryType.DIRECTORY,
+        targetPath: '' + i,
+        lastModifiedTime: 'Jan 1, 1980, 11:59 PM',
+        nameText: '' + i,
+        sizeText: '--',
+        typeText: 'Folder'
+      }));
+    }
+
+    // Open FilesApp on Downloads. Expand the directory tree view of Downloads.
+    const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, folders, []);
+    await expandRoot(appId, TREEITEM_DOWNLOADS);
+
+    // Get the directory tree and verify it is not scrolled.
+    const directoryTree = '#directory-tree';
+    const original = await remoteCall.waitForElementStyles(
+        appId, directoryTree, ['scrollTop']);
+    chrome.test.assertTrue(original.scrollTop === 0);
+
+    // Scroll the directory tree down (vertical scroll).
+    await remoteCall.callRemoteTestUtil(
+        'setScrollTop', appId, [directoryTree, 100]);
+
+    // Check: the directory tree should be scrolled.
+    const scrolled = await remoteCall.waitForElementStyles(
+        appId, directoryTree, ['scrollTop']);
+    chrome.test.assertTrue(scrolled.scrollTop === 100, 'Tree should scroll');
+  };
+
+  /**
+   * Tests that the directory tree does not horizontally scroll.
+   */
+  testcase.directoryTreeHorizontalScroll = async () => {
+    // Open FilesApp on Downloads. Expand the navigation list view of Downloads.
+    const appId = await setupAndWaitUntilReady(
+        RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET, []);
+    await expandRoot(appId, TREEITEM_DOWNLOADS);
+
+    // Get the directory tree and verify it is not scrolled.
+    const directoryTree = '#directory-tree';
+    const original = await remoteCall.waitForElementStyles(
+        appId, directoryTree, ['scrollLeft']);
+    chrome.test.assertTrue(original.scrollLeft === 0);
+
+    // Shrink the navigation list tree to 50px.
+    const navigationList = '.dialog-navigation-list';
+    await remoteCall.callRemoteTestUtil(
+        'setElementStyles', appId, [navigationList, {width: '50px'}]);
+
+    // Scroll the directory tree left (horizontal scroll).
+    await remoteCall.callRemoteTestUtil(
+        'setScrollLeft', appId, [directoryTree, 100]);
+
+    // Check; the directory tree should not be scrolled.
+    const scrolled = await remoteCall.waitForElementStyles(
+        appId, directoryTree, ['scrollLeft']);
+    chrome.test.assertTrue(scrolled.scrollLeft === 0, 'Tree should not scroll');
+  };
+})();
diff --git a/ui/file_manager/integration_tests/file_manager/navigation_list.js b/ui/file_manager/integration_tests/file_manager/navigation_list.js
deleted file mode 100644
index 0da399c..0000000
--- a/ui/file_manager/integration_tests/file_manager/navigation_list.js
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-'use strict';
-(() => {
-  /**
-   * Tests that the directory tree area can be vertically scrolled.
-   */
-  testcase.navigationListVerticalScroll = async () => {
-    // Add directory entries to overflow the navigation list container.
-    let folders = [ENTRIES.photos];
-    for (let i = 0; i < 30; i++) {
-      folders.push(new TestEntryInfo({
-        type: EntryType.DIRECTORY,
-        targetPath: '' + i,
-        lastModifiedTime: 'Jan 1, 1980, 11:59 PM',
-        nameText: '' + i,
-        sizeText: '--',
-        typeText: 'Folder'
-      }));
-    }
-
-    // Open FilesApp on Downloads. Expand the navigation list view of Downloads.
-    const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, folders, []);
-    await expandRoot(appId, TREEITEM_DOWNLOADS);
-
-    // Get the navigationList and verify it is not scrolled.
-    const navigationList = '.dialog-navigation-list';
-    const originalList = await remoteCall.waitForElementStyles(
-        appId, navigationList, ['scrollTop']);
-    chrome.test.assertTrue(originalList.scrollTop === 0);
-
-    // Scroll the navigation list down (vertical scroll).
-    await remoteCall.callRemoteTestUtil(
-        'setScrollTop', appId, [navigationList, 100]);
-
-    // Check: the navigation list should be scrolled.
-    const newList = await remoteCall.waitForElementStyles(
-        appId, navigationList, ['scrollTop']);
-    chrome.test.assertTrue(newList.scrollTop > 0);
-  };
-
-  /**
-   * Tests that the directory tree area can be horizontally scrolled.
-   * TODO(crbug.com/966807): Clean up test case to match the comment style and
-   * organization of navigationListVerticalScroll.
-   * Remove unnecessary check that originalWidth > 0.
-   */
-  testcase.navigationListHorizontalScroll = async () => {
-    // Open FilesApp on Downloads. Expand the navigation list view of Downloads.
-    const appId = await setupAndWaitUntilReady(
-        RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET, []);
-    await expandRoot(appId, TREEITEM_DOWNLOADS);
-
-    // Get the navigationList width property and make sure it has non-zero size.
-    const navigationList = '.dialog-navigation-list';
-    const originalList =
-        await remoteCall.waitForElementStyles(appId, navigationList, ['width']);
-    const originalWidth = Number(originalList.styles['width'].match(/[0-9]*/));
-    chrome.test.assertTrue(originalWidth > 0);
-
-    // Shrink the navigation list tree area to 50px.
-    await remoteCall.callRemoteTestUtil(
-        'setElementStyles', appId, [navigationList, {width: '50px'}]);
-
-    // Check the navigation list area is scrolled completely to the left side.
-    chrome.test.assertTrue(originalList.scrollLeft === 0);
-
-    // Scroll the navigation list down (horizontal scroll).
-    await remoteCall.callRemoteTestUtil(
-        'setScrollLeft', appId, [navigationList, 100]);
-
-    // Get the current state of the NavigationWidth width and left scroll
-    // offset.
-    const newList =
-        await remoteCall.waitForElementStyles(appId, navigationList, ['width']);
-
-    // Check that the width has been reduced.
-    const newWidth = Number(newList.styles['width'].match(/[0-9]*/));
-    chrome.test.assertTrue(newWidth < originalWidth);
-
-    // Check: the navigation list should be scrolled.
-    chrome.test.assertTrue(newList.scrollLeft > 0);
-  };
-})();
diff --git a/ui/file_manager/integration_tests/file_manager_test_manifest.json b/ui/file_manager/integration_tests/file_manager_test_manifest.json
index 924332c..bb64600 100644
--- a/ui/file_manager/integration_tests/file_manager_test_manifest.json
+++ b/ui/file_manager/integration_tests/file_manager_test_manifest.json
@@ -18,6 +18,7 @@
       "file_manager/copy_between_windows.js",
       "file_manager/create_new_folder.js",
       "file_manager/crostini.js",
+      "file_manager/directory_tree.js",
       "file_manager/directory_tree_context_menu.js",
       "file_manager/drive_specific.js",
       "file_manager/file_dialog.js",
@@ -34,7 +35,6 @@
       "file_manager/metadata.js",
       "file_manager/metrics.js",
       "file_manager/my_files.js",
-      "file_manager/navigation_list.js",
       "file_manager/open_audio_files.js",
       "file_manager/open_image_files.js",
       "file_manager/open_sniffed_files.js",
diff --git a/ui/file_manager/video_player/js/BUILD.gn b/ui/file_manager/video_player/js/BUILD.gn
index ca2d8e5b..726f6bd 100644
--- a/ui/file_manager/video_player/js/BUILD.gn
+++ b/ui/file_manager/video_player/js/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
+import("//ui/file_manager/base/gn/js_test_gen_html.gni")
 
 js_type_check("closure_compile_module") {
   deps = [
@@ -98,7 +99,7 @@
   ]
 }
 
-js_unit_tests("unit_tests") {
+js_test_gen_html("js_test_gen_html") {
   deps = [
     ":video_player_native_controls_unittest",
   ]
@@ -108,6 +109,6 @@
   testonly = true
   deps = [
     ":closure_compile_module",
-    ":unit_tests_type_check",
+    ":js_test_gen_html_type_check_auto",
   ]
 }
diff --git a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
index 231d590..a9d59f4 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
@@ -20,6 +20,13 @@
 
 namespace ui {
 
+namespace {
+
+// The maximum number of buffers we allow to be created.
+constexpr uint32_t kMaxNumbferOfBuffers = 3;
+
+}  // namespace
+
 size_t CalculateStride(int width) {
   base::CheckedNumeric<size_t> stride(width);
   stride *= 4;
@@ -41,13 +48,13 @@
   // Returns SkSurface, which the client can use to write to this buffer.
   sk_sp<SkSurface> sk_surface() const { return sk_surface_; }
 
-  // Tells clients if the buffer is busy and cannot be reused. Set on
-  // CommitBuffer() and reset on OnSubmissionCompleted() call.
-  bool busy() const { return busy_; }
-
   // Returns the id of the buffer.
   uint32_t buffer_id() const { return buffer_id_; }
 
+  // Tells if the buffer is pending to be processed. Set on
+  // SetPendingDamageRegion calls.
+  bool pending() const { return pending_; }
+
   // Initializes the shared memory and asks Wayland to import a shared memory
   // based wl_buffer, which can be attached to a surface and have its contents
   // shown on a screen.
@@ -86,15 +93,12 @@
   }
 
   void CommitBuffer(const gfx::Rect& damage) {
-    DCHECK(!busy_);
-    busy_ = true;
-
     buffer_manager_->CommitBuffer(widget_, buffer_id_, damage);
   }
 
   void OnSubmissionCompleted() {
-    DCHECK(busy_);
-    busy_ = false;
+    DCHECK(pending_);
+    pending_ = false;
   }
 
   void UpdateDirtyRegion(const gfx::Rect& damage, SkRegion::Op op) {
@@ -117,10 +121,23 @@
     dirty_region_.setEmpty();
   }
 
+  void SetPendingDamageRegion(const gfx::Rect& damage) {
+    DCHECK(!pending_);
+    pending_damage_region_ = damage;
+    pending_ = true;
+  }
+
+  gfx::Rect pending_damage_region() {
+    return std::move(pending_damage_region_);
+  }
+
  private:
   // The id of the buffer this surface is backed.
   const uint32_t buffer_id_;
 
+  // Says if the buffer is pending to be submitted.
+  bool pending_ = false;
+
   // The widget this buffer is created for.
   const gfx::AcceleratedWidget widget_;
 
@@ -136,9 +153,8 @@
   // The region of the buffer that's not up-to-date.
   SkRegion dirty_region_;
 
-  // Says if the buffer is busy or not. The value must be reset when the buffer
-  // manager acknowledges a swap.
-  bool busy_ = false;
+  // Pending damage region if the buffer is pending to be submitted.
+  gfx::Rect pending_damage_region_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedMemoryBuffer);
 };
@@ -155,27 +171,32 @@
 }
 
 sk_sp<SkSurface> WaylandCanvasSurface::GetSurface() {
-  DCHECK(!current_buffer_);
-  // TODO(msisov): Restrict the number of buffers that can be created per one
-  // canvas surface.
+  DCHECK(!pending_buffer_)
+      << "The previous pending buffer has not been presented yet";
+
   for (const auto& buffer : buffers_) {
-    if (buffer->busy())
-      continue;
-    current_buffer_ = buffer.get();
+    if (!buffer->pending()) {
+      pending_buffer_ = buffer.get();
+      break;
+    }
   }
 
-  if (!current_buffer_) {
-    auto buffer = CreateSharedMemoryBuffer();
-    if (!buffer) {
-      DCHECK(!current_buffer_);
+  if (!pending_buffer_) {
+    if (buffers_.size() >= kMaxNumbferOfBuffers) {
+      // We have achieved the maximum number of buffers we can create. Wait for
+      // a free buffer.
       return nullptr;
     }
-    current_buffer_ = buffer.get();
+    auto buffer = CreateSharedMemoryBuffer();
+    if (!buffer)
+      return nullptr;
+
+    pending_buffer_ = buffer.get();
     buffers_.push_back(std::move(buffer));
   }
 
-  DCHECK(current_buffer_ && !current_buffer_->busy());
-  return current_buffer_->sk_surface();
+  DCHECK(pending_buffer_ && !pending_buffer_->pending());
+  return pending_buffer_->sk_surface();
 }
 
 void WaylandCanvasSurface::ResizeCanvas(const gfx::Size& viewport_size) {
@@ -189,32 +210,21 @@
     buffers_.clear();
     current_buffer_ = nullptr;
     previous_buffer_ = nullptr;
+    pending_buffer_ = nullptr;
+    unsubmitted_buffers_.clear();
   }
   size_ = viewport_size;
 }
 
 void WaylandCanvasSurface::PresentCanvas(const gfx::Rect& damage) {
-  DCHECK(current_buffer_);
-  // The buffer has been updated. Thus, the |damage| can be subtracted from its
-  // dirty region.
-  current_buffer_->UpdateDirtyRegion(damage, SkRegion::kDifference_Op);
+  if (!pending_buffer_)
+    return;
 
-  // Make sure the buffer is up-to-date by copying the outdated region from the
-  // previous buffer.
-  if (previous_buffer_ && previous_buffer_ != current_buffer_)
-    current_buffer_->CopyDirtyRegionFrom(previous_buffer_);
+  pending_buffer_->SetPendingDamageRegion(damage);
+  unsubmitted_buffers_.push_back(pending_buffer_);
+  pending_buffer_ = nullptr;
 
-  // As long as the |current_buffer_| has been updated, add dirty region to
-  // other buffers to make sure their regions will be updated with up-to-date
-  // content.
-  for (auto& buffer : buffers_) {
-    if (buffer.get() != current_buffer_)
-      buffer->UpdateDirtyRegion(damage, SkRegion::kUnion_Op);
-  }
-
-  current_buffer_->CommitBuffer(damage);
-  previous_buffer_ = current_buffer_;
-  current_buffer_ = nullptr;
+  ProcessUnsubmittedBuffers();
 }
 
 std::unique_ptr<gfx::VSyncProvider>
@@ -225,15 +235,53 @@
   return nullptr;
 }
 
+void WaylandCanvasSurface::ProcessUnsubmittedBuffers() {
+  DCHECK(!unsubmitted_buffers_.empty());
+
+  if (!current_buffer_ && unsubmitted_buffers_.front()->pending()) {
+    current_buffer_ = std::move(unsubmitted_buffers_.front());
+    unsubmitted_buffers_.erase(unsubmitted_buffers_.begin());
+
+    gfx::Rect damage = current_buffer_->pending_damage_region();
+
+    // The buffer has been updated. Thus, the |damage| can be subtracted
+    // from its dirty region.
+    current_buffer_->UpdateDirtyRegion(damage, SkRegion::kDifference_Op);
+
+    // Make sure the buffer is up-to-date by copying the outdated region from
+    // the previous buffer.
+    if (previous_buffer_ && previous_buffer_ != current_buffer_)
+      current_buffer_->CopyDirtyRegionFrom(previous_buffer_);
+
+    // As long as the |current_buffer_| has been updated, add dirty region to
+    // other buffers to make sure their regions will be updated with up-to-date
+    // content.
+    for (auto& buffer : buffers_) {
+      if (buffer.get() != current_buffer_)
+        buffer->UpdateDirtyRegion(damage, SkRegion::kUnion_Op);
+    }
+
+    current_buffer_->CommitBuffer(damage);
+  }
+}
+
 void WaylandCanvasSurface::OnSubmission(uint32_t buffer_id,
                                         const gfx::SwapResult& swap_result) {
-  auto buffer_it = std::find_if(
-      buffers_.begin(), buffers_.end(),
-      [buffer_id](auto& buffer) { return buffer->buffer_id() == buffer_id; });
   // Upper layer does not care about the submission result, and the buffer may
   // be destroyed by this time (when the surface is resized, for example).
-  if (buffer_it != buffers_.end())
-    buffer_it->get()->OnSubmissionCompleted();
+  if (!current_buffer_)
+    return;
+
+  DCHECK_EQ(current_buffer_->buffer_id(), buffer_id);
+
+  auto* buffer = current_buffer_;
+  previous_buffer_ = buffer;
+  current_buffer_ = nullptr;
+
+  buffer->OnSubmissionCompleted();
+
+  if (!unsubmitted_buffers_.empty())
+    ProcessUnsubmittedBuffers();
 }
 
 void WaylandCanvasSurface::OnPresentation(
diff --git a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h
index fef7aea..a759672 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h
@@ -42,6 +42,8 @@
   // is backed by that shared region.
   class SharedMemoryBuffer;
 
+  void ProcessUnsubmittedBuffers();
+
   // WaylandSurfaceGpu overrides:
   void OnSubmission(uint32_t buffer_id,
                     const gfx::SwapResult& swap_result) override;
@@ -57,11 +59,18 @@
   gfx::Size size_;
   std::vector<std::unique_ptr<SharedMemoryBuffer>> buffers_;
 
-  // Currently used buffer. Set on GetSurface() and released on PresentCanvas()
-  // call.
+  // Contains pending to be submitted buffers. The vector is processed as FIFO.
+  std::vector<SharedMemoryBuffer*> unsubmitted_buffers_;
+
+  // Pending buffer that is to be placed into the |unsubmitted_buffers_| to be
+  // processed.
+  SharedMemoryBuffer* pending_buffer_ = nullptr;
+
+  // Currently used buffer. Set on PresentCanvas() and released on
+  // OnSubmission() call.
   SharedMemoryBuffer* current_buffer_ = nullptr;
 
-  // Previously used buffer. Set on PresentCanvas().
+  // Previously used buffer. Set on OnSubmission().
   SharedMemoryBuffer* previous_buffer_ = nullptr;
 
   // The id of the current existing buffer. Even though, there can only be one
diff --git a/ui/views/linux_ui/linux_ui.cc b/ui/views/linux_ui/linux_ui.cc
index f22eaccc..0c4ab3a0 100644
--- a/ui/views/linux_ui/linux_ui.cc
+++ b/ui/views/linux_ui/linux_ui.cc
@@ -19,7 +19,12 @@
 void LinuxUI::SetInstance(LinuxUI* instance) {
   delete g_linux_ui;
   g_linux_ui = instance;
+// Do not set IME instance for ozone as we delegate creating the input method to
+// OzonePlatforms instead. If this is set, OzonePlatform never sets a context
+// factory.
+#if !defined(USE_OZONE)
   LinuxInputMethodContextFactory::SetInstance(instance);
+#endif
   SkiaFontDelegate::SetInstance(instance);
   ShellDialogLinux::SetInstance(instance);
   ui::SetTextEditKeyBindingsDelegate(instance);