diff --git a/BUILD.gn b/BUILD.gn
index 2c25037..2d6f331 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -69,11 +69,16 @@
     "//chrome/installer",
     "//chrome/updater",
     "//net:net_unittests",
+    "//services:services_unittests",
+    "//services/service_manager/public/cpp",
     "//skia:skia_unittests",
     "//sql:sql_unittests",
+    "//third_party/flatbuffers:flatbuffers_unittests",
     "//tools/binary_size:binary_size_trybot_py",
     "//tools/ipc_fuzzer:ipc_fuzzer_all",
+    "//tools/metrics:metrics_metadata",
     "//ui/base:ui_base_unittests",
+    "//ui/gfx:gfx_unittests",
     "//url:url_unittests",
   ]
 
@@ -85,14 +90,7 @@
   }
 
   if (!is_fuchsia) {
-    deps += [
-      "//components:components_unittests",
-      "//services:services_unittests",
-      "//services/service_manager/public/cpp",
-      "//third_party/flatbuffers:flatbuffers_unittests",
-      "//tools/metrics:metrics_metadata",
-      "//ui/gfx:gfx_unittests",
-    ]
+    deps += [ "//components:components_unittests" ]
   }
 
   if (closure_compile) {
@@ -626,6 +624,9 @@
 
   if (is_chromecast) {
     deps += [ "//chromecast:cast_shell" ]
+    if (enable_extensions && use_aura) {
+      deps += [ "//chrome/browser/resources/chromeos/chromevox" ]
+    }
   }
 
   if (is_mac || is_win || is_android || (is_linux && !is_chromeos)) {
diff --git a/DEPS b/DEPS
index b9bce90..9482f5eb 100644
--- a/DEPS
+++ b/DEPS
@@ -129,7 +129,7 @@
   # 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': 'e1c5ea6779f431023c54e801c662723b3547381a',
+  'skia_revision': 'be2062c4305f05b4d29239e89dd7ab5108cbb7e1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -145,7 +145,7 @@
   # 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': '64b761a8af9b7f15895de979e242d9d74f51321d',
+  'swiftshader_revision': '428c645874c29a1116b775ed73ff780e086a9150',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -196,7 +196,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': 'b614c567e8b363220b00ce5557a3ddfd8d18357c',
+  'catapult_revision': '9de7d78395ad6c009e3a040e0641dfae642ceb5d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -212,7 +212,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.
-  'feed_revision': 'd1e6b4e648a89fb58f706eb182f16053fa95f1fe',
+  'feed_revision': 'd50f6d477b1ddf9294f324fa601a1f085084fba5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
@@ -264,7 +264,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.
-  'shaderc_revision': 'ff9ae40e3734a264a56bba02191f5ae18c7e5e03',
+  'shaderc_revision': '59a49bc5cdff252c6e56e2176255398ace226a90',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1183,7 +1183,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '27acfdb0261ea24940109aeb4444f55b94eae720',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'b2622a5caffbd4aae2e7137224471e555bfd1834',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1354,7 +1354,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3f6583d3fee4ab71866ade794504a20eb6f63f88',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '8607f843a71d0718e2a753a027dc703c5de03f69',
+    Var('webrtc_git') + '/src.git' + '@' + 'ff7730d2ba2b1d2fcf9ed55f51f20b8256d9c31d',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1395,7 +1395,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@93758446cf84566ab8617abea5a9ab70e8305a19',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e33c9cf2e4ee04c6ad5adb2c7a4de0dc626fe5fe',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 146e0b99..88d0b8ae 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -400,6 +400,10 @@
 const char kDeviceBatteryChargeCustomStopCharging[] =
     "ash.power.battery_charge_custom_stop_charging";
 
+// A boolean pref that indicates whether USB power share is enabled.
+// For details see "DeviceUsbPowerShareEnabled" in policy_templates.json.
+const char kDeviceUsbPowerShareEnabled[] = "ash.power.usb_power_share_enabled";
+
 // NOTE: New prefs should start with the "ash." prefix. Existing prefs moved
 // into this file should not be renamed, since they may be synced.
 
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index a82f7fa5..71fd2c2 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -151,6 +151,8 @@
 ASH_PUBLIC_EXPORT extern const char kDeviceBatteryChargeCustomStartCharging[];
 ASH_PUBLIC_EXPORT extern const char kDeviceBatteryChargeCustomStopCharging[];
 
+ASH_PUBLIC_EXPORT extern const char kDeviceUsbPowerShareEnabled[];
+
 }  // namespace prefs
 
 }  // namespace ash
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc
index f8c655e..233b3512d 100644
--- a/ash/system/power/power_prefs.cc
+++ b/ash/system/power/power_prefs.cc
@@ -256,6 +256,9 @@
                                 -1, PrefRegistry::PUBLIC);
   registry->RegisterIntegerPref(prefs::kDeviceBatteryChargeCustomStopCharging,
                                 -1, PrefRegistry::PUBLIC);
+
+  registry->RegisterBooleanPref(prefs::kDeviceUsbPowerShareEnabled, true,
+                                PrefRegistry::PUBLIC);
 }
 
 // static
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 7a0741f4..e7d8e60 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -300,10 +300,29 @@
     UpdateMaskAndShadow();
 
   if (cannot_snap_widget_) {
-    ScopedOverviewAnimationSettings settings(
-        new_animation_type, cannot_snap_widget_->GetNativeWindow());
+    gfx::RectF previous_bounds =
+        gfx::RectF(cannot_snap_widget_->GetNativeWindow()->GetBoundsInScreen());
+    inset_bounds.Inset(
+        gfx::Insets(static_cast<float>(kHeaderHeightDp), 0.f, 0.f, 0.f));
     cannot_snap_widget_->SetBoundsCenteredIn(
         gfx::ToEnclosingRect(inset_bounds));
+    if (new_animation_type != OVERVIEW_ANIMATION_NONE) {
+      // For animations, compute the transform needed to place the widget at its
+      // new bounds back to the old bounds, and then apply the idenity
+      // transform. This so the bounds visually line up with |item_widget_| and
+      // |window_|. This will not happen if we animate the bounds.
+      gfx::RectF current_bounds = gfx::RectF(
+          cannot_snap_widget_->GetNativeWindow()->GetBoundsInScreen());
+      gfx::Transform transform(
+          previous_bounds.width() / current_bounds.width(), 0.f, 0.f,
+          previous_bounds.height() / current_bounds.height(),
+          previous_bounds.x() - current_bounds.x(),
+          previous_bounds.y() - current_bounds.y());
+      cannot_snap_widget_->GetNativeWindow()->SetTransform(transform);
+      ScopedOverviewAnimationSettings settings(
+          new_animation_type, cannot_snap_widget_->GetNativeWindow());
+      cannot_snap_widget_->GetNativeWindow()->SetTransform(gfx::Transform());
+    }
   }
 }
 
@@ -335,6 +354,8 @@
   };
 
   AnimateOpacity(0.0, OVERVIEW_ANIMATION_CLOSE_OVERVIEW_ITEM);
+  if (cannot_snap_widget_)
+    animate_window(cannot_snap_widget_->GetNativeWindow(), transform, false);
   animate_window(item_widget_->GetNativeWindow(), transform, false);
   animate_window(GetWindowForStacking(), transform, true);
 }
@@ -398,7 +419,7 @@
                                   : SPLITVIEW_ANIMATION_OVERVIEW_ITEM_FADE_OUT);
   gfx::Rect bounds = gfx::ToEnclosingRect(target_bounds());
   bounds.Inset(kWindowMargin, kWindowMargin);
-  bounds.Inset(gfx::Insets(0, kHeaderHeightDp, 0, 0));
+  bounds.Inset(gfx::Insets(kHeaderHeightDp, 0, 0, 0));
   cannot_snap_widget_->SetBoundsCenteredIn(bounds);
 }
 
@@ -587,6 +608,8 @@
 void OverviewItem::SetOpacity(float opacity) {
   item_widget_->SetOpacity(opacity);
   transform_window_.SetOpacity(opacity);
+  if (cannot_snap_widget_)
+    cannot_snap_widget_->SetOpacity(opacity);
 }
 
 float OverviewItem::GetOpacity() {
@@ -856,6 +879,14 @@
   ScopedOverviewAnimationSettings animation_settings_label(animation_type,
                                                            widget_window);
   widget_window->layer()->SetOpacity(header_opacity);
+
+  if (cannot_snap_widget_) {
+    aura::Window* cannot_snap_widget_window =
+        cannot_snap_widget_->GetNativeWindow();
+    ScopedOverviewAnimationSettings animation_settings_label(
+        animation_type, cannot_snap_widget_window);
+    cannot_snap_widget_window->layer()->SetOpacity(opacity);
+  }
 }
 
 void OverviewItem::StartDrag() {
diff --git a/base/android/library_loader/library_prefetcher_unittest.cc b/base/android/library_loader/library_prefetcher_unittest.cc
index ebb0d48f..67ae24c 100644
--- a/base/android/library_loader/library_prefetcher_unittest.cc
+++ b/base/android/library_loader/library_prefetcher_unittest.cc
@@ -8,7 +8,7 @@
 #include <stdint.h>
 #include <sys/mman.h>
 #include "base/android/library_loader/anchor_functions_buildflags.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,9 +24,11 @@
 
 TEST(NativeLibraryPrefetcherTest, TestPercentageOfResidentCode) {
   size_t length = 4 * kPageSize;
-  base::SharedMemory shared_mem;
-  ASSERT_TRUE(shared_mem.CreateAndMapAnonymous(length));
-  void* address = shared_mem.memory();
+  auto shared_region = base::WritableSharedMemoryRegion::Create(length);
+  ASSERT_TRUE(shared_region.IsValid());
+  auto mapping = shared_region.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  void* address = mapping.memory();
   size_t start = reinterpret_cast<size_t>(address);
   size_t end = start + length;
 
diff --git a/base/memory/platform_shared_memory_region_posix.cc b/base/memory/platform_shared_memory_region_posix.cc
index a17b4c1..f577c81 100644
--- a/base/memory/platform_shared_memory_region_posix.cc
+++ b/base/memory/platform_shared_memory_region_posix.cc
@@ -261,20 +261,33 @@
     }
   }
 
-  // Get current size.
-  struct stat stat = {};
-  if (fstat(fd.get(), &stat) != 0)
+#if defined(OS_LINUX)
+  // Unlike ftruncate(), fallocate() always allocates disk space, so we get an
+  // error if the disk is full. https://crbug.com/951431
+  if (HANDLE_EINTR(fallocate(fd.get(), 0, 0, size)) != 0) {
+    PLOG(ERROR) << "Failed to reserve " << size << " bytes for shared memory.";
     return {};
-  const size_t current_size = stat.st_size;
-  if (current_size != size) {
-    if (HANDLE_EINTR(ftruncate(fd.get(), size)) != 0)
-      return {};
   }
+#else
+  // fallocate() is a Linux-specific syscall, fallback to ftruncate().
+  if (HANDLE_EINTR(ftruncate(fd.get(), size)) != 0) {
+    DPLOG(ERROR) << "ftruncate() failed";
+    return {};
+  }
+#endif
 
   if (readonly_fd.is_valid()) {
+    struct stat stat = {};
+    if (fstat(fd.get(), &stat) != 0) {
+      DPLOG(ERROR) << "fstat(fd) failed";
+      return {};
+    }
+
     struct stat readonly_stat = {};
-    if (fstat(readonly_fd.get(), &readonly_stat))
-      NOTREACHED();
+    if (fstat(readonly_fd.get(), &readonly_stat) != 0) {
+      DPLOG(ERROR) << "fstat(readonly_fd) failed";
+      return {};
+    }
 
     if (stat.st_dev != readonly_stat.st_dev ||
         stat.st_ino != readonly_stat.st_ino) {
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
index e70e019..c4a573b2 100644
--- a/base/process/process_metrics_unittest.cc
+++ b/base/process/process_metrics_unittest.cc
@@ -17,7 +17,8 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_mapping.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
@@ -657,14 +658,19 @@
   ASSERT_GT(counts.minor, 0);
   ASSERT_GE(counts.major, 0);
 
+  // Allocate and touch memory. Touching it is required to make sure that the
+  // page fault count goes up, as memory is typically mapped lazily.
   {
-    // Allocate and touch memory. Touching it is required to make sure that the
-    // page fault count goes up, as memory is typically mapped lazily.
-    const size_t kMappedSize = 4 * (1 << 20);
-    SharedMemory memory;
-    ASSERT_TRUE(memory.CreateAndMapAnonymous(kMappedSize));
-    memset(memory.memory(), 42, kMappedSize);
-    memory.Unmap();
+    const size_t kMappedSize = 4 << 20;  // 4 MiB.
+
+    WritableSharedMemoryRegion region =
+        WritableSharedMemoryRegion::Create(kMappedSize);
+    ASSERT_TRUE(region.IsValid());
+
+    WritableSharedMemoryMapping mapping = region.Map();
+    ASSERT_TRUE(mapping.IsValid());
+
+    memset(mapping.memory(), 42, kMappedSize);
   }
 
   PageFaultCounts counts_after;
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index 04e17a54..38bcd40c 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -308,6 +308,7 @@
     "v8/workers/zapped_for_debug/isolate_0x?",
     "site_storage/index_db/db_0x?",
     "site_storage/index_db/memenv_0x?",
+    "site_storage/local_storage/0x?/cache_size",
     "site_storage/localstorage/0x?/cache_size",
     "site_storage/localstorage/0x?/leveldb",
     "site_storage/session_storage/0x?",
diff --git a/build/android/gyp/create_app_bundle.py b/build/android/gyp/create_app_bundle.py
index b7b5106f..9666feb3 100755
--- a/build/android/gyp/create_app_bundle.py
+++ b/build/android/gyp/create_app_bundle.py
@@ -25,11 +25,11 @@
 # Location of language-based assets in bundle modules.
 _LOCALES_SUBDIR = 'assets/locales/'
 
-# The fallback language should always have its .pak files included in
+# The fallback locale should always have its .pak file included in
 # the base apk, i.e. not use language-based asset targetting. This ensures
 # that Chrome won't crash on startup if its bundle is installed on a device
 # with an unsupported system locale (e.g. fur-rIT).
-_FALLBACK_LANGUAGE = 'en'
+_FALLBACK_LOCALE = 'en-US'
 
 # List of split dimensions recognized by this tool.
 _ALL_SPLIT_DIMENSIONS = [ 'ABI', 'SCREEN_DENSITY', 'LANGUAGE' ]
@@ -178,6 +178,9 @@
   # Whether other .so files are compressed is controlled by
   # "uncompressNativeLibraries".
   uncompressed_globs = ['lib/*/crazy.*']
+  # Locale-specific pak files stored in bundle splits need not be compressed.
+  uncompressed_globs.extend(
+      ['assets/locales#lang_*/*.pak', 'assets/fallback-locales/*.pak'])
   uncompressed_globs.extend('assets/' + x for x in uncompressed_assets)
   # NOTE: Use '**' instead of '*' to work through directories!
   uncompressed_globs.extend('**.' + ext for ext in _UNCOMPRESSED_FILE_EXTS)
@@ -227,8 +230,8 @@
   else:
     android_language = android_locale
 
-  if android_language == _FALLBACK_LANGUAGE:
-    # Fallback language .pak files must be placed in a different directory
+  if locale == _FALLBACK_LOCALE:
+    # Fallback locale .pak files must be placed in a different directory
     # to ensure they are always stored in the base module.
     result_path = 'assets/fallback-locales/%s.pak' % locale
   else:
diff --git a/build/config/c++/BUILD.gn b/build/config/c++/BUILD.gn
index abe3be0d..226e89dc 100644
--- a/build/config/c++/BUILD.gn
+++ b/build/config/c++/BUILD.gn
@@ -75,6 +75,8 @@
     # and can also result in build failures if libc++'s name for a library
     # does not match ours.
     defines += [ "_LIBCPP_NO_AUTO_LINK" ]
+
+    configs = [ "//tools/win/DebugVisualizers:libc++" ]
   } else {
     cflags_cc += [
       "-nostdinc++",
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 256b6db..5ed604a 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -292,7 +292,7 @@
 config("winver") {
   defines = [
     "NTDDI_VERSION=NTDDI_WIN10_RS2",
-    
+
     # We can't say `=_WIN32_WINNT_WIN10` here because some files do
     # `#if WINVER < 0x0600` without including windows.h before,
     # and then _WIN32_WINNT_WIN10 isn't yet known to be 0x0A00.
@@ -377,9 +377,8 @@
   # lots of child processes, so this means things are really slow. Disable CFG
   # for now. https://crbug.com/846966
   if (!is_debug && !is_component_build && !is_asan) {
-    # Turn on CFG in msvc linker, regardless of compiler used. Turn off CFG for
-    # longjmp (new in VS 2017) because it relies on compiler support which we do
-    # not have enabled.
+    # Turn on CFG, except for longjmp because it relies on compiler support
+    # which clang doesn't have yet.
     ldflags = [ "/guard:cf,nolongjmp" ]
   }
 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 4dd6502..4d7fbcbc 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8916129137480703632
\ No newline at end of file
+8916106009791725872
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index d041505..863f00c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8916140137766260112
\ No newline at end of file
+8916121791194673392
\ No newline at end of file
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 6d59a29..53c2f32 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -204,6 +204,9 @@
     // http://crbug.com/797998
     "race:content::SandboxIPCHandler::HandleLocaltime\n"
 
+    // http://crbug.com/927330
+    "race:net::(anonymous namespace)::g_network_change_notifier\n"
+
     // End of suppressions.
     ;  // Please keep this semicolon.
 
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index fae9561f..307c040 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1673,7 +1673,6 @@
   "java/src/org/chromium/chrome/browser/ui/ImmersiveModeManager.java",
   "java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java",
   "java/src/org/chromium/chrome/browser/ui/system/NavigationBarColorController.java",
-  "java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java",
   "java/src/org/chromium/chrome/browser/ui/system/SystemUiCoordinator.java",
   "java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java",
   "java/src/org/chromium/chrome/browser/util/ChromeContextUtil.java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
index bccdc873..e94dacb 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
@@ -16,7 +16,9 @@
 import com.google.android.libraries.feed.host.logging.ScrollType;
 import com.google.android.libraries.feed.host.logging.SessionEvent;
 import com.google.android.libraries.feed.host.logging.SpinnerType;
+import com.google.android.libraries.feed.host.logging.Task;
 import com.google.android.libraries.feed.host.logging.ZeroStateShowReason;
+import com.google.search.now.ui.action.FeedActionProto;
 
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
@@ -133,23 +135,20 @@
     }
 
     @Override
-    public void onNotInterestedInSource(ContentLoggingData data, boolean wasCommitted) {
+    public void onNotInterestedIn(int interestType, ContentLoggingData data, boolean wasCommitted) {
         // Bridge could have been destroyed for policy when this is called.
         // See https://crbug.com/901414.
         if (mNativeFeedLoggingBridge == 0) return;
 
-        nativeOnNotInterestedInSource(
-                mNativeFeedLoggingBridge, data.getPositionInStream(), wasCommitted);
-    }
-
-    @Override
-    public void onNotInterestedInTopic(ContentLoggingData data, boolean wasCommitted) {
-        // Bridge could have been destroyed for policy when this is called.
-        // See https://crbug.com/901414.
-        if (mNativeFeedLoggingBridge == 0) return;
-
-        nativeOnNotInterestedInTopic(
-                mNativeFeedLoggingBridge, data.getPositionInStream(), wasCommitted);
+        // TODO(crbug.com/935602): Fail to compile when new values are added to NotInterestedInData.
+        if (interestType == FeedActionProto.NotInterestedInData.RecordedInterestType.TOPIC_VALUE) {
+            nativeOnNotInterestedInTopic(
+                    mNativeFeedLoggingBridge, data.getPositionInStream(), wasCommitted);
+        } else if (interestType
+                == FeedActionProto.NotInterestedInData.RecordedInterestType.SOURCE_VALUE) {
+            nativeOnNotInterestedInSource(
+                    mNativeFeedLoggingBridge, data.getPositionInStream(), wasCommitted);
+        }
     }
 
     @Override
@@ -273,6 +272,11 @@
         // TODO(https://crbug.com/924739): Implementation.
     }
 
+    @Override
+    public void onTaskFinished(@Task int task, int delayTime, int taskTime) {
+        // TODO(https://crbug.com/924739): Implementation.
+    }
+
     /**
      * Reports how long a user spends on the page.
      *
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
index bb106d1..4ca6b1b 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
@@ -13,7 +13,6 @@
 import com.google.android.libraries.feed.host.config.DebugBehavior;
 import com.google.android.libraries.feed.host.network.NetworkClient;
 import com.google.android.libraries.feed.host.stream.TooltipSupportedApi;
-import com.google.android.libraries.feed.hostimpl.logging.LoggingApiImpl;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
@@ -137,15 +136,15 @@
         NetworkClient networkClient = sTestNetworkClient == null ?
             new FeedNetworkBridge(profile) : sTestNetworkClient;
         sFeedLoggingBridge = new FeedLoggingBridge(profile);
-        sFeedProcessScope = new FeedProcessScope
-                                    .Builder(configHostApi, Executors.newSingleThreadExecutor(),
-                                            new LoggingApiImpl(), sFeedLoggingBridge, networkClient,
-                                            schedulerBridge, DebugBehavior.SILENT,
-                                            ContextUtils.getApplicationContext(), applicationInfo,
-                                            new StubFeedTooltiSupportedApi())
-                                    .setContentStorage(contentStorage)
-                                    .setJournalStorage(journalStorage)
-                                    .build();
+        sFeedProcessScope =
+                new FeedProcessScope
+                        .Builder(configHostApi, Executors.newSingleThreadExecutor(),
+                                sFeedLoggingBridge, networkClient, schedulerBridge,
+                                DebugBehavior.SILENT, ContextUtils.getApplicationContext(),
+                                applicationInfo, new StubFeedTooltiSupportedApi())
+                        .setContentStorage(contentStorage)
+                        .setJournalStorage(journalStorage)
+                        .build();
         schedulerBridge.initializeFeedDependencies(
                 sFeedProcessScope.getRequestManager(), sFeedProcessScope.getSessionManager());
 
@@ -179,13 +178,13 @@
         ApplicationInfo applicationInfo =
                 new ApplicationInfo.Builder(ContextUtils.getApplicationContext()).build();
 
-        sFeedProcessScope = new FeedProcessScope
-                                    .Builder(configHostApi, Executors.newSingleThreadExecutor(),
-                                            new LoggingApiImpl(), sFeedLoggingBridge, networkClient,
-                                            sFeedScheduler, DebugBehavior.SILENT,
-                                            ContextUtils.getApplicationContext(), applicationInfo,
-                                            new StubFeedTooltiSupportedApi())
-                                    .build();
+        sFeedProcessScope =
+                new FeedProcessScope
+                        .Builder(configHostApi, Executors.newSingleThreadExecutor(),
+                                sFeedLoggingBridge, networkClient, sFeedScheduler,
+                                DebugBehavior.SILENT, ContextUtils.getApplicationContext(),
+                                applicationInfo, new StubFeedTooltiSupportedApi())
+                        .build();
     }
 
     /** Use supplied NetworkClient instead of real one, for tests. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java
index 50d2783..5cbeabf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java
@@ -225,9 +225,8 @@
     public void updateTaskDescription(String label, Bitmap icon) {
         int color = mDefaultThemeColor;
         if (mCurrentTab != null) {
-            if (!TabThemeColorHelper.isDefaultColorUsed(mCurrentTab)) {
-                color = TabThemeColorHelper.getColor(mCurrentTab);
-            }
+            TabThemeColorHelper tabTheme = TabThemeColorHelper.get(mCurrentTab);
+            if (!tabTheme.isDefaultColor()) color = tabTheme.getColor();
         }
         ApiCompatibilityUtils.setTaskDescription(mActivity, label, icon, color);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 2423476..0d6a74e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -14,6 +14,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -132,6 +133,7 @@
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabThemeColorHelper;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModel;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -140,14 +142,15 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
+import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.chrome.browser.tabmodel.TabWindowManager;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.chrome.browser.toolbar.top.Toolbar;
 import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer;
 import org.chromium.chrome.browser.translate.TranslateBridge;
 import org.chromium.chrome.browser.ui.RootUiCoordinator;
-import org.chromium.chrome.browser.ui.system.StatusBarColorController;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
+import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.vr.ArDelegate;
@@ -198,8 +201,7 @@
 public abstract class ChromeActivity<C extends ChromeActivityComponent>
         extends AsyncInitializationActivity
         implements TabCreatorManager, AccessibilityStateChangeListener, PolicyChangeListener,
-                   ContextualSearchTabPromotionDelegate, SnackbarManageable, SceneChangeObserver,
-                   StatusBarColorController.StatusBarColorProvider {
+                   ContextualSearchTabPromotionDelegate, SnackbarManageable, SceneChangeObserver {
     /**
      * Factory which creates the AppMenuHandler.
      */
@@ -250,6 +252,7 @@
 
     private TabModelSelector mTabModelSelector;
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
+    private ActivityTabProvider.ActivityTabTabObserver mStatusBarColorTabObserver;
     private TabCreatorManager.TabCreator mRegularTabCreator;
     private TabCreatorManager.TabCreator mIncognitoTabCreator;
     private TabContentManager mTabContentManager;
@@ -297,7 +300,9 @@
     private BottomSheetController mBottomSheetController;
     private BottomSheet mBottomSheet;
     private ScrimView mScrimView;
-    private StatusBarColorController mStatusBarColorController;
+    private float mStatusBarScrimFraction;
+    private int mBaseStatusBarColor;
+    private int mScrimColor;
 
     // Timestamp in ms when initial layout inflation begins
     private long mInflateInitialLayoutBeginMs;
@@ -438,8 +443,10 @@
             super.performPostInflationStartup();
 
             ViewGroup coordinator = findViewById(R.id.coordinator);
-            mScrimView = new ScrimView(
-                    this, getStatusBarColorController().getStatusBarScrimDelegate(), coordinator);
+            mScrimView = new ScrimView(this, (fraction) -> {
+                mStatusBarScrimFraction = fraction;
+                setStatusBarColor(null, mBaseStatusBarColor);
+            }, coordinator);
 
             Intent intent = getIntent();
             if (intent != null && getSavedInstanceState() == null) {
@@ -608,8 +615,11 @@
     @Override
     protected void onInitialLayoutInflationComplete() {
         mInflateInitialLayoutEndMs = SystemClock.elapsedRealtime();
-
-        getStatusBarColorController().updateStatusBarColor(true);
+        // Set the status bar color to white by default.
+        boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(this);
+        setStatusBarColor(
+                isTablet ? Color.BLACK : ColorUtils.getDefaultThemeColor(getResources(), false),
+                true);
 
         ViewGroup rootView = (ViewGroup) getWindow().getDecorView().getRootView();
         mCompositorViewHolder = (CompositorViewHolder) findViewById(R.id.compositor_view_holder);
@@ -693,7 +703,6 @@
         mActivityTabProvider.setTabModelSelector(mTabModelSelector);
         mTabThemeColorProvider = new TabThemeColorProvider(this);
         mTabThemeColorProvider.setActivityTabProvider(mActivityTabProvider);
-        getStatusBarColorController().setTabModelSelector(mTabModelSelector);
 
         if (mTabModelSelector == null) {
             assert isFinishing();
@@ -728,6 +737,27 @@
             }
         };
 
+        mStatusBarColorTabObserver =
+                new ActivityTabProvider.ActivityTabTabObserver(getActivityTabProvider()) {
+            @Override
+            public void onShown(Tab tab, @TabSelectionType int type) {
+                setStatusBarColor(tab, TabThemeColorHelper.getColor(tab));
+            }
+
+            @Override
+            public void onDidChangeThemeColor(Tab tab, int color) {
+                setStatusBarColor(tab, color);
+            }
+
+            @Override
+            protected void onObservingDifferentTab(Tab tab) {
+                // |tab == null| means we're switching tabs - by the tab switcher or by swiping
+                // on the omnibox. These cases are dealt with differently, elsewhere.
+                if (tab == null) return;
+                setStatusBarColor(tab, TabThemeColorHelper.getColor(tab));
+            }
+        };
+
         if (mAssistStatusHandler != null) {
             mAssistStatusHandler.setTabModelSelector(mTabModelSelector);
         }
@@ -913,21 +943,50 @@
     }
 
     /**
-     * @return The {@link StatusBarColorController} that adjusts the status bar color.
+     * Set device status bar to a given color.
+     * @param tab The tab that is currently showing, used to determine whether {@code color} is the
+     *            default theme color.
+     * @param color The color that the status bar should be set to.
      */
-    public final StatusBarColorController getStatusBarColorController() {
-        // TODO(https://crbug.com/943371): Initialize in SystemUiCoordinator. This requires
-        // SystemUiCoordinator to be created before WebappActivty#onResume().
-        if (mStatusBarColorController == null) {
-            mStatusBarColorController = new StatusBarColorController(this);
-        }
-
-        return mStatusBarColorController;
+    protected void setStatusBarColor(@Nullable Tab tab, int color) {
+        setStatusBarColor(color, tab != null && TabThemeColorHelper.get(tab).isDefaultColor());
     }
 
-    @Override
-    public int getBaseStatusBarColor() {
-        return StatusBarColorController.UNDEFINED_STATUS_BAR_COLOR;
+    /**
+     * Set device status bar to a given color.
+     * @param color The color that the status bar should be set to.
+     * @param isDefaultThemeColor Whether {@code color} is the default theme color.
+     */
+    // TODO(danielpark): Move status bar & status bar icon color logic into helper class.
+    //                   See crbug.com/855079.
+    protected void setStatusBarColor(int color, boolean isDefaultThemeColor) {
+        if (UiUtils.isSystemUiThemingDisabled()) return;
+
+        int statusBarColor = color;
+        boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
+        View root = getWindow().getDecorView().getRootView();
+        if (supportsDarkStatusIcons) {
+            mBaseStatusBarColor = color;
+
+            if (mScrimColor == 0) {
+                mScrimColor =
+                        ApiCompatibilityUtils.getColor(getResources(), R.color.black_alpha_65);
+            }
+            // Apply a color overlay if the scrim is showing.
+            float scrimColorAlpha = (mScrimColor >>> 24) / 255f;
+            int scrimColorOpaque = mScrimColor & 0xFF000000;
+            statusBarColor = ColorUtils.getColorWithOverlay(
+                    statusBarColor, scrimColorOpaque, mStatusBarScrimFraction * scrimColorAlpha);
+
+            boolean needsDarkStatusBarIcons =
+                    !ColorUtils.shouldUseLightForegroundOnBackground(statusBarColor);
+            ApiCompatibilityUtils.setStatusBarIconColor(root, needsDarkStatusBarIcons);
+        } else {
+            statusBarColor = isDefaultThemeColor ? Color.BLACK
+                                                 : ColorUtils.getDarkenedColorForStatusBar(color);
+        }
+
+        ApiCompatibilityUtils.setStatusBarColor(getWindow(), statusBarColor);
     }
 
     private void createContextReporterIfNeeded() {
@@ -1288,6 +1347,11 @@
             mTabModelSelectorTabObserver = null;
         }
 
+        if (mStatusBarColorTabObserver != null) {
+            mStatusBarColorTabObserver.destroy();
+            mStatusBarColorTabObserver = null;
+        }
+
         if (mCompositorViewHolder != null) {
             if (mCompositorViewHolder.getLayoutManager() != null) {
                 mCompositorViewHolder.getLayoutManager().removeSceneChangeObserver(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 2ada68d0..e74fb21 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -195,7 +195,6 @@
     public static final String DONT_AUTO_HIDE_BROWSER_CONTROLS = "DontAutoHideBrowserControls";
     public static final String CHROME_SMART_SELECTION = "ChromeSmartSelection";
     public static final String CLEAR_OLD_BROWSING_DATA = "ClearOldBrowsingData";
-    public static final String CLIPBOARD_CONTENT_SETTING = "ClipboardContentSetting";
     public static final String COMMAND_LINE_ON_NON_ROOTED = "CommandLineOnNonRooted";
     public static final String CONTENT_SUGGESTIONS_NOTIFICATIONS =
             "ContentSuggestionsNotifications";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 3d9899b..39bfbab1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -15,6 +15,7 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ShortcutManager;
+import android.graphics.Color;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -129,6 +130,7 @@
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab.TabThemeColorHelper;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
@@ -149,6 +151,7 @@
 import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer;
 import org.chromium.chrome.browser.usage_stats.UsageStatsService;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
+import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
@@ -164,6 +167,7 @@
 import org.chromium.content_public.browser.WebContentsAccessibility;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.content_public.common.Referrer;
+import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -1609,6 +1613,22 @@
 
         mTabModelSelectorImpl.addObserver(new EmptyTabModelSelectorObserver() {
             @Override
+            public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
+                if (isInOverviewMode()) {
+                    // The passed-in color is ignored when the tab switcher is open. This call
+                    // causes the toolbar color to change (if necessary) based on whether or not
+                    // we're in incognito mode.
+                    setStatusBarColor(null, Color.BLACK);
+                } else {
+                    // When opening a new Incognito Tab from a normal Tab (or vice versa), the
+                    // status bar color is updated. However, this update is triggered after the
+                    // animation, so we update here for the duration of the new Tab animation.
+                    setStatusBarColor(null, ColorUtils.getDefaultThemeColor(
+                            getResources(), newModel.isIncognito()));
+                }
+            }
+
+            @Override
             public void onTabStateInitialized() {
                 if (!mCreatedTabOnStartup) return;
 
@@ -2335,6 +2355,7 @@
         if (getFindToolbarManager() != null) getFindToolbarManager().hideToolbar();
         if (getAssistStatusHandler() != null) getAssistStatusHandler().updateAssistState();
         if (getAppMenuHandler() != null) getAppMenuHandler().hideAppMenu();
+        setStatusBarColor(null, Color.BLACK);
     }
 
     @Override
@@ -2348,6 +2369,36 @@
     @Override
     public void onOverviewModeFinishedHiding() {
         if (getAssistStatusHandler() != null) getAssistStatusHandler().updateAssistState();
+        if (getActivityTab() != null) {
+            setStatusBarColor(getActivityTab(), TabThemeColorHelper.getColor(getActivityTab()));
+        }
+    }
+
+    @Override
+    protected void setStatusBarColor(@Nullable Tab tab, int color) {
+        if (isTablet() || UiUtils.isSystemUiThemingDisabled()) return;
+
+        if (!isInOverviewMode()) {
+            super.setStatusBarColor(tab, color);
+            return;
+        }
+
+        boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
+        if (!supportsDarkStatusIcons) {
+            super.setStatusBarColor(tab, Color.BLACK);
+            return;
+        }
+
+        if (!ChromeFeatureList.isInitialized()
+                || (!ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)
+                           && !DeviceClassManager.enableAccessibilityLayout())) {
+            super.setStatusBarColor(tab, ColorUtils.getDefaultThemeColor(getResources(), false));
+            return;
+        }
+
+        boolean incognito =
+                mTabModelSelectorImpl != null && mTabModelSelectorImpl.isIncognitoSelected();
+        super.setStatusBarColor(tab, ColorUtils.getDefaultThemeColor(getResources(), incognito));
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 8132cf7..9d217d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -268,8 +268,8 @@
             getToolbarManager().setShouldUpdateToolbarPrimaryColor(false);
         }
 
-        getStatusBarColorController().updateStatusBarColor(ColorUtils.isUsingDefaultToolbarColor(
-                getResources(), false, getBaseStatusBarColor()));
+        super.setStatusBarColor(toolbarColor,
+                ColorUtils.isUsingDefaultToolbarColor(getResources(), false, toolbarColor));
 
         // Properly attach tab's infobar to the view hierarchy, as the main tab might have been
         // initialized prior to inflation.
@@ -511,15 +511,16 @@
                 if (tab.isPreview()) {
                     final int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), false);
                     manager.onThemeColorChanged(defaultColor, false);
+                    setStatusBarColor(defaultColor, false);
                     mTriggeredPreviewChange = true;
                 } else if (mOriginalColor != manager.getPrimaryColor() && mTriggeredPreviewChange) {
                     manager.onThemeColorChanged(mOriginalColor, false);
+                    setStatusBarColor(mOriginalColor, false);
 
                     mTriggeredPreviewChange = false;
                     mOriginalColor = 0;
                 }
 
-                getStatusBarColorController().updateStatusBarColor(false);
                 manager.setShouldUpdateToolbarPrimaryColor(shouldUpdateOriginal);
             }
         });
@@ -773,12 +774,10 @@
     }
 
     @Override
-    public int getBaseStatusBarColor() {
-        if (mIntentDataProvider.isOpenedByChrome()) return super.getBaseStatusBarColor();
-        if (getActivityTab() != null && getActivityTab().isPreview()) {
-            return ColorUtils.getDefaultThemeColor(getResources(), false);
-        }
-        return mIntentDataProvider.getToolbarColor();
+    protected void setStatusBarColor(Tab tab, int color) {
+        // Intentionally do nothing as CustomTabActivity explicitly sets status bar color.  Except
+        // for Custom Tabs opened by Chrome.
+        if (mIntentDataProvider.isOpenedByChrome()) super.setStatusBarColor(tab, color);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java
index 87a99a66..7d9396d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferences.java
@@ -102,9 +102,6 @@
             if (!SiteSettingsCategory.adsCategoryEnabled()) {
                 getPreferenceScreen().removePreference(findPreference(Type.ADS));
             }
-            if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CLIPBOARD_CONTENT_SETTING)) {
-                getPreferenceScreen().removePreference(findPreference(Type.CLIPBOARD));
-            }
             // The new Languages Preference *feature* is an advanced version of this translate
             // preference. Once Languages Preference is enabled, remove this setting.
             if (ChromeFeatureList.isEnabled(ChromeFeatureList.LANGUAGES_PREFERENCE)) {
@@ -141,9 +138,7 @@
             }
             websitePrefs.add(Type.BACKGROUND_SYNC);
             websitePrefs.add(Type.CAMERA);
-            if (ChromeFeatureList.isEnabled(ChromeFeatureList.CLIPBOARD_CONTENT_SETTING)) {
-                websitePrefs.add(Type.CLIPBOARD);
-            }
+            websitePrefs.add(Type.CLIPBOARD);
             websitePrefs.add(Type.COOKIES);
             websitePrefs.add(Type.JAVASCRIPT);
             websitePrefs.add(Type.DEVICE_LOCATION);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
index ff0135f4..cccc7062 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
@@ -139,6 +139,13 @@
     }
 
     /**
+     * @return Whether the theme color for this tab is the default color.
+     */
+    public boolean isDefaultColor() {
+        return mTab.isNativePage() || mDefaultColor == getColor();
+    }
+
+    /**
      * @return The default theme color for this tab.
      */
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 4b59128..8d4cdef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -339,7 +339,6 @@
 
         setMenuHandler(menuHandler);
         mToolbar.initialize(mLocationBarModel, this, mAppMenuButtonHelper);
-        mToolbar.addUrlExpansionObserver(activity.getStatusBarColorController());
 
         mAppMenuPropertiesDelegate = appMenuPropertiesDelegate;
 
@@ -1172,8 +1171,6 @@
         if (mLocationBar != null) {
             mLocationBar.removeUrlFocusChangeListener(this);
         }
-
-        mToolbar.removeUrlExpansionObserver(mActivity.getStatusBarColorController());
         mToolbar.destroy();
 
         if (mTabObserver != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index e2d5d0c..377bb29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -23,7 +23,6 @@
 import android.widget.ImageButton;
 import android.widget.ProgressBar;
 
-import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ThemeColorProvider;
@@ -43,7 +42,6 @@
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.ToolbarTabController;
-import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator.UrlExpansionObserver;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.ToolbarProgressBar;
@@ -59,8 +57,6 @@
         extends FrameLayout implements TintObserver, ThemeColorObserver {
     private Invalidator mInvalidator;
 
-    protected final ObserverList<UrlExpansionObserver> mUrlExpansionObservers =
-            new ObserverList<>();
     private final int[] mTempPosition = new int[2];
 
     /**
@@ -72,7 +68,6 @@
 
     private ToolbarDataProvider mToolbarDataProvider;
     private ToolbarTabController mToolbarTabController;
-
     @Nullable
     protected ToolbarProgressBar mProgressBar;
 
@@ -140,20 +135,6 @@
     }
 
     /**
-     * @param urlExpansionObserver The observer that observes URL expansion percentage change.
-     */
-    void addUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) {
-        mUrlExpansionObservers.addObserver(urlExpansionObserver);
-    }
-
-    /**
-     * @param urlExpansionObserver The observer that observes URL expansion percentage change.
-     */
-    void removeUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) {
-        mUrlExpansionObservers.removeObserver(urlExpansionObserver);
-    }
-
-    /**
      * @param themeColorProvider The {@link ThemeColorProvider} used for tinting the toolbar
      *                           buttons.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index f35e9da..4f8cf621 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -69,7 +69,6 @@
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
 import org.chromium.chrome.browser.toolbar.TabSwitcherDrawable;
-import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator.UrlExpansionObserver;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
@@ -717,15 +716,13 @@
         Resources res = getResources();
         switch (visualState) {
             case VisualState.NEW_TAB_NORMAL:
-                // When the NTP fake search box is visible, the background color should be
-                // transparent. When the location bar reaches the top of the screen (i.e. location
-                // bar is fully expanded), the background needs to change back to the default
-                // toolbar color so that the NTP content is not visible beneath the toolbar. In
-                // between the transition, we set a translucent default toolbar color based on
-                // the expansion percentage of the toolbar.
-                return android.support.v4.graphics.ColorUtils.setAlphaComponent(
-                        ColorUtils.getDefaultThemeColor(getResources(), false),
-                        Math.round(mUrlExpansionPercent * 255));
+                if (mUrlExpansionPercent == 1.f) {
+                    // When the location bar reaches the top of the screen, the background needs
+                    // to change back to the default, solid color so that the NTP content is
+                    // not visible beneath the toolbar.
+                    return ColorUtils.getDefaultThemeColor(getResources(), false);
+                }
+                return Color.TRANSPARENT;
             case VisualState.NORMAL:
                 return ColorUtils.getDefaultThemeColor(getResources(), false);
             case VisualState.INCOGNITO:
@@ -915,9 +912,6 @@
 
     private void updateUrlExpansionPercent() {
         mUrlExpansionPercent = Math.max(mNtpSearchBoxScrollPercent, mUrlFocusChangePercent);
-        for (UrlExpansionObserver observer : mUrlExpansionObservers) {
-            observer.onUrlExpansionPercentageChanged(mUrlExpansionPercent);
-        }
         assert mUrlExpansionPercent >= 0;
         assert mUrlExpansionPercent <= 1;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index 24f3dc0..c886339 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -37,19 +37,6 @@
 public class TopToolbarCoordinator implements Toolbar {
     static final int TAB_SWITCHER_MODE_NORMAL_ANIMATION_DURATION_MS = 200;
 
-    /**
-     * Observes toolbar URL expansion percentage change.
-     */
-    public interface UrlExpansionObserver {
-        /**
-         * Notified when toolbar URL expansion percentage changes.
-         * @param percentage The toolbar expansion percentage. 0 indicates that the URL bar is not
-         *                   expanded. 1 indicates that the URL bar is expanded to the maximum
-         *                   width.
-         */
-        void onUrlExpansionPercentageChanged(float percentage);
-    }
-
     private ToolbarLayout mToolbarLayout;
 
     /**
@@ -134,20 +121,6 @@
     }
 
     /**
-     * @param urlExpansionObserver The observer that observes URL expansion percentage change.
-     */
-    public void addUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) {
-        mToolbarLayout.addUrlExpansionObserver(urlExpansionObserver);
-    }
-
-    /**
-     * @param urlExpansionObserver The observer that observes URL expansion percentage change.
-     */
-    public void removeUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) {
-        mToolbarLayout.removeUrlExpansionObserver(urlExpansionObserver);
-    }
-
-    /**
      * @see View#addOnAttachStateChangeListener(View.OnAttachStateChangeListener)
      */
     public void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
deleted file mode 100644
index 168151a..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
+++ /dev/null
@@ -1,281 +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.
-
-package org.chromium.chrome.browser.ui.system;
-
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.annotation.Nullable;
-import android.view.View;
-import android.view.Window;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ActivityTabProvider;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
-import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
-import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.lifecycle.Destroyable;
-import org.chromium.chrome.browser.ntp.NewTabPage;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabThemeColorHelper;
-import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
-import org.chromium.chrome.browser.tabmodel.TabModel;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
-import org.chromium.chrome.browser.tabmodel.TabSelectionType;
-import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator;
-import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.ui.UiUtils;
-
-/**
- * Maintains the status bar color for a {@link ChromeActivity}.
- */
-public class StatusBarColorController
-        implements Destroyable, TopToolbarCoordinator.UrlExpansionObserver {
-    public static @ColorInt int UNDEFINED_STATUS_BAR_COLOR = Color.TRANSPARENT;
-
-    /**
-     * Provides the base status bar color.
-     */
-    public interface StatusBarColorProvider {
-        /**
-         * @return The base status bar color to override default colors used in the
-         *         {@link StatusBarColorController}. If this returns a color other than
-         *         {@link #UNDEFINED_STATUS_BAR_COLOR}, the {@link StatusBarColorController} will
-         *         always use the color provided by this method to adjust the status bar color. This
-         *         color may be used as-is or adjusted due to a scrim overlay or Android version.
-         */
-        @ColorInt
-        int getBaseStatusBarColor();
-    }
-
-    private final Window mWindow;
-    private final boolean mIsTablet;
-    private final @Nullable OverviewModeBehavior mOverviewModeBehavior;
-    private final StatusBarColorProvider mStatusBarColorProvider;
-    private final ScrimView.StatusBarScrimDelegate mStatusBarScrimDelegate;
-    private final ActivityTabProvider.ActivityTabTabObserver mStatusBarColorTabObserver;
-    private final TabModelSelectorObserver mTabModelSelectorObserver;
-
-    private final @ColorInt int mStandardPrimaryBgColor;
-    private final @ColorInt int mIncognitoPrimaryBgColor;
-    private final @ColorInt int mStandardDefaultThemeColor;
-    private final @ColorInt int mIncognitoDefaultThemeColor;
-
-    private @Nullable TabModelSelector mTabModelSelector;
-    private @Nullable OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver;
-    private @Nullable Tab mCurrentTab;
-    private boolean mIsInOverviewMode;
-    private boolean mIsIncognito;
-
-    private @ColorInt int mScrimColor;
-    private float mStatusBarScrimFraction;
-
-    private float mToolbarUrlExpansionPercentage;
-
-    /**
-     * @param chromeActivity The {@link ChromeActivity} that this class is attached to.
-     */
-    public StatusBarColorController(ChromeActivity chromeActivity) {
-        mWindow = chromeActivity.getWindow();
-        mIsTablet = chromeActivity.isTablet();
-        mOverviewModeBehavior = chromeActivity.getOverviewModeBehavior();
-        mStatusBarColorProvider = chromeActivity;
-        mStatusBarScrimDelegate = (fraction) -> {
-            mStatusBarScrimFraction = fraction;
-            updateStatusBarColor(null);
-        };
-
-        Resources resources = chromeActivity.getResources();
-        mStandardPrimaryBgColor = ColorUtils.getPrimaryBackgroundColor(resources, false);
-        mIncognitoPrimaryBgColor = ColorUtils.getPrimaryBackgroundColor(resources, true);
-        mStandardDefaultThemeColor = ColorUtils.getDefaultThemeColor(resources, false);
-        mIncognitoDefaultThemeColor = ColorUtils.getDefaultThemeColor(resources, true);
-
-        mStatusBarColorTabObserver = new ActivityTabProvider.ActivityTabTabObserver(
-                chromeActivity.getActivityTabProvider()) {
-            @Override
-            public void onShown(Tab tab, @TabSelectionType int type) {
-                updateStatusBarColor(tab);
-            }
-
-            @Override
-            public void onDidChangeThemeColor(Tab tab, int color) {
-                updateStatusBarColor(tab);
-            }
-
-            @Override
-            protected void onObservingDifferentTab(Tab tab) {
-                mCurrentTab = tab;
-
-                // |tab == null| means we're switching tabs - by the tab switcher or by swiping
-                // on the omnibox. These cases are dealt with differently, elsewhere.
-                if (tab == null) return;
-                updateStatusBarColor(tab);
-            }
-        };
-
-        mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
-            @Override
-            public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
-                mIsIncognito = newModel.isIncognito();
-
-                // When opening a new Incognito Tab from a normal Tab (or vice versa), the
-                // status bar color is updated. However, this update is triggered after the
-                // animation, so we update here for the duration of the new Tab animation.
-                // See https://crbug.com/917689.
-                updateStatusBarColor(false);
-            }
-        };
-
-        if (mOverviewModeBehavior != null) {
-            mOverviewModeObserver = new EmptyOverviewModeObserver() {
-                @Override
-                public void onOverviewModeStartedShowing(boolean showToolbar) {
-                    mIsInOverviewMode = true;
-                    updateStatusBarColor(false);
-                }
-
-                @Override
-                public void onOverviewModeFinishedHiding() {
-                    mIsInOverviewMode = false;
-                    updateStatusBarColor(mCurrentTab);
-                }
-            };
-            mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
-        }
-
-        chromeActivity.getLifecycleDispatcher().register(this);
-    }
-
-    // Destroyable implementation.
-    @Override
-    public void destroy() {
-        mStatusBarColorTabObserver.destroy();
-        if (mOverviewModeBehavior != null) {
-            mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
-        }
-        if (mTabModelSelector != null) {
-            mTabModelSelector.removeObserver(mTabModelSelectorObserver);
-        }
-    }
-
-    // TopToolbarCoordinator.UrlExpansionObserver implementation.
-    @Override
-    public void onUrlExpansionPercentageChanged(float percentage) {
-        mToolbarUrlExpansionPercentage = percentage;
-        updateStatusBarColor(mCurrentTab);
-    }
-
-    /**
-     * @param tabModelSelector The {@link TabModelSelector} to check whether incognito model is
-     *                         selected.
-     */
-    public void setTabModelSelector(TabModelSelector tabModelSelector) {
-        assert mTabModelSelector == null : "mTabModelSelector should only be set once.";
-        mTabModelSelector = tabModelSelector;
-        if (mTabModelSelector != null) mTabModelSelector.addObserver(mTabModelSelectorObserver);
-    }
-
-    /**
-     * @return The {@link ScrimView.StatusBarScrimDelegate} that adjusts the status bar color based
-     *         on the scrim offset.
-     */
-    public ScrimView.StatusBarScrimDelegate getStatusBarScrimDelegate() {
-        return mStatusBarScrimDelegate;
-    }
-
-    /**
-     * @param isDefaultThemeColor Whether default theme color is used for the status bar color.
-     */
-    public void updateStatusBarColor(boolean isDefaultThemeColor) {
-        setStatusBarColor(calculateBaseStatusBarColor(), isDefaultThemeColor);
-    }
-
-    /**
-     * @param tab The tab that is currently showing, used to determine whether {@code color} is the
-     *            default theme color.
-     */
-    private void updateStatusBarColor(@Nullable Tab tab) {
-        setStatusBarColor(calculateBaseStatusBarColor(),
-                tab != null && TabThemeColorHelper.isDefaultColorUsed(tab));
-    }
-
-    private @ColorInt int calculateBaseStatusBarColor() {
-        // Return overridden status bar color from StatusBarColorProvider if specified.
-        final int baseStatusBarColor = mStatusBarColorProvider.getBaseStatusBarColor();
-        if (baseStatusBarColor != UNDEFINED_STATUS_BAR_COLOR) return baseStatusBarColor;
-
-        // We don't adjust status bar color for tablet when status bar color is not overridden by
-        // StatusBarColorProvider.
-        if (mIsTablet) return Color.BLACK;
-
-        // Return status bar color in overview mode.
-        if (mIsInOverviewMode) {
-            boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
-            if (!supportsDarkStatusIcons) return Color.BLACK;
-
-            if (!ChromeFeatureList.isInitialized()
-                    || (!ChromeFeatureList.isEnabled(
-                                ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)
-                            && !DeviceClassManager.enableAccessibilityLayout())) {
-                return mStandardPrimaryBgColor;
-            }
-
-            return mIsIncognito ? mIncognitoPrimaryBgColor : mStandardPrimaryBgColor;
-        }
-
-        // Return status bar color in standard NewTabPage.
-        if (mCurrentTab != null && NewTabPage.isNTPUrl(mCurrentTab.getUrl()) && !mIsIncognito) {
-            return ColorUtils.getColorWithOverlay(
-                    TabThemeColorHelper.getBackgroundColor(mCurrentTab),
-                    TabThemeColorHelper.getColor(mCurrentTab), mToolbarUrlExpansionPercentage);
-        }
-
-        // Return status bar color to match the toolbar.
-        if (mCurrentTab != null) return TabThemeColorHelper.getColor(mCurrentTab);
-
-        // This could happen when tab is not initialized (e.g. on startup).
-        return mIsIncognito ? mIncognitoDefaultThemeColor : mStandardDefaultThemeColor;
-    }
-
-    /**
-     * Set device status bar to a given color.
-     * @param color The color that the status bar should be set to.
-     * @param isDefaultThemeColor Whether {@code color} is the default theme color.
-     */
-    private void setStatusBarColor(int color, boolean isDefaultThemeColor) {
-        if (UiUtils.isSystemUiThemingDisabled()) return;
-
-        int statusBarColor = color;
-        boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
-        View root = mWindow.getDecorView().getRootView();
-        Resources resources = root.getResources();
-        if (supportsDarkStatusIcons) {
-            if (mScrimColor == 0) {
-                mScrimColor = ApiCompatibilityUtils.getColor(resources, R.color.black_alpha_65);
-            }
-            // Apply a color overlay if the scrim is showing.
-            float scrimColorAlpha = (mScrimColor >>> 24) / 255f;
-            int scrimColorOpaque = mScrimColor & 0xFF000000;
-            statusBarColor = ColorUtils.getColorWithOverlay(
-                    statusBarColor, scrimColorOpaque, mStatusBarScrimFraction * scrimColorAlpha);
-
-            boolean needsDarkStatusBarIcons =
-                    !ColorUtils.shouldUseLightForegroundOnBackground(statusBarColor);
-            ApiCompatibilityUtils.setStatusBarIconColor(root, needsDarkStatusBarIcons);
-        } else {
-            statusBarColor = isDefaultThemeColor ? Color.BLACK
-                                                 : ColorUtils.getDarkenedColorForStatusBar(color);
-        }
-
-        ApiCompatibilityUtils.setStatusBarColor(mWindow, statusBarColor);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 8fde1596..c6a7902 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -769,8 +769,10 @@
         // around an issue where the status bars go transparent and can't be seen on top of the page
         // content when users swipe them in or they appear because the on-screen keyboard was
         // triggered.
+        int statusBarColor = Color.BLACK;
         if (mBrandColor != null && mWebappInfo.displayMode() != WebDisplayMode.FULLSCREEN) {
             taskDescriptionColor = mBrandColor;
+            statusBarColor = mBrandColor;
             if (getToolbarManager() != null) {
                 getToolbarManager().onThemeColorChanged(mBrandColor, false);
             }
@@ -778,18 +780,21 @@
 
         ApiCompatibilityUtils.setTaskDescription(this, title, icon,
                 ColorUtils.getOpaqueColor(taskDescriptionColor));
-        getStatusBarColorController().updateStatusBarColor(getBaseStatusBarColor() != Color.BLACK);
+        setStatusBarColor(statusBarColor, statusBarColor != Color.BLACK);
     }
 
     @Override
-    public int getBaseStatusBarColor() {
-        // Don't use the brand color for the status bars if we're in display: fullscreen. This works
-        // around an issue where the status bars go transparent and can't be seen on top of the page
-        // content when users swipe them in or they appear because the on-screen keyboard was
-        // triggered.
-        return mBrandColor != null && mWebappInfo.displayMode() != WebDisplayMode.FULLSCREEN
-                ? mBrandColor
-                : Color.BLACK;
+    protected void setStatusBarColor(Tab tab, int color) {
+        // Ignore any color that is not the brand color.
+        super.setStatusBarColor(
+                mBrandColor == null ? Color.BLACK : mBrandColor, mBrandColor == null);
+    }
+
+    @Override
+    protected void setStatusBarColor(int color, boolean isDefaultThemeColor) {
+        // Ignore any color that is not the brand color.
+        super.setStatusBarColor(
+                mBrandColor == null ? Color.BLACK : mBrandColor, mBrandColor == null);
     }
 
     @Override
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index feb3097..aa11e3d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1791,6 +1791,7 @@
     "//components/nacl/common:buildflags",
     "//components/payments/core",
     "//components/sync",
+    "//components/sync:device_info",
     "//content/public/browser",
     "//ipc",
     "//sql",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index a745611..f2f39dc 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2988,11 +2988,6 @@
      flag_descriptions::kStopInBackgroundDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(blink::features::kStopInBackground)},
 
-    {"clipboard-content-setting",
-     flag_descriptions::kClipboardContentSettingName,
-     flag_descriptions::kClipboardContentSettingDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kClipboardContentSetting)},
-
     {"enable-network-logging-to-file",
      flag_descriptions::kEnableNetworkLoggingToFileName,
      flag_descriptions::kEnableNetworkLoggingToFileDescription, kOsAll,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index dafc7ae..33f548d 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -68,7 +68,6 @@
     &features::kAllowStartingServiceManagerOnly,
     &features::kAppNotificationStatusMessaging,
     &features::kClearOldBrowsingData,
-    &features::kClipboardContentSetting,
     &features::kDownloadsLocationChange,
     &features::kExperimentalAppBanners,
     &features::kIncognitoStrings,
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn
index d748cc4..6782eba 100644
--- a/chrome/browser/android/vr/BUILD.gn
+++ b/chrome/browser/android/vr/BUILD.gn
@@ -246,5 +246,6 @@
     "//testing/android/native_test:native_test_native_code",
     "//testing/gmock",
     "//testing/gtest:gtest",
+    "//ui/android:ui_java",  # TODO: Remove once http://crbug.com/951419 is fixed!
   ]
 }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index ef3abcf..7f3e65ad 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -16,6 +16,7 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/task/post_task.h"
 #include "base/trace_event/trace_event.h"
@@ -150,6 +151,9 @@
 
 namespace {
 
+// Timeout after which the histogram for slow tasks is recorded.
+const base::TimeDelta kSlowTaskTimeout = base::TimeDelta::FromSeconds(180);
+
 // Generic functions but currently only used when ENABLE_NACL.
 #if BUILDFLAG(ENABLE_NACL)
 void UIThreadTrampolineHelper(base::OnceClosure callback) {
@@ -318,6 +322,15 @@
   TRACE_EVENT0("browsing_data",
                "ChromeBrowsingDataRemoverDelegate::RemoveEmbedderData");
 
+  // To detect tasks that are causing slow deletions, record running sub tasks
+  // after a delay.
+  slow_pending_tasks_closure_.Reset(base::BindRepeating(
+      &ChromeBrowsingDataRemoverDelegate::RecordUnfinishedSubTasks,
+      weak_ptr_factory_.GetWeakPtr()));
+  base::PostDelayedTaskWithTraits(FROM_HERE, {BrowserThread::UI},
+                                  slow_pending_tasks_closure_.callback(),
+                                  kSlowTaskTimeout);
+
   // Embedder-defined DOM-accessible storage currently contains only
   // one datatype, which is the durable storage permission.
   if (remove_mask &
@@ -1115,7 +1128,9 @@
 void ChromeBrowsingDataRemoverDelegate::OnTaskStarted(
     TracingDataType data_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  num_pending_tasks_++;
+  auto result = pending_sub_tasks_.insert(data_type);
+  DCHECK(result.second) << "Task already started: "
+                        << static_cast<int>(data_type);
   TRACE_EVENT_ASYNC_BEGIN1("browsing_data", "ChromeBrowsingDataRemoverDelegate",
                            static_cast<int>(data_type), "data_type",
                            static_cast<int>(data_type));
@@ -1124,14 +1139,16 @@
 void ChromeBrowsingDataRemoverDelegate::OnTaskComplete(
     TracingDataType data_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_GT(num_pending_tasks_, 0);
-  num_pending_tasks_--;
+  size_t num_erased = pending_sub_tasks_.erase(data_type);
+  DCHECK_EQ(num_erased, 1U);
   TRACE_EVENT_ASYNC_END1("browsing_data", "ChromeBrowsingDataRemoverDelegate",
                          static_cast<int>(data_type), "data_type",
                          static_cast<int>(data_type));
-  if (num_pending_tasks_)
+  if (!pending_sub_tasks_.empty())
     return;
 
+  slow_pending_tasks_closure_.Cancel();
+
   DCHECK(!callback_.is_null());
   std::move(callback_).Run();
 }
@@ -1156,6 +1173,14 @@
                      weak_ptr_factory_.GetWeakPtr(), data_type));
 }
 
+void ChromeBrowsingDataRemoverDelegate::RecordUnfinishedSubTasks() {
+  DCHECK(!pending_sub_tasks_.empty());
+  for (TracingDataType task : pending_sub_tasks_) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "History.ClearBrowsingData.Duration.SlowTasks180sChrome", task);
+  }
+}
+
 #if defined(OS_ANDROID)
 void ChromeBrowsingDataRemoverDelegate::OverrideWebappRegistryForTesting(
     std::unique_ptr<WebappRegistry> webapp_registry) {
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
index 4592db3..b3e5b33 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -192,6 +192,8 @@
   using WebRtcEventLogManager = webrtc_event_logging::WebRtcEventLogManager;
 
   // For debugging purposes. Please add new deletion tasks at the end.
+  // This enum is recorded in a histogram, so don't change or reuse ids.
+  // Entries must also be added to ChromeBrowsingDataRemoverTasks in enums.xml.
   enum class TracingDataType {
     kSynchronous = 1,
     kHistory = 2,
@@ -245,6 +247,9 @@
   base::OnceClosure CreateTaskCompletionClosureForMojo(
       TracingDataType data_type);
 
+  // Records unfinished tasks from |pending_sub_tasks_| after a delay.
+  void RecordUnfinishedSubTasks();
+
   // Callback for when TemplateURLService has finished loading. Clears the data,
   // clears the respective waiting flag, and invokes NotifyIfDone.
   void OnKeywordsLoaded(base::RepeatingCallback<bool(const GURL&)> url_filter,
@@ -288,8 +293,12 @@
   // Completion callback to call when all data are deleted.
   base::OnceClosure callback_;
 
-  // Keeps track of number of tasks to be completed.
-  int num_pending_tasks_ = 0;
+  // Records which tasks of a deletion are currently active.
+  std::set<TracingDataType> pending_sub_tasks_;
+
+  // Fires after some time to track slow tasks. Cancelled when all tasks
+  // are finished.
+  base::CancelableClosure slow_pending_tasks_closure_;
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Used to delete plugin data.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 30d0b980..79958b5 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -208,7 +208,6 @@
 #include "components/data_reduction_proxy/content/common/data_reduction_proxy_url_loader_throttle.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/dom_distiller/core/dom_distiller_switches.h"
 #include "components/dom_distiller/core/url_constants.h"
@@ -4656,21 +4655,13 @@
     io_data = ProfileIOData::FromResourceContext(resource_context);
   }
 
-  ChromeNavigationUIData* chrome_navigation_ui_data =
-      static_cast<ChromeNavigationUIData*>(navigation_ui_data);
-  if (chrome_navigation_ui_data && io_data &&
-      io_data->data_reduction_proxy_io_data() &&
+  if (io_data && io_data->data_reduction_proxy_io_data() &&
       data_reduction_proxy::params::IsEnabledWithNetworkService()) {
     net::HttpRequestHeaders headers;
     data_reduction_proxy::DataReductionProxyRequestOptions* request_options =
         io_data->data_reduction_proxy_io_data()->request_options();
-    uint64_t page_id =
-        base::FeatureList::IsEnabled(
-            data_reduction_proxy::features::
-                kDataReductionProxyPopulatePreviewsPageIDToPingback)
-            ? chrome_navigation_ui_data->data_reduction_proxy_page_id()
-            : request_options->GeneratePageId();
-    request_options->AddPageIDRequestHeader(&headers, page_id);
+    request_options->AddPageIDRequestHeader(&headers,
+                                            request_options->GeneratePageId());
     result.push_back(std::make_unique<
                      data_reduction_proxy::DataReductionProxyURLLoaderThrottle>(
         headers,
@@ -4700,6 +4691,8 @@
   }
 #endif  // defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
 
+  ChromeNavigationUIData* chrome_navigation_ui_data =
+      static_cast<ChromeNavigationUIData*>(navigation_ui_data);
   if (chrome_navigation_ui_data &&
       chrome_navigation_ui_data->prerender_mode() != prerender::NO_PRERENDER) {
     result.push_back(std::make_unique<prerender::PrerenderURLLoaderThrottle>(
diff --git a/chrome/browser/chromeos/external_protocol_dialog.cc b/chrome/browser/chromeos/external_protocol_dialog.cc
index fa2f2dd..cbde152 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/external_protocol_dialog.cc
@@ -10,6 +10,8 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/text_elider.h"
@@ -31,18 +33,21 @@
 // static
 void ExternalProtocolHandler::RunExternalProtocolDialog(
     const GURL& url,
-    int render_process_host_id,
-    int routing_id,
+    WebContents* web_contents,
     ui::PageTransition page_transition,
     bool has_user_gesture) {
   // First, check if ARC version of the dialog is available and run ARC version
   // when possible.
+  // TODO(ellyjones): Refactor arc::RunArcExternalProtocolDialog() to take a
+  // web_contents directly, which will mean sorting out how lifetimes work in
+  // that code.
+  int render_process_host_id =
+      web_contents->GetRenderViewHost()->GetProcess()->GetID();
+  int routing_id = web_contents->GetRenderViewHost()->GetRoutingID();
   if (arc::RunArcExternalProtocolDialog(url, render_process_host_id, routing_id,
                                         page_transition, has_user_gesture)) {
     return;
   }
-  WebContents* web_contents = tab_util::GetWebContentsByID(
-      render_process_host_id, routing_id);
   new ExternalProtocolDialog(web_contents, url);
 }
 
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 9a22dcd..c307982 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -1691,6 +1691,7 @@
 }
 
 void FileManagerBrowserTestBase::TearDownOnMainThread() {
+  file_tasks_observer_.reset();
   select_factory_ = nullptr;
   ui::SelectFileDialog::SetFactory(nullptr);
 }
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
index fd3e85a..4024605 100644
--- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -15,7 +15,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/authpolicy/authpolicy_helper.h"
 #include "chrome/browser/chromeos/authpolicy/kerberos_files_handler.h"
 #include "chrome/browser/chromeos/login/active_directory_test_helper.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
@@ -32,6 +31,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/auth_policy/fake_auth_policy_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/tpm/stub_install_attributes.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_names.h"
 #include "content/public/common/network_service_util.h"
@@ -84,7 +84,11 @@
         // Using the same realm as supervised user domain. Should be treated as
         // normal realm.
         test_realm_(user_manager::kSupervisedUserDomain),
-        test_user_(kTestActiveDirectoryUser + ("@" + test_realm_)) {}
+        test_user_(kTestActiveDirectoryUser + ("@" + test_realm_)),
+        install_attributes_(
+            chromeos::StubInstallAttributes::CreateActiveDirectoryManaged(
+                test_realm_,
+                "device_id")) {}
 
   ~ActiveDirectoryLoginTest() override = default;
 
@@ -114,11 +118,6 @@
     LoginManagerTest::SetUpOnMainThread();
   }
 
-  void MarkAsActiveDirectoryEnterprise() {
-    StartupUtils::MarkOobeCompleted();
-    active_directory_test_helper::PrepareLogin(test_user_);
-  }
-
   void TriggerPasswordChangeScreen() {
     OobeScreenWaiter screen_waiter(
         OobeScreen::SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE);
@@ -316,6 +315,7 @@
   std::string autocomplete_realm_;
 
  private:
+  chromeos::ScopedStubInstallAttributes install_attributes_;
 
   DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryLoginTest);
 };
@@ -338,11 +338,11 @@
 };
 }  // namespace
 
-// Declares a PRE_ test that calls MarkAsActiveDirectoryEnterprise() and the
+// Declares a PRE_ test that calls StartupUtils::MarkOobeCompleted() and the
 // test itself.
 #define IN_PROC_BROWSER_TEST_F_WITH_PRE(class_name, test_name) \
   IN_PROC_BROWSER_TEST_F(class_name, PRE_##test_name) {        \
-    MarkAsActiveDirectoryEnterprise();                         \
+    StartupUtils::MarkOobeCompleted();                         \
   }                                                            \
   IN_PROC_BROWSER_TEST_F(class_name, test_name)
 
diff --git a/chrome/browser/chromeos/login/active_directory_test_helper.cc b/chrome/browser/chromeos/login/active_directory_test_helper.cc
index a859aaf..cbda860 100644
--- a/chrome/browser/chromeos/login/active_directory_test_helper.cc
+++ b/chrome/browser/chromeos/login/active_directory_test_helper.cc
@@ -4,82 +4,40 @@
 
 #include "chrome/browser/chromeos/login/active_directory_test_helper.h"
 
-#include "base/bind.h"
-#include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/strings/string_split.h"
+#include "base/test/bind_test_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/authpolicy/authpolicy_helper.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/constants/chromeos_paths.h"
-#include "chromeos/dbus/auth_policy/active_directory_info.pb.h"
-#include "chromeos/dbus/auth_policy/auth_policy_client.h"
-#include "chromeos/dbus/cryptohome/tpm_util.h"
-#include "chromeos/dbus/upstart/upstart_client.h"
-#include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
 
 namespace active_directory_test_helper {
 
-namespace {
-
-constexpr char kAdMachineName[] = "ad-machine-name";
-constexpr char kDmToken[] = "dm-token";
-
-}  // namespace
-
-void PrepareLogin(const std::string& user_principal_name) {
-  std::vector<std::string> user_and_domain = base::SplitString(
-      user_principal_name, "@", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-  ASSERT_EQ(2u, user_and_domain.size());
-
-  // Start the D-Bus service.
-  chromeos::UpstartClient::Get()->StartAuthPolicyService();
-
-  // Join the AD domain.
-  chromeos::AuthPolicyHelper helper;
-  {
-    base::RunLoop loop;
-    helper.set_dm_token(kDmToken);
-    helper.JoinAdDomain(
-        kAdMachineName, "" /* distinguished_name */,
-        authpolicy::KerberosEncryptionTypes::ENC_TYPES_STRONG,
-        user_principal_name, "" /* password */,
-        base::BindOnce(
-            [](base::OnceClosure closure, const std::string& expected_domain,
-               authpolicy::ErrorType error, const std::string& domain) {
-              EXPECT_EQ(authpolicy::ERROR_NONE, error);
-              EXPECT_EQ(expected_domain, domain);
-              std::move(closure).Run();
-            },
-            loop.QuitClosure(), user_and_domain[1]));
-    loop.Run();
-  }
-
-  // Lock the device to AD mode. Paths need to be set here, so install attribs
-  // can be saved to disk.
-  ASSERT_TRUE(
-      tpm_util::LockDeviceActiveDirectoryForTesting(user_and_domain[1]));
-
-  // Fetch device policy.
-  {
-    base::RunLoop run_loop;
-    AuthPolicyClient::Get()->RefreshDevicePolicy(base::BindOnce(
-        [](base::OnceClosure quit_closure, authpolicy::ErrorType error) {
-          EXPECT_EQ(authpolicy::ERROR_NONE, error);
-          std::move(quit_closure).Run();
-        },
-        run_loop.QuitClosure()));
-    run_loop.Run();
-  }
+InstallAttributes::LockResult LockDevice(const std::string& domain) {
+  base::RunLoop run_loop;
+  InstallAttributes::LockResult return_lock_result;
+  InstallAttributes::Get()->LockDevice(
+      policy::DEVICE_MODE_ENTERPRISE_AD, "", domain, "device_id",
+      base::AdaptCallbackForRepeating(base::BindOnce(
+          [](base::OnceClosure closure,
+             InstallAttributes::LockResult* return_lock_result,
+             InstallAttributes::LockResult lock_result) {
+            *return_lock_result = lock_result;
+            std::move(closure).Run();
+          },
+          run_loop.QuitClosure(), &return_lock_result)));
+  run_loop.Run();
+  return return_lock_result;
 }
 
 void OverridePaths() {
   base::FilePath user_data_dir;
-  ASSERT_TRUE(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
+  CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
 
   base::ScopedAllowBlockingForTesting allow_io;
   RegisterStubPathOverrides(user_data_dir);
diff --git a/chrome/browser/chromeos/login/active_directory_test_helper.h b/chrome/browser/chromeos/login/active_directory_test_helper.h
index fe96562..037d481 100644
--- a/chrome/browser/chromeos/login/active_directory_test_helper.h
+++ b/chrome/browser/chromeos/login/active_directory_test_helper.h
@@ -7,14 +7,14 @@
 
 #include <string>
 
+#include "chromeos/tpm/install_attributes.h"
+
 namespace chromeos {
 
 namespace active_directory_test_helper {
 
-// Starts AuthPolicyService, joins the Active Directory domain using
-// |user_principal_name| for authentication (user@example.com), locks the device
-// to Active Directory mode and fetches device policy.
-void PrepareLogin(const std::string& user_principal_name);
+// Locks the device to Active Directory mode.
+InstallAttributes::LockResult LockDevice(const std::string& domain);
 
 // Sets stub path overrides.
 void OverridePaths();
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
index a2b6f7d7..cd5233f 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
@@ -56,10 +56,6 @@
   service->RecordEasySignInOutcome(account_id(), true);
 }
 
-bool EasyUnlockUserLoginFlow::HandlePasswordChangeDetected() {
-  return false;
-}
-
 void EasyUnlockUserLoginFlow::HandleOAuthTokenStatusChange(
     user_manager::User::OAuthTokenStatus status) {}
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
index 459809e..e620eb0e 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
@@ -30,7 +30,6 @@
   bool ShouldSkipPostLoginScreens() override;
   bool HandleLoginFailure(const AuthFailure& failure) override;
   void HandleLoginSuccess(const UserContext& context) override;
-  bool HandlePasswordChangeDetected() override;
   void HandleOAuthTokenStatusChange(
       user_manager::User::OAuthTokenStatus status) override;
   void LaunchExtraSteps(Profile* profile) override;
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
index bbafb741..035a64f9 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -13,7 +13,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h"
 #include "chrome/browser/chromeos/login/screen_manager.h"
-#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
 #include "chrome/browser/chromeos/login/screens/error_screen.h"
 #include "chrome/browser/chromeos/login/screens/network_error.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -44,12 +43,12 @@
 }
 
 AutoEnrollmentCheckScreen::AutoEnrollmentCheckScreen(
-    BaseScreenDelegate* base_screen_delegate,
     AutoEnrollmentCheckScreenView* view,
+    ErrorScreen* error_screen,
     const base::RepeatingClosure& exit_callback)
     : BaseScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK),
-      base_screen_delegate_(base_screen_delegate),
       view_(view),
+      error_screen_(error_screen),
       exit_callback_(exit_callback),
       auto_enrollment_controller_(nullptr),
       captive_portal_status_(
@@ -152,9 +151,8 @@
     UpdateAutoEnrollmentState(new_auto_enrollment_state);
 
   // Update the connecting indicator.
-  ErrorScreen* error_screen = base_screen_delegate_->GetErrorScreen();
-  error_screen->ShowConnectingIndicator(new_auto_enrollment_state ==
-                                        policy::AUTO_ENROLLMENT_STATE_PENDING);
+  error_screen_->ShowConnectingIndicator(new_auto_enrollment_state ==
+                                         policy::AUTO_ENROLLMENT_STATE_PENDING);
 
   // Determine whether a retry is in order.
   bool retry = (new_captive_portal_status ==
@@ -184,7 +182,7 @@
     case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
       ShowErrorScreen(NetworkError::ERROR_STATE_PORTAL);
       if (captive_portal_status_ != new_captive_portal_status)
-        base_screen_delegate_->GetErrorScreen()->FixCaptivePortal();
+        error_screen_->FixCaptivePortal();
       return true;
     case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
       ShowErrorScreen(NetworkError::ERROR_STATE_PROXY);
@@ -229,20 +227,28 @@
     NetworkError::ErrorState error_state) {
   const NetworkState* network =
       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
-  ErrorScreen* error_screen = base_screen_delegate_->GetErrorScreen();
-  error_screen->SetUIState(NetworkError::UI_STATE_AUTO_ENROLLMENT_ERROR);
-  error_screen->AllowGuestSignin(
+  error_screen_->SetUIState(NetworkError::UI_STATE_AUTO_ENROLLMENT_ERROR);
+  error_screen_->AllowGuestSignin(
       auto_enrollment_controller_->GetFRERequirement() !=
       AutoEnrollmentController::FRERequirement::kExplicitlyRequired);
-  error_screen->SetErrorState(error_state,
-                              network ? network->name() : std::string());
-  connect_request_subscription_ = error_screen->RegisterConnectRequestCallback(
+  error_screen_->SetErrorState(error_state,
+                               network ? network->name() : std::string());
+  connect_request_subscription_ = error_screen_->RegisterConnectRequestCallback(
       base::Bind(&AutoEnrollmentCheckScreen::OnConnectRequested,
                  base::Unretained(this)));
-  base_screen_delegate_->ShowErrorScreen();
+  error_screen_->SetHideCallback(
+      base::BindRepeating(&AutoEnrollmentCheckScreen::OnErrorScreenHidden,
+                          weak_ptr_factory_.GetWeakPtr()));
+  error_screen_->SetParentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  error_screen_->Show();
   histogram_helper_->OnErrorShow(error_state);
 }
 
+void AutoEnrollmentCheckScreen::OnErrorScreenHidden() {
+  error_screen_->SetParentScreen(OobeScreen::SCREEN_UNKNOWN);
+  Show();
+}
+
 void AutoEnrollmentCheckScreen::SignalCompletion() {
   network_portal_detector::GetInstance()->RemoveObserver(this);
   auto_enrollment_progress_subscription_.reset();
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h
index 226eb513..b9c949d 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h
@@ -20,7 +20,6 @@
 
 namespace chromeos {
 
-class BaseScreenDelegate;
 class ErrorScreensHistogramHelper;
 class ScreenManager;
 
@@ -34,8 +33,8 @@
       public BaseScreen,
       public NetworkPortalDetector::Observer {
  public:
-  AutoEnrollmentCheckScreen(BaseScreenDelegate* base_screen_delegate,
-                            AutoEnrollmentCheckScreenView* view,
+  AutoEnrollmentCheckScreen(AutoEnrollmentCheckScreenView* view,
+                            ErrorScreen* error_screen,
                             const base::RepeatingClosure& exit_callback);
   ~AutoEnrollmentCheckScreen() override;
 
@@ -91,6 +90,10 @@
   // Configures the error screen.
   void ShowErrorScreen(NetworkError::ErrorState error_state);
 
+  // Passed as a callback to the error screen when it's shown. Called when the
+  // error screen gets hidden.
+  void OnErrorScreenHidden();
+
   // Asynchronously signals completion. The owner might destroy |this| in
   // response, so no code should be run after the completion of a message loop
   // task, in which this function was called.
@@ -108,8 +111,8 @@
   // necessary".
   bool ShouldBlockOnServerError() const;
 
-  BaseScreenDelegate* base_screen_delegate_;
   AutoEnrollmentCheckScreenView* view_;
+  ErrorScreen* error_screen_;
   base::RepeatingClosure exit_callback_;
   AutoEnrollmentController* auto_enrollment_controller_;
 
diff --git a/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.cc
index a471dff..90657cc 100644
--- a/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.cc
@@ -7,10 +7,10 @@
 namespace chromeos {
 
 MockAutoEnrollmentCheckScreen::MockAutoEnrollmentCheckScreen(
-    BaseScreenDelegate* base_screen_delegate,
     AutoEnrollmentCheckScreenView* view,
+    ErrorScreen* error_screen,
     const base::RepeatingClosure& exit_callback)
-    : AutoEnrollmentCheckScreen(base_screen_delegate, view, exit_callback) {}
+    : AutoEnrollmentCheckScreen(view, error_screen, exit_callback) {}
 
 MockAutoEnrollmentCheckScreen::~MockAutoEnrollmentCheckScreen() {}
 
diff --git a/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.h b/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.h
index f7b532b..e266e80 100644
--- a/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.h
+++ b/chrome/browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.h
@@ -13,8 +13,8 @@
 
 class MockAutoEnrollmentCheckScreen : public AutoEnrollmentCheckScreen {
  public:
-  MockAutoEnrollmentCheckScreen(BaseScreenDelegate* base_screen_delegate,
-                                AutoEnrollmentCheckScreenView* view,
+  MockAutoEnrollmentCheckScreen(AutoEnrollmentCheckScreenView* view,
+                                ErrorScreen* error_screen,
                                 const base::RepeatingClosure& exit_callback);
   ~MockAutoEnrollmentCheckScreen() override;
 
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index 4f4fef1..8276215 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -280,7 +280,8 @@
 
 // Verifies statistic collection accepted flow.
 // Advaces to the next screen and verifies stats collection is enabled.
-IN_PROC_BROWSER_TEST_F(EulaTest, EnableUsageStats) {
+// Flaky on LSAN/ASAN: crbug.com/952482.
+IN_PROC_BROWSER_TEST_F(EulaTest, DISABLED_EnableUsageStats) {
   ShowEulaScreen();
 
   // Verify that toggle is enabled by default.
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 8050b26..2b01df5c 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -1065,12 +1065,6 @@
     return;
   }
 
-  if (ChromeUserManager::Get()
-          ->GetUserFlow(last_login_attempt_account_id_)
-          ->HandlePasswordChangeDetected()) {
-    return;
-  }
-
   if (auth_status_consumer_)
     auth_status_consumer_->OnPasswordChangeDetected();
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index a23083a..1857912 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -41,13 +41,13 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/auth_policy/fake_auth_policy_client.h"
-#include "chromeos/dbus/cryptohome/tpm_util.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/login/auth/key.h"
 #include "chromeos/login/auth/mock_url_fetchers.h"
 #include "chromeos/login/auth/user_context.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/settings/cros_settings_provider.h"
+#include "chromeos/tpm/stub_install_attributes.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
@@ -763,7 +763,11 @@
 class ExistingUserControllerActiveDirectoryTest
     : public ExistingUserControllerTest {
  public:
-  ExistingUserControllerActiveDirectoryTest() = default;
+  ExistingUserControllerActiveDirectoryTest()
+      : install_attributes_(
+            chromeos::StubInstallAttributes::CreateActiveDirectoryManaged(
+                kActiveDirectoryRealm,
+                "device_id")) {}
 
   // Overriden from DevicePolicyCrosBrowserTest:
   void MarkOwnership() override {}
@@ -780,8 +784,6 @@
     // Required for tpm_util. Will be destroyed in browser shutdown.
     chromeos::CryptohomeClient::InitializeFake();
 
-    ASSERT_TRUE(
-        tpm_util::LockDeviceActiveDirectoryForTesting(kActiveDirectoryRealm));
     RefreshDevicePolicy();
     EXPECT_CALL(policy_provider_, IsInitializationComplete(_))
         .WillRepeatedly(Return(true));
@@ -895,6 +897,7 @@
   }
 
  private:
+  chromeos::ScopedStubInstallAttributes install_attributes_;
   policy::MockConfigurationPolicyProvider policy_provider_;
 };
 
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index b6ce972..9481d62f 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/public/cpp/ash_features.h"
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
@@ -175,6 +176,7 @@
   void SetLoginAuthHTMLTemplate(const std::string& template_file);
   void SetRefreshURL(const GURL& refresh_url);
   void SetCookieValue(const std::string& cookie_value);
+  void SetSamlResponseFile(const std::string& xml_file);
 
   std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request);
 
@@ -185,6 +187,7 @@
       const std::string& next_path);
 
   base::FilePath html_template_dir_;
+  base::FilePath saml_response_dir_;
 
   std::string login_path_;
   std::string login_auth_path_;
@@ -194,6 +197,7 @@
   GURL gaia_assertion_url_;
   GURL refresh_url_;
   std::string cookie_value_;
+  std::string saml_response_{"fake_response"};
 
   DISALLOW_COPY_AND_ASSIGN(FakeSamlIdp);
 };
@@ -205,7 +209,9 @@
 void FakeSamlIdp::SetUp(const std::string& base_path, const GURL& gaia_url) {
   base::FilePath test_data_dir;
   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+  // NOTE: Ideally testdata would all be in chromeos/login, to match the test.
   html_template_dir_ = test_data_dir.Append("login");
+  saml_response_dir_ = test_data_dir.Append("chromeos").Append("login");
 
   login_path_ = base_path;
   login_auth_path_ = base_path + "Auth";
@@ -224,6 +230,13 @@
                                      &login_auth_html_template_));
 }
 
+void FakeSamlIdp::SetSamlResponseFile(const std::string& xml_file) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  EXPECT_TRUE(base::ReadFileToString(saml_response_dir_.Append(xml_file),
+                                     &saml_response_));
+  base::Base64Encode(saml_response_, &saml_response_);
+}
+
 void FakeSamlIdp::SetRefreshURL(const GURL& refresh_url) {
   refresh_url_ = refresh_url;
 }
@@ -261,7 +274,7 @@
   }
 
   redirect_url =
-      net::AppendQueryParameter(redirect_url, "SAMLResponse", "fake_response");
+      net::AppendQueryParameter(redirect_url, "SAMLResponse", saml_response_);
   redirect_url =
       net::AppendQueryParameter(redirect_url, kRelayState, relay_state);
 
@@ -783,6 +796,42 @@
             WaitForAndGetFatalErrorMessage());
 }
 
+// Verifies that information about the user's password (specifically, whether
+// is has expired) can be extracted from the SAMLResponse from the IdP.
+IN_PROC_BROWSER_TEST_F(SamlTest, ExtractPasswordAttributes) {
+  // TODO(https://crbug.com/930109): Replace this with an end-to-end test that
+  // tests the actual functionality, once this is implemented.
+
+  fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
+  fake_saml_idp()->SetSamlResponseFile("saml_with_password_attributes.xml");
+  StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
+
+  ASSERT_TRUE(content::ExecuteScript(GetLoginUI()->GetWebContents(),
+      "$('gaia-signin').gaiaAuthHost_.samlHandler_"
+      ".extractSamlPasswordAttributes = true;"));
+
+  base::Value attrs;
+  GetLoginUI()->RegisterMessageCallback("updatePasswordAttributes",
+      base::BindLambdaForTesting(
+          [&](const base::ListValue* val) { attrs = val->Clone(); }));
+
+  SigninFrameJS().TypeIntoPath("fake_user", {"Email"});
+  SigninFrameJS().TypeIntoPath("fake_password", {"Password"});
+
+  content::WindowedNotificationObserver session_start_waiter(
+      chrome::NOTIFICATION_SESSION_STARTED,
+      content::NotificationService::AllSources());
+  SigninFrameJS().TapOn("Submit");
+  session_start_waiter.Wait();
+
+  ASSERT_TRUE(attrs.is_list());
+  ASSERT_EQ(3ul, attrs.GetList().size());
+  EXPECT_EQ("1550836258421", attrs.GetList()[0].GetString());
+  EXPECT_EQ("1551873058421", attrs.GetList()[1].GetString());
+  EXPECT_EQ("https://example.com/adfs/portal/updatepassword/",
+            attrs.GetList()[2].GetString());
+}
+
 class SAMLEnrollmentTest : public SamlTest {
  public:
   SAMLEnrollmentTest();
diff --git a/chrome/browser/chromeos/login/screens/base_screen_delegate.h b/chrome/browser/chromeos/login/screens/base_screen_delegate.h
index c43b5512..fa4235b41 100644
--- a/chrome/browser/chromeos/login/screens/base_screen_delegate.h
+++ b/chrome/browser/chromeos/login/screens/base_screen_delegate.h
@@ -7,9 +7,6 @@
 
 namespace chromeos {
 
-class BaseScreen;
-class ErrorScreen;
-
 // Interface that handles notifications received from any of login wizard
 // screens.
 class BaseScreenDelegate {
@@ -17,10 +14,6 @@
   // Forces current screen showing.
   virtual void ShowCurrentScreen() = 0;
 
-  virtual ErrorScreen* GetErrorScreen() = 0;
-  virtual void ShowErrorScreen() = 0;
-  virtual void HideErrorScreen(BaseScreen* parent_screen) = 0;
-
  protected:
   virtual ~BaseScreenDelegate() {}
 };
diff --git a/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h b/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h
index aa164ae4..000ea786 100644
--- a/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h
+++ b/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h
@@ -21,9 +21,6 @@
   virtual ~MockBaseScreenDelegate();
 
   MOCK_METHOD0(ShowCurrentScreen, void());
-  MOCK_METHOD0(GetErrorScreen, ErrorScreen*());
-  MOCK_METHOD0(ShowErrorScreen, void());
-  MOCK_METHOD1(HideErrorScreen, void(BaseScreen*));
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.cc b/chrome/browser/chromeos/login/screens/mock_update_screen.cc
index dfdbb6f5..b5ac712 100644
--- a/chrome/browser/chromeos/login/screens/mock_update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/mock_update_screen.cc
@@ -12,8 +12,9 @@
 MockUpdateScreen::MockUpdateScreen(
     BaseScreenDelegate* base_screen_delegate,
     UpdateView* view,
+    ErrorScreen* error_screen,
     const UpdateScreen::ScreenExitCallback& exit_callback)
-    : UpdateScreen(base_screen_delegate, view, exit_callback) {}
+    : UpdateScreen(base_screen_delegate, view, error_screen, exit_callback) {}
 
 MockUpdateScreen::~MockUpdateScreen() {}
 
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.h b/chrome/browser/chromeos/login/screens/mock_update_screen.h
index 49ab20d..3dba1807 100644
--- a/chrome/browser/chromeos/login/screens/mock_update_screen.h
+++ b/chrome/browser/chromeos/login/screens/mock_update_screen.h
@@ -16,6 +16,7 @@
  public:
   MockUpdateScreen(BaseScreenDelegate* base_screen_delegate,
                    UpdateView* view,
+                   ErrorScreen* error_screen,
                    const ScreenExitCallback& exit_callback);
   virtual ~MockUpdateScreen();
 
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.cc b/chrome/browser/chromeos/login/screens/reset_screen.cc
index 53a0e92d..97f2c0b 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.cc
+++ b/chrome/browser/chromeos/login/screens/reset_screen.cc
@@ -10,7 +10,6 @@
 #include "base/task/post_task.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
 #include "chrome/browser/chromeos/login/screens/error_screen.h"
 #include "chrome/browser/chromeos/login/screens/network_error.h"
 #include "chrome/browser/chromeos/login/screens/reset_view.h"
@@ -88,12 +87,12 @@
   g_tpm_firmware_update_checker = checker;
 }
 
-ResetScreen::ResetScreen(BaseScreenDelegate* base_screen_delegate,
-                         ResetView* view,
+ResetScreen::ResetScreen(ResetView* view,
+                         ErrorScreen* error_screen,
                          const base::RepeatingClosure& exit_callback)
     : BaseScreen(OobeScreen::SCREEN_OOBE_RESET),
-      base_screen_delegate_(base_screen_delegate),
       view_(view),
+      error_screen_(error_screen),
       exit_callback_(exit_callback),
       tpm_firmware_update_checker_(
           g_tpm_firmware_update_checker
@@ -355,9 +354,8 @@
           UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT) {
     view_->SetScreenState(ResetView::State::kError);
     // Show error screen.
-    base_screen_delegate_->GetErrorScreen()->SetUIState(
-        NetworkError::UI_STATE_ROLLBACK_ERROR);
-    base_screen_delegate_->ShowErrorScreen();
+    error_screen_->SetUIState(NetworkError::UI_STATE_ROLLBACK_ERROR);
+    error_screen_->Show();
   } else if (status.status ==
              UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
     PowerManagerClient::Get()->RequestRestart(
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.h b/chrome/browser/chromeos/login/screens/reset_screen.h
index 7417650..b662b1bb 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.h
+++ b/chrome/browser/chromeos/login/screens/reset_screen.h
@@ -22,7 +22,7 @@
 
 namespace chromeos {
 
-class BaseScreenDelegate;
+class ErrorScreen;
 class ResetView;
 
 // Representation independent class that controls screen showing reset to users.
@@ -30,8 +30,8 @@
 // will end up in the device restart.
 class ResetScreen : public BaseScreen, public UpdateEngineClient::Observer {
  public:
-  ResetScreen(BaseScreenDelegate* base_screen_delegate,
-              ResetView* view,
+  ResetScreen(ResetView* view,
+              ErrorScreen* error_screen,
               const base::RepeatingClosure& exit_callback);
   ~ResetScreen() override;
 
@@ -74,8 +74,8 @@
 
   void ShowHelpArticle(HelpAppLauncher::HelpTopic topic);
 
-  BaseScreenDelegate* const base_screen_delegate_;
   ResetView* view_;
+  ErrorScreen* error_screen_;
   base::RepeatingClosure exit_callback_;
 
   // Help application used for help dialogs.
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index 958469b..5789516 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -94,12 +94,14 @@
 
 UpdateScreen::UpdateScreen(BaseScreenDelegate* base_screen_delegate,
                            UpdateView* view,
+                           ErrorScreen* error_screen,
                            const ScreenExitCallback& exit_callback)
     : BaseScreen(OobeScreen::SCREEN_OOBE_UPDATE),
       tick_clock_(base::DefaultTickClock::GetInstance()),
       reboot_check_delay_(kWaitForRebootTimeSec),
       base_screen_delegate_(base_screen_delegate),
       view_(view),
+      error_screen_(error_screen),
       exit_callback_(exit_callback),
       histogram_helper_(new ErrorScreensHistogramHelper("Update")),
       weak_factory_(this) {
@@ -487,17 +489,14 @@
 }
 
 void UpdateScreen::MakeSureScreenIsShown() {
-  if (!is_shown_)
+  if (!is_shown_) {
     base_screen_delegate_->ShowCurrentScreen();
-}
-
-ErrorScreen* UpdateScreen::GetErrorScreen() {
-  return base_screen_delegate_->GetErrorScreen();
+  }
 }
 
 void UpdateScreen::StartUpdateCheck() {
   error_message_timer_.Stop();
-  GetErrorScreen()->HideCaptivePortal();
+  error_screen_->HideCaptivePortal();
 
   network_portal_detector::GetInstance()->RemoveObserver(this);
   connect_request_subscription_.reset();
@@ -520,18 +519,22 @@
 
   error_message_timer_.Stop();
 
+  is_shown_ = false;
   state_ = State::STATE_ERROR;
   connect_request_subscription_ =
-      GetErrorScreen()->RegisterConnectRequestCallback(base::Bind(
+      error_screen_->RegisterConnectRequestCallback(base::BindRepeating(
           &UpdateScreen::OnConnectRequested, base::Unretained(this)));
-  GetErrorScreen()->SetUIState(NetworkError::UI_STATE_UPDATE);
-  base_screen_delegate_->ShowErrorScreen();
-  histogram_helper_->OnErrorShow(GetErrorScreen()->GetErrorState());
+  error_screen_->SetUIState(NetworkError::UI_STATE_UPDATE);
+  error_screen_->SetParentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  error_screen_->SetHideCallback(base::BindRepeating(
+      &UpdateScreen::OnErrorScreenHidden, weak_factory_.GetWeakPtr()));
+  error_screen_->Show();
+  histogram_helper_->OnErrorShow(error_screen_->GetErrorState());
 }
 
 void UpdateScreen::HideErrorMessage() {
   LOG(WARNING) << "UpdateScreen::HideErrorMessage()";
-  base_screen_delegate_->HideErrorScreen(this);
+  error_screen_->Hide();
   histogram_helper_->OnErrorHide();
 }
 
@@ -544,21 +547,21 @@
       break;
     case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
     case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
-      GetErrorScreen()->SetErrorState(NetworkError::ERROR_STATE_OFFLINE,
-                                      std::string());
+      error_screen_->SetErrorState(NetworkError::ERROR_STATE_OFFLINE,
+                                   std::string());
       break;
     case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
       DCHECK(network);
-      GetErrorScreen()->SetErrorState(NetworkError::ERROR_STATE_PORTAL,
-                                      network->name());
+      error_screen_->SetErrorState(NetworkError::ERROR_STATE_PORTAL,
+                                   network->name());
       if (is_first_portal_notification_) {
         is_first_portal_notification_ = false;
-        GetErrorScreen()->FixCaptivePortal();
+        error_screen_->FixCaptivePortal();
       }
       break;
     case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
-      GetErrorScreen()->SetErrorState(NetworkError::ERROR_STATE_PROXY,
-                                      std::string());
+      error_screen_->SetErrorState(NetworkError::ERROR_STATE_PROXY,
+                                   std::string());
       break;
     default:
       NOTREACHED();
@@ -590,4 +593,9 @@
   }
 }
 
+void UpdateScreen::OnErrorScreenHidden() {
+  error_screen_->SetParentScreen(OobeScreen::SCREEN_UNKNOWN);
+  Show();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/update_screen.h b/chrome/browser/chromeos/login/screens/update_screen.h
index 83b4c86..c5a10a5 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.h
+++ b/chrome/browser/chromeos/login/screens/update_screen.h
@@ -70,6 +70,7 @@
   using ScreenExitCallback = base::RepeatingCallback<void(Result result)>;
   UpdateScreen(BaseScreenDelegate* base_screen_delegate,
                UpdateView* view,
+               ErrorScreen* error_screen,
                const ScreenExitCallback& exit_callback);
   ~UpdateScreen() override;
 
@@ -166,6 +167,10 @@
   // The user requested an attempt to connect to the network should be made.
   void OnConnectRequested();
 
+  // Callback passed to |error_screen_| when it's shown. Called when the error
+  // screen gets hidden.
+  void OnErrorScreenHidden();
+
   // Timer for the interval to wait for the reboot.
   // If reboot didn't happen - ask user to reboot manually.
   base::OneShotTimer reboot_timer_;
@@ -193,7 +198,8 @@
   bool ignore_idle_status_ = true;
 
   BaseScreenDelegate* base_screen_delegate_;
-  UpdateView* view_ = nullptr;
+  UpdateView* view_;
+  ErrorScreen* error_screen_;
   ScreenExitCallback exit_callback_;
 
   // Time of the first notification from the downloading stage.
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index bc5bde2..7b6b050e 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -50,45 +50,21 @@
 
 class TestErrorScreenDelegate : public BaseScreenDelegate {
  public:
-  explicit TestErrorScreenDelegate(ErrorScreen* error_screen)
-      : error_screen_(error_screen) {}
+  TestErrorScreenDelegate() = default;
+  ~TestErrorScreenDelegate() override = default;
 
   void set_parent_screen(UpdateScreen* parent_screen) {
     parent_screen_ = parent_screen;
   }
 
-  bool error_screen_shown() const { return error_screen_shown_; }
-
   // BaseScreenDelegate:
-  void ShowCurrentScreen() override {
-    error_screen_->Hide();
-    parent_screen_->Show();
-    error_screen_shown_ = false;
-  }
-  ErrorScreen* GetErrorScreen() override { return error_screen_; }
-  void ShowErrorScreen() override {
-    parent_screen_->Hide();
-    error_screen_->Show();
-    error_screen_shown_ = true;
-  }
-  void HideErrorScreen(BaseScreen* parent_screen) override {
-    EXPECT_EQ(parent_screen, parent_screen_);
-    error_screen_->Hide();
-    parent_screen_->Show();
-    error_screen_shown_ = false;
-  }
+  void ShowCurrentScreen() override { parent_screen_->Show(); }
 
  private:
-  // Owned by OobeUI.
-  ErrorScreen* const error_screen_;
-
   // The update screen under test, that uses this delegate.
   // Should be set using |set_parent_screen()| after the update screen is
   // created.
   BaseScreen* parent_screen_;
-
-  // Whether the error screen is shown by the delegate.
-  bool error_screen_shown_ = false;
 };
 
 }  // namespace
@@ -112,10 +88,10 @@
 
     tick_clock_.Advance(base::TimeDelta::FromMinutes(1));
 
-    error_delegate_ = std::make_unique<TestErrorScreenDelegate>(
-        GetOobeUI()->GetErrorScreen());
+    error_screen_ = GetOobeUI()->GetErrorScreen();
+    error_delegate_ = std::make_unique<TestErrorScreenDelegate>();
     update_screen_ = std::make_unique<UpdateScreen>(
-        error_delegate_.get(), GetOobeUI()->GetUpdateView(),
+        error_delegate_.get(), GetOobeUI()->GetUpdateView(), error_screen_,
         base::BindRepeating(&UpdateScreenTest::HandleScreenExit,
                             base::Unretained(this)));
     update_screen_->set_tick_clock_for_testing(&tick_clock_);
@@ -149,6 +125,8 @@
 
   std::unique_ptr<TestErrorScreenDelegate> error_delegate_;
   std::unique_ptr<UpdateScreen> update_screen_;
+  // Error screen - owned by OobeUI.
+  ErrorScreen* error_screen_ = nullptr;
 
   FakeUpdateEngineClient* fake_update_engine_client_ = nullptr;  // Unowned.
 
@@ -452,7 +430,7 @@
             last_screen_result_.value());
 }
 
-IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTemproraryPortalNetwork) {
+IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTemporaryPortalNetwork) {
   // Change ethernet state to offline.
   network_portal_detector_.SimulateDefaultNetworkState(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL);
@@ -461,18 +439,16 @@
 
   // If the network is a captive portal network, error message is shown with a
   // delay.
-  EXPECT_FALSE(error_delegate_->error_screen_shown());
   EXPECT_TRUE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
+  EXPECT_EQ(OobeScreen::SCREEN_UNKNOWN, error_screen_->GetParentScreen());
 
   // If network goes back online, the error message timer should be canceled.
   network_portal_detector_.SimulateDefaultNetworkState(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
-
-  EXPECT_FALSE(error_delegate_->error_screen_shown());
   EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
 
   UpdateEngineClient::Status status;
-  status.status = UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE;
+  status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
 
   fake_update_engine_client_->set_default_status(status);
   fake_update_engine_client_->NotifyObserversThatStatusChanged(status);
@@ -506,12 +482,11 @@
 
   // Update screen will delay error message about portal state because
   // ethernet is behind captive portal. Simulate the delay timing out.
-  EXPECT_FALSE(error_delegate_->error_screen_shown());
   EXPECT_TRUE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
   update_screen_->GetErrorMessageTimerForTesting()->FireNow();
-
   EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
-  EXPECT_TRUE(error_delegate_->error_screen_shown());
+
+  ASSERT_EQ(OobeScreen::SCREEN_OOBE_UPDATE, error_screen_->GetParentScreen());
 
   OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
   error_screen_waiter.set_assert_next_screen();
@@ -544,14 +519,13 @@
   // results, so detection is restarted.
   update_screen_->StartNetworkCheck();
 
-  EXPECT_FALSE(error_delegate_->error_screen_shown());
   EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
 
   network_portal_detector_.WaitForPortalDetectionRequest();
   network_portal_detector_.SimulateNoNetwork();
 
-  ASSERT_TRUE(error_delegate_->error_screen_shown());
   EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
+  ASSERT_EQ(OobeScreen::SCREEN_OOBE_UPDATE, error_screen_->GetParentScreen());
 
   // Second portal detection also returns NULL network and undefined
   // results.  In this case, offline message should be displayed.
@@ -578,6 +552,7 @@
   // Force timer expiration.
   EXPECT_TRUE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
   update_screen_->GetErrorMessageTimerForTesting()->FireNow();
+  ASSERT_EQ(OobeScreen::SCREEN_OOBE_UPDATE, error_screen_->GetParentScreen());
 
   OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
   error_screen_waiter.set_assert_next_screen();
@@ -587,6 +562,8 @@
       "fake_path", base::DoNothing(), base::DoNothing(),
       false /* check_error_state */, ConnectCallbackMode::ON_COMPLETED);
 
+  ASSERT_EQ(OobeScreen::SCREEN_UNKNOWN, error_screen_->GetParentScreen());
+
   OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
diff --git a/chrome/browser/chromeos/login/screens/update_screen_unittest.cc b/chrome/browser/chromeos/login/screens/update_screen_unittest.cc
index 1848599..d77507ed 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_unittest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_unittest.cc
@@ -82,12 +82,9 @@
     EXPECT_CALL(*mock_network_portal_detector_, IsEnabled())
         .Times(AnyNumber())
         .WillRepeatedly(Return(false));
-    EXPECT_CALL(mock_base_screen_delegate_, GetErrorScreen())
-        .Times(AnyNumber())
-        .WillRepeatedly(Return(mock_error_screen_.get()));
 
     update_screen_ = std::make_unique<UpdateScreen>(
-        &mock_base_screen_delegate_, &mock_view_,
+        &mock_base_screen_delegate_, &mock_view_, mock_error_screen_.get(),
         base::BindRepeating(&UpdateScreenUnitTest::HandleScreenExit,
                             base::Unretained(this)));
   }
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
index 7568eb413..e213f0c 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
@@ -66,10 +66,6 @@
   return false;
 }
 
-bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() {
-  return false;
-}
-
 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded(const std::string& token) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ConfigureSync(token);
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
index 4f25bd0..c5b0072 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
@@ -32,7 +32,6 @@
   bool SupportsEarlyRestartToApplyFlags() override;
   bool HandleLoginFailure(const AuthFailure& failure) override;
   void HandleLoginSuccess(const UserContext& context) override;
-  bool HandlePasswordChangeDetected() override;
   void LaunchExtraSteps(Profile* profile) override;
 
   // ExtendedAuthenticator::NewAuthStatusConsumer overrides.
diff --git a/chrome/browser/chromeos/login/user_flow.cc b/chrome/browser/chromeos/login/user_flow.cc
index e32059d..ed4b46d 100644
--- a/chrome/browser/chromeos/login/user_flow.cc
+++ b/chrome/browser/chromeos/login/user_flow.cc
@@ -64,10 +64,6 @@
 
 void DefaultUserFlow::HandleLoginSuccess(const UserContext& context) {}
 
-bool DefaultUserFlow::HandlePasswordChangeDetected() {
-  return false;
-}
-
 void DefaultUserFlow::HandleOAuthTokenStatusChange(
     user_manager::User::OAuthTokenStatus status) {}
 
diff --git a/chrome/browser/chromeos/login/user_flow.h b/chrome/browser/chromeos/login/user_flow.h
index 63e60f0..e64b838 100644
--- a/chrome/browser/chromeos/login/user_flow.h
+++ b/chrome/browser/chromeos/login/user_flow.h
@@ -42,7 +42,6 @@
   virtual bool AllowsNotificationBalloons() = 0;
   virtual bool HandleLoginFailure(const AuthFailure& failure) = 0;
   virtual void HandleLoginSuccess(const UserContext& context) = 0;
-  virtual bool HandlePasswordChangeDetected() = 0;
   virtual void HandleOAuthTokenStatusChange(
       user_manager::User::OAuthTokenStatus status) = 0;
   virtual void LaunchExtraSteps(Profile* profile) = 0;
@@ -71,7 +70,6 @@
   bool AllowsNotificationBalloons() override;
   bool HandleLoginFailure(const AuthFailure& failure) override;
   void HandleLoginSuccess(const UserContext& context) override;
-  bool HandlePasswordChangeDetected() override;
   void HandleOAuthTokenStatusChange(
       user_manager::User::OAuthTokenStatus status) override;
   void LaunchExtraSteps(Profile* profile) override;
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index b2e2722..568bbe44 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -402,7 +402,7 @@
       base::BindRepeating(&WizardController::OnNetworkScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<UpdateScreen>(
-      this, oobe_ui->GetUpdateView(),
+      this, oobe_ui->GetUpdateView(), oobe_ui->GetErrorScreen(),
       base::BindRepeating(&WizardController::OnUpdateScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<EulaScreen>(
@@ -414,7 +414,7 @@
       base::BindRepeating(&WizardController::OnEnrollmentScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<chromeos::ResetScreen>(
-      this, oobe_ui->GetResetView(),
+      oobe_ui->GetResetView(), oobe_ui->GetErrorScreen(),
       base::BindRepeating(&WizardController::OnResetScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<chromeos::DemoSetupScreen>(
@@ -466,7 +466,7 @@
       base::BindRepeating(&WizardController::OnHidDetectionScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<AutoEnrollmentCheckScreen>(
-      this, oobe_ui->GetAutoEnrollmentCheckScreenView(),
+      oobe_ui->GetAutoEnrollmentCheckScreenView(), oobe_ui->GetErrorScreen(),
       base::BindRepeating(&WizardController::OnAutoEnrollmentCheckScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<DeviceDisabledScreen>(
@@ -681,9 +681,7 @@
 }
 
 void WizardController::OnScreenExit(OobeScreen screen, int exit_code) {
-  DCHECK(current_screen_->screen_id() == screen ||
-         (current_screen_->screen_id() == OobeScreen::SCREEN_ERROR_MESSAGE &&
-          previous_screen_->screen_id() == screen));
+  DCHECK(current_screen_->screen_id() == screen);
 
   VLOG(1) << "Wizard screen " << GetOobeScreenName(screen)
           << " exited with code: " << exit_code;
@@ -1469,12 +1467,6 @@
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ERROR_MESSAGE));
 }
 
-void WizardController::HideErrorScreen(BaseScreen* parent_screen) {
-  DCHECK(parent_screen);
-  VLOG(1) << "Hiding error screen.";
-  SetCurrentScreen(parent_screen);
-}
-
 void WizardController::OnAccessibilityStatusChanged(
     const AccessibilityStatusEventDetails& details) {
   enum AccessibilityNotificationType type = details.notification_type;
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 267f119..e8661ec3 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -250,9 +250,8 @@
 
   // Overridden from BaseScreenDelegate:
   void ShowCurrentScreen() override;
-  ErrorScreen* GetErrorScreen() override;
-  void ShowErrorScreen() override;
-  void HideErrorScreen(BaseScreen* parent_screen) override;
+  ErrorScreen* GetErrorScreen();
+  void ShowErrorScreen();
 
   void OnHIDScreenNecessityCheck(bool screen_needed);
 
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 1621c93..826816c 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -362,11 +362,7 @@
     command_line->AppendSwitch(switches::kLoginManager);
   }
 
-  ErrorScreen* GetErrorScreen() {
-    return static_cast<BaseScreenDelegate*>(
-               WizardController::default_controller())
-        ->GetErrorScreen();
-  }
+  ErrorScreen* GetErrorScreen() { return GetOobeUI()->GetErrorScreen(); }
 
   OobeUI* GetOobeUI() { return LoginDisplayHost::default_host()->GetOobeUI(); }
 
@@ -619,7 +615,7 @@
     mock_update_view_ = std::make_unique<MockUpdateView>();
     mock_update_screen_ =
         MockScreenExpectLifecycle(std::make_unique<MockUpdateScreen>(
-            wizard_controller, mock_update_view_.get(),
+            wizard_controller, mock_update_view_.get(), GetErrorScreen(),
             base::BindRepeating(&WizardController::OnUpdateScreenExit,
                                 base::Unretained(wizard_controller))));
 
@@ -642,7 +638,7 @@
     ExpectSetDelegate(mock_auto_enrollment_check_screen_view_.get());
     mock_auto_enrollment_check_screen_ = MockScreenExpectLifecycle(
         std::make_unique<MockAutoEnrollmentCheckScreen>(
-            wizard_controller, mock_auto_enrollment_check_screen_view_.get(),
+            mock_auto_enrollment_check_screen_view_.get(), GetErrorScreen(),
             base::BindRepeating(
                 &WizardController::OnAutoEnrollmentCheckScreenExit,
                 base::Unretained(wizard_controller))));
@@ -1276,8 +1272,9 @@
 
   // The error screen shows up if device state could not be retrieved.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  EXPECT_EQ(GetErrorScreen(),
-            WizardController::default_controller()->current_screen());
+  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
+            GetErrorScreen()->GetParentScreen());
   base::DictionaryValue device_state;
   device_state.SetString(policy::kDeviceStateMode,
                          policy::kDeviceStateRestoreModeDisabled);
@@ -1375,8 +1372,9 @@
 
   // The error screen shows up if there's no auto-enrollment decision.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  EXPECT_EQ(GetErrorScreen(),
-            WizardController::default_controller()->current_screen());
+  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
+            GetErrorScreen()->GetParentScreen());
 
   WaitUntilJSIsReady();
   constexpr char guest_session_link_display[] =
@@ -1483,8 +1481,9 @@
 
     // The error screen shows up.
     EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-    EXPECT_EQ(GetErrorScreen(),
-              WizardController::default_controller()->current_screen());
+    CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+    EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
+              GetErrorScreen()->GetParentScreen());
 
     WaitUntilJSIsReady();
     constexpr char guest_session_link_display[] =
@@ -1619,8 +1618,8 @@
 
   // The error screen shows up if there's no auto-enrollment decision.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  EXPECT_EQ(GetErrorScreen(),
-            WizardController::default_controller()->current_screen());
+  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
+            GetErrorScreen()->GetParentScreen());
   base::DictionaryValue device_state;
   device_state.SetString(policy::kDeviceStateMode,
                          policy::kDeviceStateRestoreModeReEnrollmentEnforced);
@@ -1703,8 +1702,8 @@
 
   // The error screen shows up if there's no auto-enrollment decision.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  EXPECT_EQ(GetErrorScreen(),
-            WizardController::default_controller()->current_screen());
+  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
+            GetErrorScreen()->GetParentScreen());
 
   WaitUntilJSIsReady();
   constexpr char guest_session_link_display[] =
diff --git a/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc b/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc
index 6cac1a9..ef28802 100644
--- a/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc
@@ -15,8 +15,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
-#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
-#include "chromeos/dbus/cryptohome/tpm_util.h"
 #include "chromeos/dbus/login_manager/policy_descriptor.pb.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/tpm/stub_install_attributes.h"
@@ -80,16 +78,6 @@
     builder_.policy_data().set_settings_entity_id(kTestExtensionId);
   }
 
-  void SetUp() override {
-    // CryptohomeClient needs to be initialized before
-    // tpm_util::LockDeviceActiveDirectoryForTesting.
-    chromeos::CryptohomeClient::InitializeFake();
-
-    ASSERT_TRUE(
-        chromeos::tpm_util::LockDeviceActiveDirectoryForTesting(kTestDomain));
-    ExtensionBrowserTest::SetUp();
-  }
-
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ExtensionBrowserTest::SetUpCommandLine(command_line);
 
diff --git a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
index 544f849..5e4eccf 100644
--- a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
@@ -27,6 +27,7 @@
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
+#include "chromeos/tpm/install_attributes.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 #include "components/user_manager/user.h"
@@ -49,6 +50,7 @@
 namespace {
 
 constexpr char kAffiliatedUser[] = "affiliated-user@example.com";
+constexpr char kAffiliatedDomain[] = "example.com";
 constexpr char kAffiliatedUserGaiaId[] = "1234567890";
 constexpr char kAffiliatedUserObjGuid[] =
     "{11111111-1111-1111-1111-111111111111}";
@@ -285,8 +287,9 @@
 IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, PRE_PRE_TestAffiliation) {
   AffiliationTestHelper::PreLoginUser(account_id_);
   if (GetParam().active_directory) {
-    chromeos::active_directory_test_helper::PrepareLogin(
-        account_id_.GetUserEmail());
+    ASSERT_EQ(
+        chromeos::InstallAttributes::LOCK_SUCCESS,
+        chromeos::active_directory_test_helper::LockDevice(kAffiliatedDomain));
   }
 }
 
diff --git a/chrome/browser/chromeos/settings/cros_settings.cc b/chrome/browser/chromeos/settings/cros_settings.cc
index 4b79e2c..56676a03 100644
--- a/chrome/browser/chromeos/settings/cros_settings.cc
+++ b/chrome/browser/chromeos/settings/cros_settings.cc
@@ -111,14 +111,6 @@
                           base::CompareCase::SENSITIVE);
 }
 
-void CrosSettings::Set(const std::string& path, const base::Value& in_value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CrosSettingsProvider* provider;
-  provider = GetProvider(path);
-  if (provider)
-    provider->Set(path, in_value);
-}
-
 const base::Value* CrosSettings::GetPref(const std::string& path) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CrosSettingsProvider* provider = GetProvider(path);
@@ -140,52 +132,6 @@
   return CrosSettingsProvider::TRUSTED;
 }
 
-void CrosSettings::SetBoolean(const std::string& path, bool in_value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::Value value(in_value);
-  Set(path, value);
-}
-
-void CrosSettings::SetInteger(const std::string& path, int in_value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::Value value(in_value);
-  Set(path, value);
-}
-
-void CrosSettings::SetDouble(const std::string& path, double in_value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::Value value(in_value);
-  Set(path, value);
-}
-
-void CrosSettings::SetString(const std::string& path,
-                             const std::string& in_value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::Value value(in_value);
-  Set(path, value);
-}
-
-void CrosSettings::AppendToList(const std::string& path,
-                                const base::Value* value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  const base::Value* old_value = GetPref(path);
-  std::unique_ptr<base::Value> new_value(old_value ? old_value->DeepCopy()
-                                                   : new base::ListValue());
-  static_cast<base::ListValue*>(new_value.get())
-      ->Append(value->CreateDeepCopy());
-  Set(path, *new_value);
-}
-
-void CrosSettings::RemoveFromList(const std::string& path,
-                                  const base::Value* value) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  const base::Value* old_value = GetPref(path);
-  std::unique_ptr<base::Value> new_value(old_value ? old_value->DeepCopy()
-                                                   : new base::ListValue());
-  static_cast<base::ListValue*>(new_value.get())->Remove(*value, nullptr);
-  Set(path, *new_value);
-}
-
 bool CrosSettings::GetBoolean(const std::string& path,
                               bool* bool_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chrome/browser/chromeos/settings/cros_settings.h b/chrome/browser/chromeos/settings/cros_settings.h
index 16934ad..9ee2a226 100644
--- a/chrome/browser/chromeos/settings/cros_settings.h
+++ b/chrome/browser/chromeos/settings/cros_settings.h
@@ -63,14 +63,6 @@
   // Helper function to test if the given |path| is a valid cros setting.
   static bool IsCrosSettings(const std::string& path);
 
-  // TODO(https://crbug.com/433840): There are no longer any callers of
-  // CrosSettings::Set. Still TODO: delete CrosSettings::Set, convenience forms
-  // of Set, all implementations of CrosSettingsProvider::Set, and remove any
-  // dependencies that are no longer needed.
-
-  // Sets |in_value| to given |path| in cros settings.
-  void Set(const std::string& path, const base::Value& in_value);
-
   // Returns setting value for the given |path|.
   const base::Value* GetPref(const std::string& path) const;
 
@@ -90,21 +82,6 @@
   virtual CrosSettingsProvider::TrustedStatus PrepareTrustedValues(
       const base::Closure& callback) const;
 
-  // Convenience forms of Set().  These methods will replace any existing
-  // value at that |path|, even if it has a different type.
-  void SetBoolean(const std::string& path, bool in_value);
-  void SetInteger(const std::string& path, int in_value);
-  void SetDouble(const std::string& path, double in_value);
-  void SetString(const std::string& path, const std::string& in_value);
-
-  // Convenience functions for manipulating lists. Note that the following
-  // functions employs a read, modify and write pattern. If underlying settings
-  // provider updates its value asynchronously such as DeviceSettingsProvider,
-  // value cache they read from might not be fresh and multiple calls to those
-  // function would lose data. See http://crbug.com/127215
-  void AppendToList(const std::string& path, const base::Value* value);
-  void RemoveFromList(const std::string& path, const base::Value* value);
-
   // These are convenience forms of Get().  The value will be retrieved
   // and the return value will be true if the |path| is valid and the value at
   // the end of the path can be returned in the form specified.
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.h b/chrome/browser/chromeos/settings/device_settings_provider.h
index 7993a86..e5f613d 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.h
+++ b/chrome/browser/chromeos/settings/device_settings_provider.h
@@ -65,8 +65,11 @@
       PrefValueMap* new_values_cache);
 
  private:
-  // CrosSettingsProvider implementation:
-  void DoSet(const std::string& path, const base::Value& value) override;
+  // TODO(https://crbug.com/433840): There are no longer any actual callers of
+  // DeviceSettingsProvider::DoSet, but it is still called in the unit test.
+  // Still TODO: remove the calls from the test, and remove the extra state
+  // that this class will no longer need (ie, cached written values).
+  void DoSet(const std::string& path, const base::Value& value);
 
   // DeviceSettingsService::Observer implementation:
   void OwnershipStatusChanged() override;
@@ -140,6 +143,11 @@
   FRIEND_TEST_ALL_PREFIXES(DeviceSettingsProviderTest,
                            PolicyFailedPermanentlyNotification);
   FRIEND_TEST_ALL_PREFIXES(DeviceSettingsProviderTest, PolicyLoadNotification);
+  // TODO(https://crbug.com/433840) Remove these once DoSet is removed.
+  FRIEND_TEST_ALL_PREFIXES(DeviceSettingsProviderTest, SetPrefFailed);
+  FRIEND_TEST_ALL_PREFIXES(DeviceSettingsProviderTest, SetPrefSucceed);
+  FRIEND_TEST_ALL_PREFIXES(DeviceSettingsProviderTest, SetPrefTwice);
+
   DISALLOW_COPY_AND_ASSIGN(DeviceSettingsProvider);
 };
 
diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
index 9629773..c3c22ad1 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
@@ -353,7 +353,7 @@
   EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber());
   EXPECT_CALL(*this, SettingChanged(kReleaseChannel)).Times(1);
   base::Value new_value("stable-channel");
-  provider_->Set(kReleaseChannel, new_value);
+  provider_->DoSet(kReleaseChannel, new_value);
   Mock::VerifyAndClearExpectations(this);
 
   // This shouldn't trigger a write.
@@ -396,7 +396,7 @@
   // If we are not the owner no sets should work.
   base::Value value(true);
   EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1);
-  provider_->Set(kStatsReportingPref, value);
+  provider_->DoSet(kStatsReportingPref, value);
   Mock::VerifyAndClearExpectations(this);
 
   // This shouldn't trigger a write.
@@ -421,7 +421,7 @@
   base::Value value(true);
   EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber());
   EXPECT_CALL(*this, SettingChanged(kStatsReportingPref)).Times(1);
-  provider_->Set(kStatsReportingPref, value);
+  provider_->DoSet(kStatsReportingPref, value);
   Mock::VerifyAndClearExpectations(this);
 
   // Process the store.
@@ -451,9 +451,9 @@
   EXPECT_CALL(*this, SettingChanged(_)).Times(AnyNumber());
 
   base::Value value1("beta");
-  provider_->Set(kReleaseChannel, value1);
+  provider_->DoSet(kReleaseChannel, value1);
   base::Value value2("dev");
-  provider_->Set(kReleaseChannel, value2);
+  provider_->DoSet(kReleaseChannel, value2);
 
   // Let the changes propagate through the system.
   session_manager_client_.set_device_policy(std::string());
diff --git a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
index e70cb9f..a8c06d9 100644
--- a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
@@ -60,6 +60,18 @@
   current_user_is_owner_ = owner;
 }
 
+void StubCrosSettingsProvider::Set(const std::string& path,
+                                   const base::Value& value) {
+  bool is_value_changed = false;
+  if (current_user_is_owner_)
+    is_value_changed = values_.SetValue(path, value.Clone());
+  else
+    LOG(WARNING) << "Blocked changing setting from non-owner, setting=" << path;
+
+  if (is_value_changed || !current_user_is_owner_)
+    NotifyObservers(path);
+}
+
 void StubCrosSettingsProvider::SetBoolean(const std::string& path,
                                           bool in_value) {
   Set(path, base::Value(in_value));
@@ -80,18 +92,6 @@
   Set(path, base::Value(in_value));
 }
 
-void StubCrosSettingsProvider::DoSet(const std::string& path,
-                                     const base::Value& value) {
-  bool is_value_changed = false;
-  if (current_user_is_owner_)
-    is_value_changed = values_.SetValue(path, value.Clone());
-  else
-    LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
-
-  if (is_value_changed || !current_user_is_owner_)
-    NotifyObservers(path);
-}
-
 void StubCrosSettingsProvider::SetDefaults() {
   values_.SetBoolean(kAccountsPrefAllowGuest, true);
   values_.SetBoolean(kAccountsPrefAllowNewUser, true);
diff --git a/chrome/browser/chromeos/settings/stub_cros_settings_provider.h b/chrome/browser/chromeos/settings/stub_cros_settings_provider.h
index fe41754..2296161 100644
--- a/chrome/browser/chromeos/settings/stub_cros_settings_provider.h
+++ b/chrome/browser/chromeos/settings/stub_cros_settings_provider.h
@@ -32,6 +32,9 @@
 
   bool current_user_is_owner() const { return current_user_is_owner_; }
 
+  // Sets in-memory setting at |path| to value |in_value|.
+  void Set(const std::string& path, const base::Value& in_value);
+
   // Convenience forms of Set(). These methods will replace any existing value
   // at that |path|, even if it has a different type.
   void SetBoolean(const std::string& path, bool in_value);
@@ -40,9 +43,6 @@
   void SetString(const std::string& path, const std::string& in_value);
 
  private:
-  // CrosSettingsProvider implementation:
-  void DoSet(const std::string& path, const base::Value& value) override;
-
   // Initializes settings to their defaults.
   void SetDefaults();
 
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
index 35ad325..280e207 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -20,8 +20,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
@@ -583,48 +581,6 @@
   net::EmbeddedTestServer secondary_server_;
 };
 
-class TestDataReductionProxyPingbackClient
-    : public DataReductionProxyPingbackClient {
- public:
-  bool received_valid_pingback() { return received_valid_pingback_; }
-
- private:
-  void SendPingback(const DataReductionProxyData& data,
-                    const DataReductionProxyPageLoadTiming& timing) override {
-    ASSERT_TRUE(data.used_data_reduction_proxy());
-    ASSERT_EQ(kSessionKey, data.session_key());
-    ASSERT_GT(data.page_id(), 0U);
-    received_valid_pingback_ = true;
-  }
-
-  void SetPingbackReportingFraction(
-      float pingback_reporting_fraction) override {}
-
-  bool received_valid_pingback_ = false;
-};
-
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, PingbackSent) {
-  net::EmbeddedTestServer primary_server;
-  SetConfig(CreateConfigForServer(primary_server));
-
-  // Pingback client is owned by the DRP service.
-  TestDataReductionProxyPingbackClient* pingback_client =
-      new TestDataReductionProxyPingbackClient();
-  DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-      browser()->profile())
-      ->data_reduction_proxy_service()
-      ->SetPingbackClientForTesting(pingback_client);
-
-  // Proxy will be used, so it shouldn't matter if the host cannot be resolved.
-  ui_test_utils::NavigateToURL(browser(), GURL("http://does.not.resolve/echo"));
-  // EXPECT_THAT(GetBody(), kPrimaryResponse);
-
-  // Navigate away for the metrics to be recorded.
-  ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
-
-  ASSERT_TRUE(pingback_client->received_valid_pingback());
-}
-
 IN_PROC_BROWSER_TEST_F(DataReductionProxyFallbackBrowsertest,
                        FallbackProxyUsedOnNetError) {
   SetResponseHook(
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
index 7dfa4168..cdf5f433 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h"
@@ -35,7 +34,6 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
@@ -282,6 +280,9 @@
     return nullptr;
 
   // TODO(721403): Need to fill in:
+  //  - client_lofi_requestd_
+  //  - session_key_
+  //  - page_id_
   //  - request_info_
   auto data = std::make_unique<data_reduction_proxy::DataReductionProxyData>();
   data->set_request_url(handle->GetURL());
@@ -321,23 +322,6 @@
     case data_reduction_proxy::TRANSFORM_UNKNOWN:
       break;
   }
-
-  const ChromeNavigationUIData* chrome_navigation_ui_data =
-      static_cast<const ChromeNavigationUIData*>(handle->GetNavigationUIData());
-  if (data_reduction_proxy::params::IsEnabledWithNetworkService() &&
-      base::FeatureList::IsEnabled(
-          data_reduction_proxy::features::
-              kDataReductionProxyPopulatePreviewsPageIDToPingback)) {
-    if (chrome_navigation_ui_data) {
-      data->set_page_id(
-          chrome_navigation_ui_data->data_reduction_proxy_page_id());
-    }
-    const auto session_key =
-        data_reduction_proxy::DataReductionProxyRequestOptions::
-            GetSessionKeyFromRequestHeaders(GetProxyRequestHeaders());
-    if (session_key)
-      data->set_session_key(session_key.value());
-  }
   return data;
 }
 
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index 7d493945..f8fc80c5 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -233,17 +233,17 @@
     // sessions (anything older than 14 days), so we cannot use
     // MockModelTypeWorker's convenience functions, which internally use very
     // old timestamps.
-    syncer::EntityData header_entity_data;
-    header_entity_data.client_tag_hash =
+    auto header_entity_data = std::make_unique<syncer::EntityData>();
+    header_entity_data->client_tag_hash =
         TagHashFromSpecifics(header_entity.session());
-    header_entity_data.id = "FakeId:" + header_entity_data.client_tag_hash;
-    header_entity_data.specifics = header_entity;
-    header_entity_data.creation_time =
+    header_entity_data->id = "FakeId:" + header_entity_data->client_tag_hash;
+    header_entity_data->specifics = header_entity;
+    header_entity_data->creation_time =
         time_now - base::TimeDelta::FromSeconds(index);
-    header_entity_data.modification_time = header_entity_data.creation_time;
+    header_entity_data->modification_time = header_entity_data->creation_time;
 
     auto header_update = std::make_unique<syncer::UpdateResponseData>();
-    header_update->entity = header_entity_data.PassToPtr();
+    header_update->entity = std::move(header_entity_data);
     header_update->response_version = 1;
     syncer::UpdateResponseDataList updates;
     updates.push_back(std::move(header_update));
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index aec443c..895fdee 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -177,8 +177,7 @@
       content::ResourceInterceptPolicy::kAllowNone, false /* is_async */,
       content::PREVIEWS_OFF,
       ChromeNavigationUIData::CreateForMainFrameNavigation(
-          nullptr /* web_contents */, WindowOpenDisposition::CURRENT_TAB,
-          0 /* data_reduction_proxy_page_id */));
+          nullptr /* web_contents */, WindowOpenDisposition::CURRENT_TAB));
   return request;
 }
 
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index fab33800..5abac6dd 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -73,19 +73,18 @@
 
 void RunExternalProtocolDialogWithDelegate(
     const GURL& url,
-    int render_process_host_id,
-    int routing_id,
+    content::WebContents* web_contents,
     ui::PageTransition page_transition,
     bool has_user_gesture,
     ExternalProtocolHandler::Delegate* delegate) {
+  DCHECK(web_contents);
   if (delegate) {
-    delegate->RunExternalProtocolDialog(url, render_process_host_id, routing_id,
-                                        page_transition, has_user_gesture);
+    delegate->RunExternalProtocolDialog(url, web_contents, page_transition,
+                                        has_user_gesture);
     return;
   }
   ExternalProtocolHandler::RunExternalProtocolDialog(
-      url, render_process_host_id, routing_id, page_transition,
-      has_user_gesture);
+      url, web_contents, page_transition, has_user_gesture);
 }
 
 void LaunchUrlWithoutSecurityCheckWithDelegate(
@@ -129,20 +128,24 @@
     return;
   }
 
+  content::WebContents* web_contents = tab_util::GetWebContentsByID(
+      render_process_host_id, render_view_routing_id);
+
   // If we get here, either we are not the default or we cannot work out
   // what the default is, so we proceed.
   if (prompt_user) {
+    // Never prompt the user without a web_contents.
+    if (!web_contents)
+      return;
+
     // Ask the user if they want to allow the protocol. This will call
     // LaunchUrlWithoutSecurityCheck if the user decides to accept the
     // protocol.
     RunExternalProtocolDialogWithDelegate(
-        escaped_url, render_process_host_id, render_view_routing_id,
-        page_transition, has_user_gesture, delegate);
+        escaped_url, web_contents, page_transition, has_user_gesture, delegate);
     return;
   }
 
-  content::WebContents* web_contents = tab_util::GetWebContentsByID(
-      render_process_host_id, render_view_routing_id);
   LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url, web_contents,
                                             delegate);
 }
diff --git a/chrome/browser/external_protocol/external_protocol_handler.h b/chrome/browser/external_protocol/external_protocol_handler.h
index 727dba7..f195d30 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.h
+++ b/chrome/browser/external_protocol/external_protocol_handler.h
@@ -12,6 +12,10 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/base/page_transition_types.h"
 
+namespace content {
+class WebContents;
+}
+
 class GURL;
 class PrefRegistrySimple;
 class Profile;
@@ -45,12 +49,10 @@
     virtual BlockState GetBlockState(const std::string& scheme,
                                      Profile* profile) = 0;
     virtual void BlockRequest() = 0;
-    virtual void RunExternalProtocolDialog(
-        const GURL& url,
-        int render_process_host_id,
-        int routing_id,
-        ui::PageTransition page_transition,
-        bool has_user_gesture) = 0;
+    virtual void RunExternalProtocolDialog(const GURL& url,
+                                           content::WebContents* web_contents,
+                                           ui::PageTransition page_transition,
+                                           bool has_user_gesture) = 0;
     virtual void LaunchUrlWithoutSecurityCheck(
         const GURL& url,
         content::WebContents* web_contents) = 0;
@@ -124,8 +126,7 @@
   // TODO(davidsac): Consider refactoring this to take a WebContents directly.
   // crbug.com/668289
   static void RunExternalProtocolDialog(const GURL& url,
-                                        int render_process_host_id,
-                                        int routing_id,
+                                        content::WebContents* web_contents,
                                         ui::PageTransition page_transition,
                                         bool has_user_gesture);
 
diff --git a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
index 2d7cc11..631fa71 100644
--- a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
@@ -11,8 +11,12 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/testing_pref_service.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
+#include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class FakeExternalProtocolHandlerWorker
@@ -71,8 +75,7 @@
   }
 
   void RunExternalProtocolDialog(const GURL& url,
-                                 int render_process_host_id,
-                                 int routing_id,
+                                 content::WebContents* web_contents,
                                  ui::PageTransition page_transition,
                                  bool has_user_gesture) override {
     EXPECT_EQ(block_state_, ExternalProtocolHandler::UNKNOWN);
@@ -126,7 +129,10 @@
   ExternalProtocolHandlerTest() : delegate_(run_loop_.QuitClosure()) {}
 
   void SetUp() override {
-    profile_.reset(new TestingProfile());
+    profile_ = std::make_unique<TestingProfile>();
+    rvh_test_enabler_ = std::make_unique<content::RenderViewHostTestEnabler>();
+    web_contents_ = content::WebContentsTester::CreateTestWebContents(
+        profile_.get(), nullptr);
   }
 
   void TearDown() override {
@@ -154,8 +160,10 @@
     ExternalProtocolHandler::SetDelegateForTesting(&delegate_);
     delegate_.set_block_state(block_state);
     delegate_.set_os_state(os_state);
-    ExternalProtocolHandler::LaunchUrl(url, 0, 0, ui::PAGE_TRANSITION_LINK,
-                                       true);
+    int process_id = web_contents_->GetRenderViewHost()->GetProcess()->GetID();
+    int routing_id = web_contents_->GetRenderViewHost()->GetRoutingID();
+    ExternalProtocolHandler::LaunchUrl(url, process_id, routing_id,
+                                       ui::PAGE_TRANSITION_LINK, true);
     run_loop_.Run();
     ExternalProtocolHandler::SetDelegateForTesting(nullptr);
 
@@ -170,6 +178,8 @@
   FakeExternalProtocolHandlerDelegate delegate_;
 
   std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_;
+  std::unique_ptr<content::WebContents> web_contents_;
 };
 
 TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeDefault) {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 577e0bfc..6ab8b45 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -352,11 +352,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "clipboard-content-setting",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "composited-layer-borders",
     "owners": [ "ccameron" ],
     "expiry_milestone": 76
@@ -475,7 +470,7 @@
   },
   {
     "name": "delegate-overscroll-swipes",
-    // "owners": [ "your-team" ],
+    "owners": [ "chrome-android-app@chromium.org" ],
     "expiry_milestone": 88
   },
   {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 7bcbc99..d21623d 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -240,11 +240,6 @@
     "When the PDF plugin is unavailable, show a click-to-open placeholder for "
     "embedded PDFs.";
 
-const char kClipboardContentSettingName[] = "Clipboard content setting";
-const char kClipboardContentSettingDescription[] =
-    "Enables a site-wide permission in the UI which controls access to the "
-    "asynchronous clipboard web API";
-
 const char kCloudImportName[] = "Cloud Import";
 const char kCloudImportDescription[] = "Allows the cloud-import feature.";
 
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 006d4e7..ef3b0dc8 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -160,9 +160,6 @@
 extern const char kClickToOpenPDFName[];
 extern const char kClickToOpenPDFDescription[];
 
-extern const char kClipboardContentSettingName[];
-extern const char kClipboardContentSettingDescription[];
-
 extern const char kCloudImportName[];
 extern const char kCloudImportDescription[];
 
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index f9e8465e..8b93fcc 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -199,7 +199,6 @@
 void AttemptUserExit() {
 #if defined(OS_CHROMEOS)
   VLOG(1) << "AttemptUserExit";
-  browser_shutdown::StartShutdownTracing();
   chromeos::BootTimesRecorder::Get()->AddLogoutTimeMarker("LogoutStarted",
                                                           false);
 
diff --git a/chrome/browser/lifetime/browser_shutdown.cc b/chrome/browser/lifetime/browser_shutdown.cc
index e0edf124..123028a 100644
--- a/chrome/browser/lifetime/browser_shutdown.cc
+++ b/chrome/browser/lifetime/browser_shutdown.cc
@@ -123,12 +123,6 @@
   static crash_reporter::CrashKeyString<8> shutdown_type_key("shutdown-type");
   shutdown_type_key.Set(ToShutdownTypeString(type));
 
-#if !defined(OS_CHROMEOS)
-  // Start the shutdown tracing. Note that On ChromeOS this has already been
-  // called in AttemptUserExit().
-  StartShutdownTracing();
-#endif
-
   g_shutdown_type = type;
   // For now, we're only counting the number of renderer processes
   // since we can't safely count the number of plugin processes from this
@@ -367,17 +361,4 @@
   return g_trying_to_quit;
 }
 
-void StartShutdownTracing() {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kTraceShutdown)) {
-    base::trace_event::TraceConfig trace_config(
-        command_line.GetSwitchValueASCII(switches::kTraceShutdown), "");
-    content::TracingController::GetInstance()->StartTracing(
-        trace_config,
-        content::TracingController::StartTracingDoneCallback());
-  }
-  TRACE_EVENT0("shutdown", "StartShutdownTracing");
-}
-
 }  // namespace browser_shutdown
diff --git a/chrome/browser/lifetime/browser_shutdown.h b/chrome/browser/lifetime/browser_shutdown.h
index 74a153dc..53625a3 100644
--- a/chrome/browser/lifetime/browser_shutdown.h
+++ b/chrome/browser/lifetime/browser_shutdown.h
@@ -89,11 +89,6 @@
 // General accessor.
 bool IsTryingToQuit();
 
-// Starts to collect shutdown traces. On ChromeOS this will start immediately
-// on AttemptUserExit() and all other systems will start once all tabs are
-// closed.
-void StartShutdownTracing();
-
 }  // namespace browser_shutdown
 
 #endif  // CHROME_BROWSER_LIFETIME_BROWSER_SHUTDOWN_H_
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index 6470f4c..b924d995fd 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -168,6 +168,7 @@
   hit_javascript_errors_.Get() = false;
 
   EnablePixelOutput();
+  EnableAudioOutput();
 }
 
 WebRtcTestBase::~WebRtcTestBase() {
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 4cb7d61..83d16e3f 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -3849,6 +3849,9 @@
 // bubble is shown instead of silent update.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
                        NoSilentOverwriteOnPSLMatch) {
+  // The test matches the behavior of the new password form manager.
+  base::test::ScopedFeatureList scoped_feature_list;
+  SetNewParsingForSaving(&scoped_feature_list, true);
   // Store a password at origin A.
   const GURL url_A = embedded_test_server()->GetURL("abc.foo.com", "/");
   scoped_refptr<password_manager::TestPasswordStore> password_store =
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 65fa880..b9e6f59 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -758,6 +758,9 @@
   { key::kDeviceBatteryChargeCustomStopCharging,
     ash::prefs::kDeviceBatteryChargeCustomStopCharging,
     base::Value::Type::INTEGER },
+  { key::kDeviceUsbPowerShareEnabled,
+    ash::prefs::kDeviceUsbPowerShareEnabled,
+    base::Value::Type::BOOLEAN },
 #endif  // defined(OS_CHROMEOS)
 
 // Metrics reporting is controlled by a platform specific policy for ChromeOS
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
index 23a62bd..e1edb86 100644
--- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -42,6 +42,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/url_loader_interceptor.h"
 #include "net/base/escape.h"
+#include "net/base/features.h"
 #include "net/base/load_flags.h"
 #include "net/cookies/cookie_store.h"
 #include "net/dns/mock_host_resolver.h"
@@ -211,6 +212,29 @@
   DISALLOW_COPY_AND_ASSIGN(NoStatePrefetchBrowserTest);
 };
 
+class NoStatePrefetchBrowserTestHttpCache
+    : public NoStatePrefetchBrowserTest,
+      public testing::WithParamInterface<bool> {
+ protected:
+  void SetUp() override {
+    if (GetParam()) {
+      feature_list_.InitAndEnableFeature(
+          net::features::kSplitCacheByTopFrameOrigin);
+    }
+    NoStatePrefetchBrowserTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(DefaultKeyedHttpCache,
+                         NoStatePrefetchBrowserTestHttpCache,
+                         ::testing::Values(false));
+INSTANTIATE_TEST_SUITE_P(DoubleKeyedHttpCache,
+                         NoStatePrefetchBrowserTestHttpCache,
+                         ::testing::Values(true));
+
 // Checks that a page is correctly prefetched in the case of a
 // <link rel=prerender> tag and the JavaScript on the page is not executed.
 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchSimple) {
@@ -239,18 +263,42 @@
   WaitForRequestCount(src_server()->GetURL(kPrefetchPngRedirect), 1);
 }
 
-// Checks that a page load following a prefetch reuses preload-scanned
-// resources from cache without failing over to network.
-IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, LoadAfterPrefetch) {
+// Checks that a page load following a prefetch reuses preload-scanned resources
+// and link rel 'prerender' main resource from cache without failing over to
+// network.
+IN_PROC_BROWSER_TEST_P(NoStatePrefetchBrowserTestHttpCache, LoadAfterPrefetch) {
   {
     std::unique_ptr<TestPrerender> test_prerender = PrefetchFromFile(
         kPrefetchPageBigger, FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+    WaitForRequestCount(src_server()->GetURL(kPrefetchPageBigger), 1);
     WaitForRequestCount(src_server()->GetURL(kPrefetchJpeg), 1);
     WaitForRequestCount(src_server()->GetURL(kPrefetchPng2), 1);
   }
   ui_test_utils::NavigateToURL(current_browser(),
                                src_server()->GetURL(kPrefetchPageBigger));
   // Check that the request counts did not increase.
+  WaitForRequestCount(src_server()->GetURL(kPrefetchPageBigger), 1);
+  WaitForRequestCount(src_server()->GetURL(kPrefetchJpeg), 1);
+  WaitForRequestCount(src_server()->GetURL(kPrefetchPng2), 1);
+}
+
+// Checks that a page load following a cross origin prefetch reuses
+// preload-scanned resources and link rel 'prerender' main resource
+// from cache without failing over to network.
+IN_PROC_BROWSER_TEST_P(NoStatePrefetchBrowserTestHttpCache,
+                       LoadAfterPrefetchCrossOrigin) {
+  static const std::string kSecondaryDomain = "www.foo.com";
+  GURL cross_domain_url =
+      embedded_test_server()->GetURL(kSecondaryDomain, kPrefetchPageBigger);
+
+  PrefetchFromURL(cross_domain_url, FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+  WaitForRequestCount(src_server()->GetURL(kPrefetchPageBigger), 1);
+  WaitForRequestCount(src_server()->GetURL(kPrefetchJpeg), 1);
+  WaitForRequestCount(src_server()->GetURL(kPrefetchPng2), 1);
+
+  ui_test_utils::NavigateToURL(current_browser(), cross_domain_url);
+  // Check that the request counts did not increase.
+  WaitForRequestCount(src_server()->GetURL(kPrefetchPageBigger), 1);
   WaitForRequestCount(src_server()->GetURL(kPrefetchJpeg), 1);
   WaitForRequestCount(src_server()->GetURL(kPrefetchPng2), 1);
 }
diff --git a/chrome/browser/prerender/prerender_test_utils.cc b/chrome/browser/prerender/prerender_test_utils.cc
index e57030a7..224d614 100644
--- a/chrome/browser/prerender/prerender_test_utils.cc
+++ b/chrome/browser/prerender/prerender_test_utils.cc
@@ -185,8 +185,7 @@
   void BlockRequest() override {}
 
   void RunExternalProtocolDialog(const GURL& url,
-                                 int render_process_host_id,
-                                 int routing_id,
+                                 content::WebContents* web_contents,
                                  ui::PageTransition page_transition,
                                  bool has_user_gesture) override {
     NOTREACHED();
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index c34834d..0c51bfdb 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -39,8 +39,6 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
@@ -1415,74 +1413,6 @@
   WaitForPingback();
 }
 
-class TestDataReductionProxyPingbackClient
-    : public data_reduction_proxy::DataReductionProxyPingbackClient {
- public:
-  void WaitForPingback() {
-    base::RunLoop run_loop;
-    wait_for_pingback_closure_ = run_loop.QuitClosure();
-    run_loop.Run();
-  }
-
-  data_reduction_proxy::DataReductionProxyData* data() { return data_.get(); }
-
- private:
-  void SendPingback(
-      const data_reduction_proxy::DataReductionProxyData& data,
-      const data_reduction_proxy::DataReductionProxyPageLoadTiming& timing)
-      override {
-    data_ = data.DeepCopy();
-    if (wait_for_pingback_closure_)
-      std::move(wait_for_pingback_closure_).Run();
-  }
-
-  void SetPingbackReportingFraction(
-      float pingback_reporting_fraction) override {}
-
-  base::OnceClosure wait_for_pingback_closure_;
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data_;
-};
-
-IN_PROC_BROWSER_TEST_P(PreviewsLitePageServerBrowserTest,
-                       DISABLE_ON_WIN_MAC_CHROMESOS(PingbackContent)) {
-  TestDataReductionProxyPingbackClient* pingback_client =
-      new TestDataReductionProxyPingbackClient();
-  DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-      browser()->profile())
-      ->data_reduction_proxy_service()
-      ->SetPingbackClientForTesting(pingback_client);
-
-  ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
-  VerifyPreviewLoaded();
-
-  PreviewsUITabHelper* ui_tab_helper =
-      PreviewsUITabHelper::FromWebContents(GetWebContents());
-  previews::PreviewsUserData* previews_data =
-      ui_tab_helper->previews_user_data();
-  // Grab the page id and session now because they may change after the reload.
-  uint64_t expected_page_id = previews_data->server_lite_page_info()->page_id;
-  std::string expected_session_key =
-      previews_data->server_lite_page_info()->drp_session_key;
-
-  // Starting a new page load will send a pingback for the previous page load.
-  GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false);
-  pingback_client->WaitForPingback();
-
-  data_reduction_proxy::DataReductionProxyData* data = pingback_client->data();
-  EXPECT_TRUE(data->used_data_reduction_proxy());
-  EXPECT_TRUE(data->lite_page_received());
-  EXPECT_FALSE(data->lofi_policy_received());
-  EXPECT_FALSE(data->lofi_received());
-  EXPECT_FALSE(data->was_cached_data_reduction_proxy_response());
-
-  // TODO(crbug.com/952523): Fix and remove this early return.
-  if (GetParam())
-    return;
-
-  EXPECT_EQ(data->session_key(), expected_session_key);
-  EXPECT_EQ(data->page_id().value(), expected_page_id);
-}
-
 class PreviewsLitePageServerTimeoutBrowserTest
     : public PreviewsLitePageServerBrowserTest {
  public:
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
index 0841b60d..7bdacbf 100644
--- a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
+++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
@@ -116,27 +116,26 @@
     // restart. Note: This could be a navigation to the litepages server, or to
     // the original URL.
     if (restarted_navigation_url_ == handle->GetURL()) {
-      if (!info_) {
-        // Create a new info_ if needed. This will use the previous page_id,
-        // which is desired.
-        PreviewsService* previews_service =
-            PreviewsServiceFactory::GetForProfile(Profile::FromBrowserContext(
-                web_contents()->GetBrowserContext()));
-        PreviewsLitePageNavigationThrottleManager* manager =
-            previews_service->previews_lite_page_decider();
-
-        info_ =
-            PreviewsLitePageNavigationThrottle::GetOrCreateServerLitePageInfo(
-                handle, manager)
-                ->Clone();
-      }
+      // Get a new page id.
+      PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
+          Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+      PreviewsLitePageNavigationThrottleManager* manager =
+          previews_service->previews_lite_page_decider();
+      uint64_t page_id = manager->GeneratePageID();
 
       // Create a new PreviewsUserData if needed.
       PreviewsUITabHelper* ui_tab_helper =
           PreviewsUITabHelper::FromWebContents(web_contents());
       previews::PreviewsUserData* previews_data =
-          ui_tab_helper->CreatePreviewsUserDataForNavigationHandle(
-              handle, info_->page_id);
+          ui_tab_helper->CreatePreviewsUserDataForNavigationHandle(handle,
+                                                                   page_id);
+
+      // Set the lite page state on the user data.
+      if (!info_) {
+        info_ =
+            std::make_unique<previews::PreviewsUserData::ServerLitePageInfo>();
+        info_->original_navigation_start = handle->NavigationStart();
+      }
       previews_data->set_server_lite_page_info(std::move(info_));
 
       // Reset member state.
diff --git a/chrome/browser/renderer_host/chrome_navigation_ui_data.cc b/chrome/browser/renderer_host/chrome_navigation_ui_data.cc
index cc45146..afea094 100644
--- a/chrome/browser/renderer_host/chrome_navigation_ui_data.cc
+++ b/chrome/browser/renderer_host/chrome_navigation_ui_data.cc
@@ -47,12 +47,9 @@
 std::unique_ptr<ChromeNavigationUIData>
 ChromeNavigationUIData::CreateForMainFrameNavigation(
     content::WebContents* web_contents,
-    WindowOpenDisposition disposition,
-    int64_t data_reduction_proxy_page_id) {
+    WindowOpenDisposition disposition) {
   auto navigation_ui_data = std::make_unique<ChromeNavigationUIData>();
   navigation_ui_data->disposition_ = disposition;
-  navigation_ui_data->data_reduction_proxy_page_id_ =
-      data_reduction_proxy_page_id;
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   int tab_id = extension_misc::kUnknownTabId;
@@ -73,7 +70,6 @@
   auto copy = std::make_unique<ChromeNavigationUIData>();
 
   copy->disposition_ = disposition_;
-  copy->data_reduction_proxy_page_id_ = data_reduction_proxy_page_id_;
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   if (extension_data_)
diff --git a/chrome/browser/renderer_host/chrome_navigation_ui_data.h b/chrome/browser/renderer_host/chrome_navigation_ui_data.h
index 6f6b20e..f40feb1e 100644
--- a/chrome/browser/renderer_host/chrome_navigation_ui_data.h
+++ b/chrome/browser/renderer_host/chrome_navigation_ui_data.h
@@ -34,8 +34,7 @@
 
   static std::unique_ptr<ChromeNavigationUIData> CreateForMainFrameNavigation(
       content::WebContents* web_contents,
-      WindowOpenDisposition disposition,
-      int64_t data_reduction_proxy_page_id);
+      WindowOpenDisposition disposition);
 
   // Creates a new ChromeNavigationUIData that is a deep copy of the original.
   // Any changes to the original after the clone is created will not be
@@ -66,9 +65,6 @@
   const std::string& prerender_histogram_prefix() {
     return prerender_histogram_prefix_;
   }
-  uint64_t data_reduction_proxy_page_id() const {
-    return data_reduction_proxy_page_id_;
-  }
 
  private:
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -85,7 +81,6 @@
   WindowOpenDisposition disposition_;
   prerender::PrerenderMode prerender_mode_ = prerender::NO_PRERENDER;
   std::string prerender_histogram_prefix_;
-  uint64_t data_reduction_proxy_page_id_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeNavigationUIData);
 };
diff --git a/chrome/browser/resources/chromeos/braille_ime/BUILD.gn b/chrome/browser/resources/chromeos/braille_ime/BUILD.gn
index b91d293..823b74c 100644
--- a/chrome/browser/resources/chromeos/braille_ime/BUILD.gn
+++ b/chrome/browser/resources/chromeos/braille_ime/BUILD.gn
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//chromecast/chromecast.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 
-assert(is_chromeos)
+assert(is_chromeos || is_chromecast)
 
 copy("braille_ime_manifest") {
   sources = [
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css
index 621e015..19563472 100644
--- a/chrome/browser/resources/chromeos/camera/src/css/main.css
+++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -212,14 +212,15 @@
   -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0, rgba(0,0,0,1) 10% 90%, rgba(0,0,0,0) 100%);
   bottom: var(--modes-bottom);
   flex-direction: column;
-  height: var(--modes-height);
+  height: calc(var(--modes-height) * 0.8);
   justify-content: flex-start;
   overflow: scroll;
+  padding: calc(var(--modes-height) * 0.1) 0;
   pointer-events: auto;
 }
 
 .mode-item {
-  margin: 5px 0;
+  margin: 4px 0;
   position: relative;
 }
 
@@ -229,9 +230,9 @@
   display: inline-block;
   font-family: 'Roboto', sans-serif;
   font-size: 14px;
-  font-weight: 400;
+  font-weight: 500;
   padding: 10px 15px;
-  text-shadow: 2px 3px 3px rgba(32, 33, 36, 0.5);
+  text-shadow: 2px 3px 3px rgba(32, 33, 36, 0.3);
 }
 
 .mode-item>input {
@@ -241,7 +242,7 @@
 }
 
 .mode-item>input:checked + span {
-  background: rgb(238, 238, 238);
+  background: white;
   color: black;
   text-shadow: none;
 }
@@ -374,12 +375,12 @@
 }
 
 #options-group {
-  bottom: calc((var(--bottom-line) + (var(--big-icon)/2)) + 30px);
+  bottom: calc((var(--bottom-line) + (var(--big-icon) / 2)) + 30px);
   flex-direction: column;
 }
 
 body:not(.multi-camera) #options-group {
-  bottom: calc((var(--bottom-line) - 18px) - (var(--small-icon)/2));
+  bottom: calc((var(--bottom-line) - 18px) - (var(--small-icon) / 2));
 }
 
 #options-group input {
@@ -481,11 +482,17 @@
 #camera {
   --big-icon: 48px;
   --bottom-line: 56px;
-  --modes-height: 120px;
-  --modes-bottom: calc((var(--bottom-line) + (var(--big-icon)/2)) + 24px);
+  --modes-height: 130px;
+  --modes-bottom: calc((var(--bottom-line) + (var(--big-icon) / 2)) + 24px);
   --small-icon: 40px;
 }
 
+@media screen and (min-height: 800px) {
+  #camera {
+    --modes-height: 220px;
+  }
+}
+
 body.w-letterbox.w-letterbox-s #camera {
   justify-content: flex-end;
 }
@@ -520,7 +527,7 @@
 }
 
 body:not(.w-letterbox).preview-vertical-dock #preview-wrapper {
-  bottom: calc((var(--bottom-line) + (var(--big-icon)/2)) + 12px);
+  bottom: calc((var(--bottom-line) + (var(--big-icon) / 2)) + 12px);
 }
 
 body:not(.mode-switching).square-mode #preview-wrapper {
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
index c3226666..deb74e2 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
@@ -54,6 +54,12 @@
   this.stream_ = null;
 
   /**
+   * @type {HTMLElement}
+   * @private
+   */
+  this.modesGroup_ = document.querySelector('#modes-group');
+
+  /**
    * Mode classname and related functions and attributes.
    * @type {Object<string, Object>}
    * @private
@@ -136,7 +142,13 @@
   Object.keys(this.allModes).forEach((m) => cca.state.set(m, m == mode));
   const element = document.querySelector(`.mode-item>input[data-mode=${mode}]`);
   element.checked = true;
-  element.focus();
+  const wrapper = element.parentElement;
+  this.modesGroup_.scrollTo({
+    left: 0,
+    top: wrapper.offsetTop - this.modesGroup_.offsetHeight / 2 +
+        wrapper.offsetHeight / 2,
+    behavior: 'smooth',
+  });
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 340a44c..0327edc3 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -5,12 +5,13 @@
 import("//build/config/features.gni")
 import("//chrome/common/features.gni")
 import("//chrome/test/base/js2gtest.gni")
+import("//chromecast/chromecast.gni")
 import("//components/nacl/features.gni")
 import("//testing/test.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("run_jsbundler.gni")
 
-assert(is_chromeos)
+assert(is_chromeos || is_chromecast)
 
 declare_args() {
   # Whether to compress the main Chromevox javascript files or load the
@@ -490,34 +491,36 @@
   }
 }
 
-source_set("browser_tests") {
-  testonly = true
-  assert(enable_extensions)
+if (is_chromeos) {
+  source_set("browser_tests") {
+    testonly = true
+    assert(enable_extensions)
 
-  deps = [
-    ":chromevox_extjs_tests",
-    ":chromevox_unitjs_tests",
-  ]
+    deps = [
+      ":chromevox_extjs_tests",
+      ":chromevox_unitjs_tests",
+    ]
 
-  # TODO(jamescook): Figure out which of these are really necessary.
-  data = [
-    "$root_out_dir/chrome_100_percent.pak",
-    "$root_out_dir/chrome_200_percent.pak",
-    "$root_out_dir/locales/en-US.pak",
-    "$root_out_dir/locales/fr.pak",
-    "$root_out_dir/resources.pak",
-    "$root_out_dir/resources/chromeos/chromevox/",
-    "$root_out_dir/test_data/chrome/browser/resources/chromeos/chromevox/",
+    # TODO(jamescook): Figure out which of these are really necessary.
+    data = [
+      "$root_out_dir/chrome_100_percent.pak",
+      "$root_out_dir/chrome_200_percent.pak",
+      "$root_out_dir/locales/en-US.pak",
+      "$root_out_dir/locales/fr.pak",
+      "$root_out_dir/resources.pak",
+      "$root_out_dir/resources/chromeos/chromevox/",
+      "$root_out_dir/test_data/chrome/browser/resources/chromeos/chromevox/",
 
-    # Surprisingly, the test uses data from the original location, not the
-    # copied one.
-    "//chrome/browser/resources/chromeos/chromevox/",
-    "//chrome/test/data/webui/test_api.js",
-    "//third_party/chromevox/",
-    "//chrome/third_party/mock4js/",
-    "//third_party/accessibility-audit/axs_testing.js",
-    "//third_party/chaijs/chai.js",
-  ]
+      # Surprisingly, the test uses data from the original location, not the
+      # copied one.
+      "//chrome/browser/resources/chromeos/chromevox/",
+      "//chrome/test/data/webui/test_api.js",
+      "//third_party/chromevox/",
+      "//chrome/third_party/mock4js/",
+      "//third_party/accessibility-audit/axs_testing.js",
+      "//third_party/chaijs/chai.js",
+    ]
+  }
 }
 
 action("chromevox_test_messages_js") {
@@ -612,45 +615,47 @@
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 }
 
-js2gtest("chromevox_extjs_tests") {
-  test_type = "extension"
-  sources = [
-    "braille/braille_table_test.extjs",
-    "braille/braille_translator_manager_test.extjs",
-    "braille/liblouis_test.extjs",
-    "cvox2/background/automation_util_test.extjs",
-    "cvox2/background/background_test.extjs",
-    "cvox2/background/braille_command_data_test.extjs",
-    "cvox2/background/color_test.extjs",
-    "cvox2/background/cursors_test.extjs",
-    "cvox2/background/download_handler_test.extjs",
-    "cvox2/background/editing_test.extjs",
-    "cvox2/background/i_search_test.extjs",
-    "cvox2/background/language_switching_test.extjs",
-    "cvox2/background/live_regions_test.extjs",
-    "cvox2/background/log_store_test.extjs",
-    "cvox2/background/output_test.extjs",
-    "cvox2/background/panel_test.extjs",
-    "cvox2/background/recovery_strategy_test.extjs",
-    "cvox2/background/tree_walker_test.extjs",
-    "host/chrome/tts_background_test.extjs",
-  ]
-  gen_include_files = [
-    "testing/assert_additions.js",
-    "testing/callback_helper.js",
-    "testing/chromevox_e2e_test_base.js",
-    "testing/chromevox_next_e2e_test_base.js",
-    "testing/mock_feedback.js",
-  ]
+if (is_chromeos) {
+  js2gtest("chromevox_extjs_tests") {
+    test_type = "extension"
+    sources = [
+      "braille/braille_table_test.extjs",
+      "braille/braille_translator_manager_test.extjs",
+      "braille/liblouis_test.extjs",
+      "cvox2/background/automation_util_test.extjs",
+      "cvox2/background/background_test.extjs",
+      "cvox2/background/braille_command_data_test.extjs",
+      "cvox2/background/color_test.extjs",
+      "cvox2/background/cursors_test.extjs",
+      "cvox2/background/download_handler_test.extjs",
+      "cvox2/background/editing_test.extjs",
+      "cvox2/background/i_search_test.extjs",
+      "cvox2/background/language_switching_test.extjs",
+      "cvox2/background/live_regions_test.extjs",
+      "cvox2/background/log_store_test.extjs",
+      "cvox2/background/output_test.extjs",
+      "cvox2/background/panel_test.extjs",
+      "cvox2/background/recovery_strategy_test.extjs",
+      "cvox2/background/tree_walker_test.extjs",
+      "host/chrome/tts_background_test.extjs",
+    ]
+    gen_include_files = [
+      "testing/assert_additions.js",
+      "testing/callback_helper.js",
+      "testing/chromevox_e2e_test_base.js",
+      "testing/chromevox_next_e2e_test_base.js",
+      "testing/mock_feedback.js",
+    ]
 
-  # The test base classes generate C++ code with these deps.
-  deps = [
-    "//ash",
-    "//base",
-    "//chrome/browser/chromeos",
-    "//chrome/common",
-  ]
-  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+    # The test base classes generate C++ code with these deps.
+    deps = [
+      "//ash",
+      "//base",
+      "//chrome/browser/chromeos",
+      "//chrome/common",
+    ]
+    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+  }
 }
 
 js_library("tree_walker") {
diff --git a/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni b/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni
index 9f309395..0ae1562 100644
--- a/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni
+++ b/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni
@@ -1,8 +1,9 @@
 # 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("//chromecast/chromecast.gni")
 
-assert(is_chromeos)
+assert(is_chromeos || is_chromecast)
 
 closure_library_dir =
     "//third_party/chromevox/third_party/closure-library/closure/goog"
diff --git a/chrome/browser/resources/chromeos/login/saml_password_attributes.js b/chrome/browser/resources/chromeos/login/saml_password_attributes.js
index 0b8d087..a102125 100644
--- a/chrome/browser/resources/chromeos/login/saml_password_attributes.js
+++ b/chrome/browser/resources/chromeos/login/saml_password_attributes.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// <include src="saml_timestamps.js">
+
 /**
  * @fileoverview A utility for extracting password information from SAML
  * authorization response. This requires that the SAML IDP administrator
@@ -57,16 +59,18 @@
    * Extract password information from the Attribute elements in the given SAML
    * authorization response.
    * @param {string} xmlStr The SAML response XML, as a string.
-   * @return {!PasswordAttributes} The password information extracted.
+   * @return {!PasswordAttributes} A struct containing all the attributes that
+   * could be extracted, formatted as strings. Some or all of the strings can
+   * be empty if some or all of the attributes could not be extracted.
    */
   function readPasswordAttributes(xmlStr) {
     if (xmlStr.length < MIN_SANE_XML_LENGTH ||
         xmlStr.length > MAX_SANE_XML_LENGTH) {
-      return new PasswordAttributes(null, null, null);
+      return PasswordAttributes.EMPTY;
     }
     const xmlDom = new DOMParser().parseFromString(xmlStr, 'text/xml');
     if (!xmlDom) {
-      return new PasswordAttributes(null, null, null);
+      return PasswordAttributes.EMPTY;
     }
 
     return new PasswordAttributes(
@@ -79,11 +83,11 @@
    * Extracts a string from the given XML DOM, using the given query selector.
    * @param {!XMLDocument} xmlDom The XML DOM.
    * @param {string} querySelectorStr The query selector to find the string.
-   * @return {?string} The extracted string (null if failed to extract).
+   * @return {string} The extracted string (empty if failed to extract).
    */
   function extractStringFromXml(xmlDom, querySelectorStr) {
     const element = xmlDom.querySelector(querySelectorStr);
-    return (element && element.textContent) ? element.textContent : null;
+    return (element && element.textContent) ? element.textContent : '';
   }
 
   /**
@@ -91,30 +95,43 @@
    * to find it and using {@code samlTimestamps.decodeTimestamp} to decode it.
    * @param {!XMLDocument} xmlDom The XML DOM.
    * @param {string} querySelectorStr The query selector to find the timestamp.
-   * @return {?Date} The decoded timestamp (null if failed to extract).
+   * @return {string} The timestamp as number of ms since 1970, formatted as a
+   * string (or an empty string if the timestamp could not be extracted).
    */
   function extractTimestampFromXml(xmlDom, querySelectorStr) {
     const valueText = extractStringFromXml(xmlDom, querySelectorStr);
-    return valueText ? samlTimestamps.decodeTimestamp(valueText) : null;
+    if (!valueText) return '';
+
+    const timestamp = samlTimestamps.decodeTimestamp(valueText);
+    return timestamp ? String(timestamp.valueOf()) : '';
   }
 
   /**
-   * Struct to hold password attributes.
+   * Immutable struct to hold password attributes. All three fields are strings
+   * and are always present, but they are empty if that information is missing.
+   * Timestamps are in JS time - the number of ms since 1 January 1970 - but
+   * are also formatted as strings, since this struct is sent from JS into C++,
+   * and strings travel easier than int64s across this boundary.
    * @export @final
    */
   class PasswordAttributes {
     constructor(modifiedTimestamp, expirationTimestamp, passwordChangeUrl) {
-      /** @type {?Date} Password last-modified timestamp. */
+      /** @type {string} Password last-modified timestamp. */
       this.modifiedTimestamp = modifiedTimestamp;
 
-      /** @type {?Date} Password expiration timestamp. */
+      /** @type {string} Password expiration timestamp. */
       this.expirationTimestamp = expirationTimestamp;
 
-      /** @type {?string} Password-change URL. */
+      /** @type {string} Password-change URL. */
       this.passwordChangeUrl = passwordChangeUrl;
+
+      Object.freeze(this);  // Make immutable.
     }
   }
 
+  /** An immutable and empty PasswordAttributes struct. */
+  PasswordAttributes.EMPTY = new PasswordAttributes('', '', '');
+
   // Public functions:
   return {
     readPasswordAttributes: readPasswordAttributes,
diff --git a/chrome/browser/resources/chromeos/login/saml_password_attributes_test.unitjs b/chrome/browser/resources/chromeos/login/saml_password_attributes_test.unitjs
index 39b48fc..6575756 100644
--- a/chrome/browser/resources/chromeos/login/saml_password_attributes_test.unitjs
+++ b/chrome/browser/resources/chromeos/login/saml_password_attributes_test.unitjs
@@ -56,33 +56,33 @@
 };
 
 TEST_F('SamlPasswordAttributesUnitTest', 'ReadInvalid', function() {
-  // Make sure null is returned for empty input:
+  // Make sure empty result is returned for empty input:
   let result = samlPasswordAttributes.readPasswordAttributes('');
-  assertEquals(null, result.modifiedTimestamp);
-  assertEquals(null, result.expirationTimestamp);
-  assertEquals(null, result.passwordChangeUrl);
+  assertEquals('', result.modifiedTimestamp);
+  assertEquals('', result.expirationTimestamp);
+  assertEquals('', result.passwordChangeUrl);
 
-  // Make sure null is returned for random junk:
+  // Make sure empty result is returned for random junk:
   result = samlPasswordAttributes.readPasswordAttributes('<abc></abc>');
-  assertEquals(null, result.modifiedTimestamp);
-  assertEquals(null, result.expirationTimestamp);
-  assertEquals(null, result.passwordChangeUrl);
+  assertEquals('', result.modifiedTimestamp);
+  assertEquals('', result.expirationTimestamp);
+  assertEquals('', result.passwordChangeUrl);
 
-  // Make sure null is returned when the input is almost valid, but not quite:
+  // Make sure empty result is returned when the input is almost valid, but not quite:
   result = samlPasswordAttributes.readPasswordAttributes(
       XML_TEST_DATA_WITH_ATTRIBUTES_REMOVED);
-  assertEquals(null, result.modifiedTimestamp);
-  assertEquals(null, result.expirationTimestamp);
-  assertEquals(null, result.passwordChangeUrl);
+  assertEquals('', result.modifiedTimestamp);
+  assertEquals('', result.expirationTimestamp);
+  assertEquals('', result.passwordChangeUrl);
 });
 
 TEST_F('SamlPasswordAttributesUnitTest', 'ReadValid', function() {
   const result = samlPasswordAttributes.readPasswordAttributes(XML_TEST_DATA);
 
-  assertEquals(Date.parse('2019-02-22T11:50:58.421Z'),
-               result.modifiedTimestamp.valueOf());
-  assertEquals(Date.parse('2019-03-06T11:50:58.421Z'),
-               result.expirationTimestamp.valueOf());
+  assertEquals(String(Date.parse('2019-02-22T11:50:58.421Z')),
+               result.modifiedTimestamp);
+  assertEquals(String(Date.parse('2019-03-06T11:50:58.421Z')),
+               result.expirationTimestamp);
   assertEquals('https://example.com/adfs/portal/updatepassword/',
                result.passwordChangeUrl);
 });
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 48d0de3..b7b1080 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -91,7 +91,9 @@
     'lsbReleaseBoard',           // Chrome OS Release board name
     'isFirstUser',               // True if this is non-enterprise device,
                                  // and there are no users yet.
-    'obfuscatedOwnerId',         // Obfuscated device owner ID, if neeed.
+    'obfuscatedOwnerId',         // Obfuscated device owner ID, if needed.
+    'extractSamlPasswordAttributes',  // If enabled attempts to extract password
+                                      // attributes from the SAML response.
 
     // The email fields allow for the following possibilities:
     //
@@ -304,6 +306,8 @@
       // http. Otherwise, block insecure content as long as gaia is https.
       this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP &&
           this.idpOrigin_.startsWith('https://');
+      this.samlHandler_.extractSamlPasswordAttributes =
+          data.extractSamlPasswordAttributes;
       this.needPassword = !('needPassword' in data) || data.needPassword;
 
       if (this.isNewGaiaFlow) {
diff --git a/chrome/browser/resources/gaia_auth_host/saml_handler.js b/chrome/browser/resources/gaia_auth_host/saml_handler.js
index c3fabeb..76694699 100644
--- a/chrome/browser/resources/gaia_auth_host/saml_handler.js
+++ b/chrome/browser/resources/gaia_auth_host/saml_handler.js
@@ -4,6 +4,7 @@
 
 // <include src="post_message_channel.js">
 // <include src="webview_event_manager.js">
+// <include src="../chromeos/login/saml_password_attributes.js">
 
 /**
  * @fileoverview Saml support for webview based auth.
@@ -148,13 +149,20 @@
        */
       this.apiPasswordBytes_ = null;
 
-      /*
+      /**
        * Whether to abort the authentication flow and show an error messagen
        * when content served over an unencrypted connection is detected.
        * @type {boolean}
        */
       this.blockInsecureContent = false;
 
+      /**
+       * Whether to attempt to extract password attributes from the SAMLResponse
+       * XML. See ../chromeos/login/saml_password_attributes.js
+       * @type {boolean}
+       */
+      this.extractSamlPasswordAttributes = false;
+
       this.webviewEventManager_ = WebviewEventManager.create();
 
       this.webviewEventManager_.addEventListener(
@@ -170,6 +178,12 @@
           this.onInsecureRequest.bind(this),
           {urls: ['http://*/*', 'file://*/*', 'ftp://*/*']}, ['blocking']);
 
+      this.webviewEventManager_.addWebRequestEventListener(
+          this.webview_.request.onBeforeRequest,
+          this.onMainFrameWebRequest.bind(this),
+          {urls: ['http://*/*', 'https://*/*'], types: ['main_frame']},
+          ['requestBody']);
+
       if (!this.startsOnSamlPage_) {
         this.webviewEventManager_.addEventListener(
             this.webview_, 'loadcommit', this.onLoadCommit_.bind(this));
@@ -345,6 +359,37 @@
     }
 
     /**
+     * Handler for webRequest.onBeforeRequest that looks for the Base64
+     * encoded SAMLResponse in the POST-ed formdata sent from the SAML page.
+     * Non-blocking.
+     * @param {Object} details The web-request details.
+     */
+    onMainFrameWebRequest(details) {
+      if (!this.extractSamlPasswordAttributes) return;
+      if (!this.isSamlPage_ || details.method != 'POST') return;
+
+      const formData = details.requestBody.formData;
+      let samlResponse = (formData && formData.SAMLResponse);
+      if (!samlResponse) {
+        samlResponse = new URL(details.url).searchParams.get('SAMLResponse');
+      }
+      if (!samlResponse) return;
+
+      try {
+        // atob means asciiToBinary, which actually means base64Decode:
+        samlResponse = window.atob(samlResponse);
+      } catch (decodingError) {
+        console.warn('SAMLResponse is not Base64 encoded');
+        return;
+      }
+
+      const attr = samlPasswordAttributes.readPasswordAttributes(samlResponse);
+      chrome.send('updatePasswordAttributes', [
+        attr.modifiedTimestamp, attr.expirationTimestamp, attr.passwordChangeUrl
+      ]);
+    }
+
+    /**
      * Invoked when headers are received for the main frame.
      * @private
      */
diff --git a/chrome/browser/resources/management/management_ui.html b/chrome/browser/resources/management/management_ui.html
index 2d9850e2..2f15e52 100644
--- a/chrome/browser/resources/management/management_ui.html
+++ b/chrome/browser/resources/management/management_ui.html
@@ -92,6 +92,10 @@
         margin-inline-start: 20px;
       }
 
+      .overview-section {
+        padding-top: 10px;
+      }
+
       .overview-section div + div {
         margin-top: 1em;
       }
@@ -105,12 +109,17 @@
       }
 
 <if expr="chromeos">
-      .device-reporting div {
-        align-items: center;
-        display: flex;
+      .device-reporting-section {
+        padding-bottom: 13px;
       }
 
-      .device-reporting div + div {
+      .device-reporting-section ul {
+        list-style: none;
+        padding: 0;
+        margin: 0;
+      }
+
+      .device-reporting-section li + li {
         margin-top: 2em;
       }
 
@@ -118,10 +127,6 @@
         margin-inline-end: 10px;
         width: 24px;
       }
-
-      .device-reporting {
-        margin-bottom: 2em;
-      }
 </if>
 
       .extension-name {
@@ -201,25 +206,28 @@
           </section>
 <if expr="chromeos">
           <div hidden="[[!localTrustRoots_]]">
-            <section class="three-line single-column">
+            <section class="single-column">
               <h2>$i18n{localTrustRoots}</h2>
-              <div id="trust-roots-configuration">[[localTrustRoots_]]</div>
+              <div class="subtitle" id="trust-roots-configuration">
+                [[localTrustRoots_]]</div>
             </section>
           </div>
           <template is="dom-if"
               if="[[showDeviceReportingInfo_(deviceReportingInfo_)]]">
-            <section class="single-column">
+            <section class="single-column device-reporting-section">
               <h2>$i18n{deviceReporting}</h2>
               <div class="subtitle">$i18n{deviceConfiguration}</div>
-              <template is="dom-repeat" items="[[deviceReportingInfo_]]">
-                <div class="device-reporting">
-                  <span>
-                    <iron-icon icon="[[getIconForDeviceReportingType_(
-                        item.reportingType)]]"></iron-icon>
-                    [[i18n(item.messageId)]]
-                  </span>
-                </div>
-              </template>
+              <ul>
+                <template is="dom-repeat" items="[[deviceReportingInfo_]]">
+                  <li class="device-reporting">
+                    <span>
+                      <iron-icon icon="[[getIconForDeviceReportingType_(
+                          item.reportingType)]]"></iron-icon>
+                      [[i18n(item.messageId)]]
+                    </span>
+                  </li>
+                </template>
+              </ul>
             </section>
           </template>
 </if>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index a145333..f1da2b7 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -612,23 +612,21 @@
 </if>
         </settings-subpage>
       </template>
-      <template is="dom-if" if="[[enableClipboardContentSetting_]]">
-        <template is="dom-if" route-path="/content/clipboard" no-search>
-          <settings-subpage page-title="$i18n{siteSettingsClipboard}"
-              search-label="$i18n{siteSettingsAllSitesSearch}"
-              search-term="{{searchFilter_}}">
-            <category-default-setting
-                toggle-off-label="$i18n{siteSettingsClipboardBlock}"
-                toggle-on-label="$i18n{siteSettingsClipboardAskRecommended}"
-                category="{{ContentSettingsTypes.CLIPBOARD}}">
-            </category-default-setting>
-            <category-setting-exceptions
-                category="{{ContentSettingsTypes.CLIPBOARD}}"
-                block-header="$i18n{siteSettingsBlock}"
-                search-filter="[[searchFilter_]]">
-            </category-setting-exceptions>
-          </settings-subpage>
-       </template>
+      <template is="dom-if" route-path="/content/clipboard" no-search>
+        <settings-subpage page-title="$i18n{siteSettingsClipboard}"
+            search-label="$i18n{siteSettingsAllSitesSearch}"
+            search-term="{{searchFilter_}}">
+          <category-default-setting
+              toggle-off-label="$i18n{siteSettingsClipboardBlock}"
+              toggle-on-label="$i18n{siteSettingsClipboardAskRecommended}"
+              category="{{ContentSettingsTypes.CLIPBOARD}}">
+          </category-default-setting>
+          <category-setting-exceptions
+              category="{{ContentSettingsTypes.CLIPBOARD}}"
+              block-header="$i18n{siteSettingsBlock}"
+              search-filter="[[searchFilter_]]">
+          </category-setting-exceptions>
+        </settings-subpage>
       </template>
       <template is="dom-if" if="[[enablePaymentHandlerContentSetting_]]">
         <template is="dom-if" route-path="/content/paymentHandler" no-search>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index 6a33e927..4b22eae 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -111,14 +111,6 @@
     },
 
     /** @private */
-    enableClipboardContentSetting_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('enableClipboardContentSetting');
-      }
-    },
-
-    /** @private */
     enablePaymentHandlerContentSetting_: {
       type: Boolean,
       value: function() {
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
index 26e71eb..309b8082 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
@@ -201,9 +201,6 @@
         settings.ContentSettingsTypes.ADS,
         'enableSafeBrowsingSubresourceFilter');
     addOrRemoveSettingWithFlag(
-        settings.ContentSettingsTypes.CLIPBOARD,
-        'enableClipboardContentSetting');
-    addOrRemoveSettingWithFlag(
         settings.ContentSettingsTypes.PAYMENT_HANDLER,
         'enablePaymentHandlerContentSetting');
     return this.contentTypes_.slice(0);
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
index df33aa4d..858b13b 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -218,15 +218,15 @@
         on-click="onTapNavigate_" start-icon="settings:protected-content">
     </cr-link-row>
 
-    <template is="dom-if" if="[[enableClipboardContentSetting_]]">
-      <cr-link-row class="hr two-line" data-route="SITE_SETTINGS_CLIPBOARD"
-          id="clipboard" label="$i18n{siteSettingsClipboard}"
-          on-click="onTapNavigate_" start-icon="settings:clipboard"
-          sub-label="[[defaultSettingLabel_(
-              default_.clipboard,
-              '$i18nPolymer{siteSettingsAskBeforeAccessing}',
-              '$i18nPolymer{siteSettingsBlocked}')]]"></cr-link-row>
-    </template>
+    <cr-link-row class="hr two-line" data-route="SITE_SETTINGS_CLIPBOARD"
+        id="clipboard" label="$i18n{siteSettingsClipboard}"
+        on-click="onTapNavigate_" start-icon="settings:clipboard"
+        sub-label="[[defaultSettingLabel_(
+            default_.clipboard,
+            '$i18nPolymer{siteSettingsAskBeforeAccessing}',
+            '$i18nPolymer{siteSettingsBlocked}')]]">
+    </cr-link-row>
+
     <template is="dom-if" if="[[enablePaymentHandlerContentSetting_]]">
       <cr-link-row class="hr two-line"
           data-route="SITE_SETTINGS_PAYMENT_HANDLER" id="paymentHandler"
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
index cde5b22..278ecb9 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
@@ -52,14 +52,6 @@
     },
 
     /** @private */
-    enableClipboardContentSetting_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('enableClipboardContentSetting');
-      }
-    },
-
-    /** @private */
     enableSensorsContentSetting_: {
       type: Boolean,
       readOnly: true,
diff --git a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
index 12ad1887..7d502a4 100644
--- a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
@@ -578,8 +578,7 @@
   content::WebContents* web_contents() { return web_contents_; }
 
   void RunExternalProtocolDialog(const GURL& url,
-                                 int render_process_host_id,
-                                 int routing_id,
+                                 content::WebContents* web_contents,
                                  ui::PageTransition page_transition,
                                  bool has_user_gesture) override {}
 
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index a67918e2..a0342c5 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -25,6 +25,8 @@
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/security_events/security_event_recorder.h"
+#include "chrome/browser/security_events/security_event_recorder_factory.h"
 #include "chrome/browser/sync/bookmark_sync_service_factory.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/glue/theme_data_type_controller.h"
@@ -290,6 +292,15 @@
   const base::RepeatingClosure dump_stack = base::BindRepeating(
       &syncer::ReportUnrecoverableError, chrome::GetChannel());
 
+  if (!disabled_types.Has(syncer::SECURITY_EVENTS)) {
+    controllers.push_back(std::make_unique<syncer::ModelTypeController>(
+        syncer::SECURITY_EVENTS,
+        std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
+            SecurityEventRecorderFactory::GetForProfile(profile_)
+                ->GetControllerDelegate()
+                .get())));
+  }
+
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSSupervisedUsers)) {
     controllers.push_back(
@@ -607,10 +618,6 @@
           ->change_processor()
           ->GetControllerDelegate();
 #endif  // defined(OS_CHROMEOS)
-    case syncer::SECURITY_EVENTS:
-      // TODO(crbug.com/919489): Return the real delegate once it is wired to
-      // the security event service.
-      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::USER_CONSENTS:
       return ConsentAuditorFactory::GetForProfile(profile_)
           ->GetControllerDelegate();
@@ -628,6 +635,7 @@
     case syncer::AUTOFILL_WALLET_METADATA:
     case syncer::BOOKMARKS:
     case syncer::DEVICE_INFO:
+    case syncer::SECURITY_EVENTS:
     case syncer::SEND_TAB_TO_SELF:
     case syncer::SESSIONS:
     case syncer::TYPED_URLS:
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 350feca3..a1d9f0f8 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/security_events/security_event_recorder_factory.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
@@ -41,6 +42,7 @@
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
 #include "chrome/common/buildflags.h"
+#include "chrome/common/channel_info.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/invalidation/impl/invalidation_switches.h"
 #include "components/invalidation/impl/profile_identity_provider.h"
@@ -141,6 +143,7 @@
   DependsOn(invalidation::ProfileInvalidationProviderFactory::GetInstance());
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
   DependsOn(PasswordStoreFactory::GetInstance());
+  DependsOn(SecurityEventRecorderFactory::GetInstance());
   DependsOn(SendTabToSelfSyncServiceFactory::GetInstance());
   DependsOn(SpellcheckServiceFactory::GetInstance());
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -183,6 +186,7 @@
           ->GetURLLoaderFactoryForBrowserProcess();
   init_params.network_connection_tracker =
       content::GetNetworkConnectionTracker();
+  init_params.channel = chrome::GetChannel();
   init_params.debug_identifier = profile->GetDebugName();
   init_params.autofill_enable_account_wallet_storage =
       base::FeatureList::IsEnabled(
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index d5198ac..b0d48be 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -85,6 +85,7 @@
     datatypes.push_back(syncer::PRIORITY_PREFERENCES);
     datatypes.push_back(syncer::SESSIONS);
     datatypes.push_back(syncer::PROXY_TABS);
+    datatypes.push_back(syncer::SECURITY_EVENTS);
     datatypes.push_back(syncer::SUPERVISED_USER_SETTINGS);
     datatypes.push_back(syncer::SUPERVISED_USER_WHITELISTS);
     datatypes.push_back(syncer::TYPED_URLS);
@@ -93,8 +94,6 @@
     if (base::FeatureList::IsEnabled(switches::kSyncSendTabToSelf)) {
       datatypes.push_back(syncer::SEND_TAB_TO_SELF);
     }
-    // TODO(markusheintz): Add security events once it is enabled.
-    // datatypes.push_back(syncer::SECURITY_EVENTS);
     return datatypes;
   }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 643059b..b9405d4 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2548,8 +2548,8 @@
       "views/extensions/extensions_menu_view.h",
       "views/extensions/extensions_toolbar_button.cc",
       "views/extensions/extensions_toolbar_button.h",
-      "views/extensions/pwa_confirmation_view.cc",
-      "views/extensions/pwa_confirmation_view.h",
+      "views/extensions/pwa_confirmation_dialog_view.cc",
+      "views/extensions/pwa_confirmation_dialog_view.h",
       "views/extensions/web_app_info_image_source.cc",
       "views/extensions/web_app_info_image_source.h",
       "views/feature_promos/feature_promo_bubble_timeout.cc",
diff --git a/chrome/browser/ui/android/external_protocol_dialog_android.cc b/chrome/browser/ui/android/external_protocol_dialog_android.cc
index 795cf14..83fbf946 100644
--- a/chrome/browser/ui/android/external_protocol_dialog_android.cc
+++ b/chrome/browser/ui/android/external_protocol_dialog_android.cc
@@ -18,14 +18,9 @@
 // static
 void ExternalProtocolHandler::RunExternalProtocolDialog(
     const GURL& url,
-    int render_process_host_id,
-    int routing_id,
+    WebContents* web_contents,
     ui::PageTransition page_transition,
     bool has_user_gesture) {
-  WebContents* web_contents = tab_util::GetWebContentsByID(
-      render_process_host_id, routing_id);
-  if (!web_contents)
-    return;
   navigation_interception::InterceptNavigationDelegate* delegate =
       navigation_interception::InterceptNavigationDelegate::Get(web_contents);
   if (!delegate)
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 8b29fe2..59a9392 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -19,9 +19,6 @@
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
-#include "chrome/browser/previews/previews_lite_page_decider.h"
-#include "chrome/browser/previews/previews_service.h"
-#include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
 #include "chrome/browser/signin/signin_promo.h"
@@ -339,15 +336,9 @@
   // |frame_tree_node_id| is kNoFrameTreeNodeId for main frame navigations.
   if (params->frame_tree_node_id ==
       content::RenderFrameHost::kNoFrameTreeNodeId) {
-    PreviewsService* previews_service =
-        PreviewsServiceFactory::GetForProfile(GetSourceProfile(params));
-    uint64_t previews_page_id =
-        previews_service
-            ? previews_service->previews_lite_page_decider()->GeneratePageID()
-            : 0;
     load_url_params.navigation_ui_data =
         ChromeNavigationUIData::CreateForMainFrameNavigation(
-            target_contents, params->disposition, previews_page_id);
+            target_contents, params->disposition);
   }
 
   if (params->uses_post) {
diff --git a/chrome/browser/ui/external_protocol_dialog_delegate.cc b/chrome/browser/ui/external_protocol_dialog_delegate.cc
index 8f201e7..d4b52d0 100644
--- a/chrome/browser/ui/external_protocol_dialog_delegate.cc
+++ b/chrome/browser/ui/external_protocol_dialog_delegate.cc
@@ -26,11 +26,9 @@
 
 ExternalProtocolDialogDelegate::ExternalProtocolDialogDelegate(
     const GURL& url,
-    int render_process_host_id,
-    int render_view_routing_id)
+    content::WebContents* web_contents)
     : ProtocolDialogDelegate(url),
-      render_process_host_id_(render_process_host_id),
-      render_view_routing_id_(render_view_routing_id),
+      content::WebContentsObserver(web_contents),
       program_name_(shell_integration::GetApplicationNameForProtocol(url)) {}
 
 ExternalProtocolDialogDelegate::~ExternalProtocolDialogDelegate() {}
@@ -59,19 +57,16 @@
 
 void ExternalProtocolDialogDelegate::DoAccept(const GURL& url,
                                               bool remember) const {
-  content::WebContents* web_contents = tab_util::GetWebContentsByID(
-      render_process_host_id_, render_view_routing_id_);
-
-  if (!web_contents)
+  if (!web_contents())
     return;  // The dialog may outlast the WebContents.
 
   if (remember) {
     Profile* profile =
-        Profile::FromBrowserContext(web_contents->GetBrowserContext());
+        Profile::FromBrowserContext(web_contents()->GetBrowserContext());
 
     ExternalProtocolHandler::SetBlockState(
         url.scheme(), ExternalProtocolHandler::DONT_BLOCK, profile);
   }
 
-  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url, web_contents);
+  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url, web_contents());
 }
diff --git a/chrome/browser/ui/external_protocol_dialog_delegate.h b/chrome/browser/ui/external_protocol_dialog_delegate.h
index 57891e7..c241a79a 100644
--- a/chrome/browser/ui/external_protocol_dialog_delegate.h
+++ b/chrome/browser/ui/external_protocol_dialog_delegate.h
@@ -9,15 +9,22 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/protocol_dialog_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "url/gurl.h"
 
 // Provides text for the external protocol handler dialog and handles whether
 // or not to launch the application for the given protocol.
-class ExternalProtocolDialogDelegate : public ProtocolDialogDelegate {
+//
+// Note that this class is a content::WebContentsObserver despite not overriding
+// any methods from content::WebContentsObserver; it is taking advantage of
+// content::WebContentsObserver's behavior where web_contents() will begin
+// returning nullptr after the WebContents is destroyed to create an ersatz weak
+// pointer to the WebContents.
+class ExternalProtocolDialogDelegate : public ProtocolDialogDelegate,
+                                       public content::WebContentsObserver {
  public:
-  explicit ExternalProtocolDialogDelegate(const GURL& url,
-                                          int render_process_host_id,
-                                          int render_view_routing_id);
+  ExternalProtocolDialogDelegate(const GURL& url,
+                                 content::WebContents* web_contents);
   ~ExternalProtocolDialogDelegate() override;
 
   const base::string16& program_name() const { return program_name_; }
@@ -30,8 +37,6 @@
   base::string16 GetTitleText() const override;
 
  private:
-  int render_process_host_id_;
-  int render_view_routing_id_;
   const base::string16 program_name_;
 
   DISALLOW_COPY_AND_ASSIGN(ExternalProtocolDialogDelegate);
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index c841af1..c511355 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -177,11 +177,6 @@
       return true;
   }
 
-  if (info.type == CONTENT_SETTINGS_TYPE_CLIPBOARD_READ) {
-    if (!base::FeatureList::IsEnabled(features::kClipboardContentSetting))
-      return false;
-  }
-
 #if defined(OS_ANDROID)
   // Special geolocation DSE settings apply only on Android, so make sure it
   // gets checked there regardless of default setting on Desktop.
diff --git a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
index 9b20d05..2780cb1 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
@@ -305,16 +305,16 @@
 RecentTabsBuilderTestHelper::BuildUpdateResponseData(
     const sync_pb::SessionSpecifics& specifics,
     base::Time timestamp) {
-  syncer::EntityData entity;
-  *entity.specifics.mutable_session() = specifics;
-  entity.creation_time = timestamp;
-  entity.modification_time = timestamp;
-  entity.client_tag_hash = syncer::GenerateSyncableHash(
+  auto entity = std::make_unique<syncer::EntityData>();
+  *entity->specifics.mutable_session() = specifics;
+  entity->creation_time = timestamp;
+  entity->modification_time = timestamp;
+  entity->client_tag_hash = syncer::GenerateSyncableHash(
       syncer::SESSIONS, sync_sessions::SessionStore::GetClientTag(specifics));
-  entity.id = entity.client_tag_hash;
+  entity->id = entity->client_tag_hash;
 
   auto update = std::make_unique<syncer::UpdateResponseData>();
-  update->entity = entity.PassToPtr();
+  update->entity = std::move(entity);
   update->response_version = ++next_response_version_;
   return update;
 }
diff --git a/chrome/browser/ui/views/extensions/pwa_confirmation_view.cc b/chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.cc
similarity index 82%
rename from chrome/browser/ui/views/extensions/pwa_confirmation_view.cc
rename to chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.cc
index 7b07182..5f045f1 100644
--- a/chrome/browser/ui/views/extensions/pwa_confirmation_view.cc
+++ b/chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.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/extensions/pwa_confirmation_view.h"
+#include "chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.h"
 
 #include <memory>
 #include <utility>
@@ -32,13 +32,13 @@
 
 namespace {
 
-constexpr int kPWAConfirmationViewIconSize = 48;
+constexpr int kPWAConfirmationDialogViewIconSize = 48;
 
 bool g_auto_accept_pwa_for_testing = false;
 
 }  // namespace
 
-PWAConfirmationView::PWAConfirmationView(
+PWAConfirmationDialogView::PWAConfirmationDialogView(
     const WebApplicationInfo& web_app_info,
     chrome::AppInstallationAcceptanceCallback callback)
     : web_app_info_(web_app_info), callback_(std::move(callback)) {
@@ -55,9 +55,9 @@
     Accept();
 }
 
-PWAConfirmationView::~PWAConfirmationView() {}
+PWAConfirmationDialogView::~PWAConfirmationDialogView() {}
 
-gfx::Size PWAConfirmationView::CalculatePreferredSize() const {
+gfx::Size PWAConfirmationDialogView::CalculatePreferredSize() const {
   int bubble_width = ChromeLayoutProvider::Get()->GetDistanceMetric(
       DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH);
 
@@ -66,30 +66,30 @@
   return size;
 }
 
-ui::ModalType PWAConfirmationView::GetModalType() const {
+ui::ModalType PWAConfirmationDialogView::GetModalType() const {
   return ui::MODAL_TYPE_CHILD;
 }
 
-base::string16 PWAConfirmationView::GetWindowTitle() const {
+base::string16 PWAConfirmationDialogView::GetWindowTitle() const {
   return l10n_util::GetStringUTF16(
       IDS_INSTALL_TO_OS_LAUNCH_SURFACE_BUBBLE_TITLE);
 }
 
-bool PWAConfirmationView::ShouldShowCloseButton() const {
+bool PWAConfirmationDialogView::ShouldShowCloseButton() const {
   return false;
 }
 
-void PWAConfirmationView::WindowClosing() {
+void PWAConfirmationDialogView::WindowClosing() {
   if (callback_)
     std::move(callback_).Run(false, web_app_info_);
 }
 
-bool PWAConfirmationView::Accept() {
+bool PWAConfirmationDialogView::Accept() {
   std::move(callback_).Run(true, web_app_info_);
   return true;
 }
 
-base::string16 PWAConfirmationView::GetDialogButtonLabel(
+base::string16 PWAConfirmationDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
                                        ? IDS_INSTALL_PWA_BUTTON_LABEL
@@ -101,10 +101,10 @@
 // Returns an ImageView containing the app icon.
 std::unique_ptr<views::ImageView> CreateIconView(
     const std::vector<WebApplicationInfo::IconInfo>& icons) {
-  gfx::ImageSkia image(
-      std::make_unique<WebAppInfoImageSource>(kPWAConfirmationViewIconSize,
-                                              icons),
-      gfx::Size(kPWAConfirmationViewIconSize, kPWAConfirmationViewIconSize));
+  gfx::ImageSkia image(std::make_unique<WebAppInfoImageSource>(
+                           kPWAConfirmationDialogViewIconSize, icons),
+                       gfx::Size(kPWAConfirmationDialogViewIconSize,
+                                 kPWAConfirmationDialogViewIconSize));
 
   auto icon_image_view = std::make_unique<views::ImageView>();
   icon_image_view->SetImage(image);
@@ -139,7 +139,7 @@
 
 }  // namespace
 
-void PWAConfirmationView::InitializeView() {
+void PWAConfirmationDialogView::InitializeView() {
   const ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
 
   // Use CONTROL insets, because the icon is non-text (see documentation for
@@ -171,7 +171,8 @@
                           const WebApplicationInfo& web_app_info,
                           AppInstallationAcceptanceCallback callback) {
   constrained_window::ShowWebModalDialogViews(
-      new PWAConfirmationView(web_app_info, std::move(callback)), web_contents);
+      new PWAConfirmationDialogView(web_app_info, std::move(callback)),
+      web_contents);
 }
 
 void SetAutoAcceptPWAInstallDialogForTesting(bool auto_accept) {
diff --git a/chrome/browser/ui/views/extensions/pwa_confirmation_view.h b/chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.h
similarity index 63%
rename from chrome/browser/ui/views/extensions/pwa_confirmation_view.h
rename to chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.h
index 1ae096f..7ee6191 100644
--- a/chrome/browser/ui/views/extensions/pwa_confirmation_view.h
+++ b/chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.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 CHROME_BROWSER_UI_VIEWS_EXTENSIONS_PWA_CONFIRMATION_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_PWA_CONFIRMATION_VIEW_H_
+#ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_PWA_CONFIRMATION_DIALOG_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_PWA_CONFIRMATION_DIALOG_VIEW_H_
 
 #include <vector>
 
@@ -13,15 +13,15 @@
 #include "chrome/common/web_application_info.h"
 #include "ui/views/window/dialog_delegate.h"
 
-// PWAConfirmationView provides a dialog for accepting or rejecting the
+// PWAConfirmationDialogView provides a dialog for accepting or rejecting the
 // installation of a PWA (Progressive Web App).
-class PWAConfirmationView : public views::DialogDelegateView {
+class PWAConfirmationDialogView : public views::DialogDelegateView {
  public:
-  // Constructs a PWAConfirmationView. |web_app_info| contains information
+  // Constructs a PWAConfirmationDialogView. |web_app_info| contains information
   // about a web app that has passed the PWA check.
-  PWAConfirmationView(const WebApplicationInfo& web_app_info,
-                      chrome::AppInstallationAcceptanceCallback callback);
-  ~PWAConfirmationView() override;
+  PWAConfirmationDialogView(const WebApplicationInfo& web_app_info,
+                            chrome::AppInstallationAcceptanceCallback callback);
+  ~PWAConfirmationDialogView() override;
 
  private:
   // views::WidgetDelegate:
@@ -46,7 +46,7 @@
   // The callback to be invoked when the dialog is completed.
   chrome::AppInstallationAcceptanceCallback callback_;
 
-  DISALLOW_COPY_AND_ASSIGN(PWAConfirmationView);
+  DISALLOW_COPY_AND_ASSIGN(PWAConfirmationDialogView);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_PWA_CONFIRMATION_VIEW_H_
+#endif  // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_PWA_CONFIRMATION_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/extensions/pwa_confirmation_view_browsertest.cc b/chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view_browsertest.cc
similarity index 80%
rename from chrome/browser/ui/views/extensions/pwa_confirmation_view_browsertest.cc
rename to chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view_browsertest.cc
index d971f78..e2c881c1 100644
--- a/chrome/browser/ui/views/extensions/pwa_confirmation_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view_browsertest.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
-#include "chrome/browser/ui/views/extensions/pwa_confirmation_view.h"
+#include "chrome/browser/ui/views/extensions/pwa_confirmation_dialog_view.h"
 #include "chrome/common/web_application_info.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,9 +16,9 @@
 namespace {
 
 // Helper class to display the PWAConfirmationView dialog for testing.
-class PWAConfirmationViewTest : public DialogBrowserTest {
+class PWAConfirmationDialogViewTest : public DialogBrowserTest {
  public:
-  PWAConfirmationViewTest() {}
+  PWAConfirmationDialogViewTest() {}
 
   void ShowUi(const std::string& name) override {
     constexpr int kIconSize = 48;
@@ -47,30 +47,30 @@
       web_app_info.app_url = GURL("https://דוגמא.דוגמא.דוגמא.אחד.example.com");
     }
     constrained_window::ShowWebModalDialogViews(
-        new PWAConfirmationView(web_app_info,
-                                chrome::AppInstallationAcceptanceCallback()),
+        new PWAConfirmationDialogView(
+            web_app_info, chrome::AppInstallationAcceptanceCallback()),
         browser()->tab_strip_model()->GetActiveWebContents());
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(PWAConfirmationViewTest);
+  DISALLOW_COPY_AND_ASSIGN(PWAConfirmationDialogViewTest);
 };
 
 // Launches an installation confirmation dialog for a PWA with a short name and
 // origin.
-IN_PROC_BROWSER_TEST_F(PWAConfirmationViewTest, InvokeUi_short_text) {
+IN_PROC_BROWSER_TEST_F(PWAConfirmationDialogViewTest, InvokeUi_short_text) {
   ShowAndVerifyUi();
 }
 
 // Launches an installation confirmation dialog for a PWA with name and origin
 // long enough to be elided.
-IN_PROC_BROWSER_TEST_F(PWAConfirmationViewTest, InvokeUi_long_text) {
+IN_PROC_BROWSER_TEST_F(PWAConfirmationDialogViewTest, InvokeUi_long_text) {
   ShowAndVerifyUi();
 }
 
 // Launches an installation confirmation dialog for a PWA with an RTL subdomain
 // which is long enough to be elided.
-IN_PROC_BROWSER_TEST_F(PWAConfirmationViewTest, InvokeUi_rtl) {
+IN_PROC_BROWSER_TEST_F(PWAConfirmationDialogViewTest, InvokeUi_rtl) {
   ShowAndVerifyUi();
 }
 
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index e6e71d47..b227680 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -26,19 +26,20 @@
 
 // static
 void ExternalProtocolHandler::RunExternalProtocolDialog(
-    const GURL& url, int render_process_host_id, int routing_id,
-    ui::PageTransition page_transition, bool has_user_gesture) {
+    const GURL& url,
+    WebContents* web_contents,
+    ui::PageTransition page_transition,
+    bool has_user_gesture) {
+  DCHECK(web_contents);
   std::unique_ptr<ExternalProtocolDialogDelegate> delegate(
-      new ExternalProtocolDialogDelegate(url, render_process_host_id,
-                                         routing_id));
+      new ExternalProtocolDialogDelegate(url, web_contents));
   if (delegate->program_name().empty()) {
     // ShellExecute won't do anything. Don't bother warning the user.
     return;
   }
 
   // Windowing system takes ownership.
-  new ExternalProtocolDialog(std::move(delegate), render_process_host_id,
-                             routing_id);
+  new ExternalProtocolDialog(std::move(delegate), web_contents);
 }
 
 ExternalProtocolDialog::~ExternalProtocolDialog() {}
@@ -96,12 +97,8 @@
 
 ExternalProtocolDialog::ExternalProtocolDialog(
     std::unique_ptr<const ProtocolDialogDelegate> delegate,
-    int render_process_host_id,
-    int routing_id)
-    : delegate_(std::move(delegate)),
-      render_process_host_id_(render_process_host_id),
-      routing_id_(routing_id),
-      creation_time_(base::TimeTicks::Now()) {
+    WebContents* web_contents)
+    : delegate_(std::move(delegate)), creation_time_(base::TimeTicks::Now()) {
   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
   set_margins(
       provider->GetDialogInsetsForContentType(views::TEXT, views::TEXT));
@@ -113,11 +110,6 @@
       new views::Checkbox(delegate_->GetCheckboxText());
   AddChildView(remember_decision_checkbox_);
 
-  WebContents* web_contents = tab_util::GetWebContentsByID(
-      render_process_host_id_, routing_id_);
-  // Only launch the dialog if there is a web contents associated with the
-  // request.
-  if (web_contents)
-    constrained_window::ShowWebModalDialogViews(this, web_contents);
+  constrained_window::ShowWebModalDialogViews(this, web_contents);
   chrome::RecordDialogCreation(chrome::DialogIdentifier::EXTERNAL_PROTOCOL);
 }
diff --git a/chrome/browser/ui/views/external_protocol_dialog.h b/chrome/browser/ui/views/external_protocol_dialog.h
index 7eba7230..31b74cc3 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.h
+++ b/chrome/browser/ui/views/external_protocol_dialog.h
@@ -12,6 +12,10 @@
 
 class ProtocolDialogDelegate;
 
+namespace content {
+class WebContents;
+}
+
 namespace test {
 class ExternalProtocolDialogTestApi;
 }
@@ -24,8 +28,7 @@
  public:
   // Show by calling ExternalProtocolHandler::RunExternalProtocolDialog().
   ExternalProtocolDialog(std::unique_ptr<const ProtocolDialogDelegate> delegate,
-                         int render_process_host_id,
-                         int routing_id);
+                         content::WebContents* web_contents);
 
   ~ExternalProtocolDialog() override;
 
@@ -46,10 +49,6 @@
 
   views::Checkbox* remember_decision_checkbox_;
 
-  // IDs of the associated WebContents.
-  int render_process_host_id_;
-  int routing_id_;
-
   // The time at which this dialog was created.
   base::TimeTicks creation_time_;
 
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
index 7de8132f..788864c 100644
--- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -46,12 +46,11 @@
     : public ExternalProtocolDialogDelegate {
  public:
   TestExternalProtocolDialogDelegate(const GURL& url,
-                                     int render_process_host_id,
-                                     int routing_id,
+                                     content::WebContents* web_contents,
                                      bool* called,
                                      bool* accept,
                                      bool* remember)
-      : ExternalProtocolDialogDelegate(url, render_process_host_id, routing_id),
+      : ExternalProtocolDialogDelegate(url, web_contents),
         called_(called),
         accept_(accept),
         remember_(remember) {}
@@ -88,15 +87,11 @@
   void ShowUi(const std::string& name) override {
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
-    int render_view_process_id =
-        web_contents->GetRenderViewHost()->GetProcess()->GetID();
-    int render_view_routing_id =
-        web_contents->GetRenderViewHost()->GetRoutingID();
     dialog_ = new ExternalProtocolDialog(
         std::make_unique<TestExternalProtocolDialogDelegate>(
-            GURL("telnet://12345"), render_view_process_id,
-            render_view_routing_id, &called_, &accept_, &remember_),
-        render_view_process_id, render_view_routing_id);
+            GURL("telnet://12345"), web_contents, &called_, &accept_,
+            &remember_),
+        web_contents);
   }
 
   void SetChecked(bool checked) {
@@ -116,8 +111,7 @@
   }
   void BlockRequest() override {}
   void RunExternalProtocolDialog(const GURL& url,
-                                 int render_process_host_id,
-                                 int routing_id,
+                                 content::WebContents* web_contents,
                                  ui::PageTransition page_transition,
                                  bool has_user_gesture) override {}
   void LaunchUrlWithoutSecurityCheck(
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
index 0bfa486..55b9f705 100644
--- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
+++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -134,8 +134,8 @@
         device::AuthenticatorGetAssertionResponse response(
             std::move(auth_data), {10, 11, 12, 13} /* signature */);
         device::PublicKeyCredentialUserEntity user({1, 2, 3, 4});
-        user.SetUserName(info.first);
-        user.SetDisplayName(info.second);
+        user.name = info.first;
+        user.display_name = info.second;
         response.SetUserEntity(std::move(user));
         responses.emplace_back(std::move(response));
       }
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index a8ccee5..49e85ff 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -1063,9 +1063,9 @@
   const auto user = dialog_model()->responses()[row].user_entity();
 
   if (column_id == IDS_WEBAUTHN_ACCOUNT_COLUMN) {
-    return base::UTF8ToUTF16(user->user_name().value_or(""));
+    return base::UTF8ToUTF16(user->name.value_or(""));
   } else {
-    return base::UTF8ToUTF16(user->user_display_name().value_or(""));
+    return base::UTF8ToUTF16(user->display_name.value_or(""));
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index e8f80be..73524ae 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -487,6 +487,10 @@
 
   params.SetString("webviewPartitionName", partition_name);
 
+  params.SetBoolean(
+      "extractSamlPasswordAttributes",
+      base::FeatureList::IsEnabled(features::kInSessionPasswordChange));
+
   frame_state_ = FRAME_STATE_LOADING;
   CallJS("login.GaiaSigninScreen.loadAuthExtension", params);
 }
@@ -616,6 +620,11 @@
               &GaiaScreenHandler::HandleUpdateSigninUIState);
   AddCallback("showGuestInOobe", &GaiaScreenHandler::HandleShowGuestInOobe);
 
+  if (base::FeatureList::IsEnabled(features::kInSessionPasswordChange)) {
+     AddCallback("updatePasswordAttributes",
+                 &GaiaScreenHandler::HandleUpdatePasswordAttributes);
+  }
+
   // Allow UMA metrics collection from JS.
   web_ui()->AddMessageHandler(std::make_unique<MetricsHandler>());
 }
@@ -940,6 +949,24 @@
   }
 }
 
+void GaiaScreenHandler::HandleUpdatePasswordAttributes(
+    const std::string& passwordModifiedTimestamp,
+    const std::string& passwordExpirationTimestamp,
+    const std::string& passwordChangeUrl) {
+  CHECK(base::FeatureList::IsEnabled(features::kInSessionPasswordChange));
+  // TODO(olsen): Store this information in the user's session, use it to show a
+  // notification when the user's password is expired / is soon to expire.
+  if (passwordModifiedTimestamp.empty() &&
+      passwordExpirationTimestamp.empty() && passwordChangeUrl.empty()) {
+    VLOG(4) << "No password attributes extracted from SAML response";
+  } else {
+    VLOG(4) << "Extracted password attributes from SAML response: {";
+    VLOG(4) << "passwordModifiedTimestamp: " << passwordModifiedTimestamp;
+    VLOG(4) << "passwordExpirationTimestamp: " << passwordExpirationTimestamp;
+    VLOG(4) << "passwordChangeUrl: " << passwordChangeUrl << " }";
+  }
+}
+
 void GaiaScreenHandler::HandleShowGuestInOobe(bool show) {
   LoginScreenClient::Get()->login_screen()->SetShowGuestButtonInOobe(show);
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index 6c58755..a4757c2 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -157,6 +157,13 @@
                                        const std::string& gaia_id);
   void HandleUpdateSigninUIState(int state);
 
+  // Allows for a password expiry notification to be shown using information
+  // extracted from the SAML response during SAML auth flow.
+  void HandleUpdatePasswordAttributes(
+      const std::string& passwordModifiedTimestamp,
+      const std::string& passwordExpirationTimestamp,
+      const std::string& passwordChangeUrl);
+
   // Allows WebUI to control the login shelf's guest button visibility during
   // OOBE.
   void HandleShowGuestInOobe(bool show);
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index 7e2388b..7b6e308 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -394,22 +394,16 @@
   if (!profile_->GetPrefs()->GetBoolean(prefs::kUserNativePrintersAllowed)) {
     PRINTER_LOG(DEBUG) << "HandleUpdateCupsPrinter() called when "
                           "kUserNativePrintersAllowed is set to false";
-    // Used to log UMA metrics.
-    OnAddedOrEditedPrinterCommon(
-        printer, PrinterSetupResult::kNativePrintersNotAllowed, false);
+    OnAddedOrEditedPrinterCommon(printer,
+                                 PrinterSetupResult::kNativePrintersNotAllowed,
+                                 false /* is_automatic */);
     // Used to fire the web UI listener.
     OnAddOrEditPrinterError(PrinterSetupResult::kNativePrintersNotAllowed);
     return;
   }
 
-  PRINTER_LOG(USER) << "Comitting printer update";
-  printers_manager_->UpdateConfiguredPrinter(printer);
-
-  // TODO(xdai): Replace "on-add-or-edit-cups-printer" callback with Promise
-  // resolve function.
-  FireWebUIListener("on-add-or-edit-cups-printer",
-                    base::Value(PrinterSetupResult::kEditSuccess),
-                    base::Value(printer_name));
+  OnAddedOrEditedSpecifiedPrinter(printer, true /* is_printer_edit */,
+                                  PrinterSetupResult::kEditSuccess);
 }
 
 void CupsPrintersHandler::HandleRemoveCupsPrinter(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index ba0f3da..830d0a854 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -2626,10 +2626,6 @@
       base::FeatureList::IsEnabled(media::kAutoplayWhitelistSettings));
 
   html_source->AddBoolean(
-      "enableClipboardContentSetting",
-      base::FeatureList::IsEnabled(features::kClipboardContentSetting));
-
-  html_source->AddBoolean(
       "enableSensorsContentSetting",
       base::FeatureList::IsEnabled(features::kSensorContentSetting));
 
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index b510875..8d82d85 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -178,11 +178,6 @@
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-// Enables a site-wide permission in the UI which controls access to the
-// asynchronous Clipboard web API.
-const base::Feature kClipboardContentSetting{"ClipboardContentSetting",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 #if defined(OS_CHROMEOS)
 // Enable project Crostini, Linux VMs on Chrome OS.
 const base::Feature kCrostini{"Crostini", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index cc3ba13..67f4fb8 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -100,9 +100,6 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kClickToOpenPDFPlaceholder;
 
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::Feature kClipboardContentSetting;
-
 #if defined(OS_MACOSX)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kContentFullscreen;
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
index 4aca6669..82d76b1 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -377,9 +377,16 @@
     ui::AXNode* focus = ancestor->tree()->GetFromId(focus_id);
     if (!focus)
       return false;
+
+    const ui::AXTreeID& child_tree_id =
+        child_of_ancestor->tree()->data().tree_id;
+
+    // Either the focused node points to the child tree, or the ancestor tree
+    // points to the child tree via the focused tree id. Exit early if both are
+    // not true.
     if (ui::AXTreeID::FromString(focus->GetStringAttribute(
-            ax::mojom::StringAttribute::kChildTreeId)) !=
-        child_of_ancestor->tree()->data().tree_id)
+            ax::mojom::StringAttribute::kChildTreeId)) != child_tree_id &&
+        ancestor->tree()->data().focused_tree_id != child_tree_id)
       return false;
 
     if (ancestor->IsDesktopTree())
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0b89e949..81cdc9ea 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1634,7 +1634,7 @@
         "../browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc",
         "../browser/ui/views/extensions/extensions_menu_view_browsertest.cc",
         "../browser/ui/views/extensions/media_galleries_dialog_views_browsertest.cc",
-        "../browser/ui/views/extensions/pwa_confirmation_view_browsertest.cc",
+        "../browser/ui/views/extensions/pwa_confirmation_dialog_view_browsertest.cc",
         "../browser/ui/views/external_protocol_dialog_browsertest.cc",
         "../browser/ui/views/folder_upload_confirmation_view_browsertest.cc",
         "../browser/ui/views/frame/browser_frame_browsertest.cc",
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index c479f624..e5904d70 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -4523,6 +4523,17 @@
     ]
   },
 
+  "DeviceUsbPowerShareEnabled": {
+    "os": ["chromeos"],
+    "test_policy": { "DeviceUsbPowerShareEnabled": true },
+    "pref_mappings": [
+      {
+        "pref": "ash.power.usb_power_share_enabled",
+        "local_state": true
+      }
+    ]
+  },
+
   "----- Chrome Frame policies -------------------------------------------": {},
 
   "ChromeFrameRendererSettings": {
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js
index 7e05141..79ced1fe 100644
--- a/chrome/test/data/webui/settings/site_details_tests.js
+++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -126,9 +126,6 @@
     // flag string.
     const optionalSiteDetailsContentSettingsTypes =
         /** @type {!settings.ContentSettingsType : string} */ ({});
-    optionalSiteDetailsContentSettingsTypes[settings.ContentSettingsTypes
-                                                .CLIPBOARD] =
-        'enableClipboardContentSetting';
     optionalSiteDetailsContentSettingsTypes[settings.ContentSettingsTypes.ADS] =
         'enableSafeBrowsingSubresourceFilter';
 
@@ -296,7 +293,6 @@
     browserProxy.setPrefs(prefs);
     // Make sure all the possible content settings are shown for this test.
     loadTimeData.overrideValues({enableSafeBrowsingSubresourceFilter: true});
-    loadTimeData.overrideValues({enableClipboardContentSetting: true});
     loadTimeData.overrideValues({enableSensorsContentSetting: true});
     loadTimeData.overrideValues({enablePaymentHandlerContentSetting: true});
     testElement = createSiteDetails('https://foo.com:443');
diff --git a/chrome/utility/importer/nss_decryptor.cc b/chrome/utility/importer/nss_decryptor.cc
index ae3d785..9842ee2 100644
--- a/chrome/utility/importer/nss_decryptor.cc
+++ b/chrome/utility/importer/nss_decryptor.cc
@@ -295,42 +295,51 @@
     std::vector<autofill::PasswordForm>* forms) {
   std::string json_content;
   base::ReadFileToString(json_file, &json_content);
-  std::unique_ptr<base::Value> parsed_json(
-      base::JSONReader::ReadDeprecated(json_content));
-  const base::DictionaryValue* password_dict;
-  const base::ListValue* password_list;
-  const base::ListValue* blacklist_domains;
-  if (!parsed_json || !parsed_json->GetAsDictionary(&password_dict))
+  base::Optional<base::Value> parsed_json =
+      base::JSONReader::Read(json_content);
+  if (!parsed_json || !parsed_json->is_dict())
     return false;
 
-  if (password_dict->GetList("disabledHosts", &blacklist_domains)) {
-    for (const auto& value : *blacklist_domains) {
-      std::string disabled_host;
-      if (!value.GetAsString(&disabled_host))
+  const base::Value* blacklist_domains =
+      parsed_json->FindListKey("disabledHosts");
+  if (blacklist_domains) {
+    for (const auto& value : blacklist_domains->GetList()) {
+      if (!value.is_string())
         continue;
-      forms->push_back(CreateBlacklistPasswordForm(disabled_host));
+      forms->push_back(CreateBlacklistPasswordForm(value.GetString()));
     }
   }
 
-  if (password_dict->GetList("logins", &password_list)) {
-    for (const auto& value : *password_list) {
-      const base::DictionaryValue* password_detail;
-      if (!value.GetAsDictionary(&password_detail))
+  const base::Value* password_list = parsed_json->FindListKey("logins");
+  if (password_list) {
+    for (const auto& value : password_list->GetList()) {
+      if (!value.is_dict())
         continue;
 
       FirefoxRawPasswordInfo raw_password_info;
-      password_detail->GetString("hostname", &raw_password_info.host);
-      password_detail->GetString("usernameField",
-                                 &raw_password_info.username_element);
-      password_detail->GetString("passwordField",
-                                 &raw_password_info.password_element);
-      password_detail->GetString("encryptedUsername",
-                                 &raw_password_info.encrypted_username);
-      password_detail->GetString("encryptedPassword",
-                                 &raw_password_info.encrypted_password);
-      password_detail->GetString("formSubmitURL",
-                                 &raw_password_info.form_action);
-      password_detail->GetString("httpRealm", &raw_password_info.realm);
+
+      if (const std::string* hostname = value.FindStringKey("hostname"))
+        raw_password_info.host = *hostname;
+
+      if (const std::string* username = value.FindStringKey("usernameField"))
+        raw_password_info.username_element = base::UTF8ToUTF16(*username);
+
+      if (const std::string* password = value.FindStringKey("passwordField"))
+        raw_password_info.password_element = base::UTF8ToUTF16(*password);
+
+      if (const std::string* username =
+              value.FindStringKey("encryptedUsername"))
+        raw_password_info.encrypted_username = *username;
+
+      if (const std::string* password =
+              value.FindStringKey("encryptedPassword"))
+        raw_password_info.encrypted_password = *password;
+
+      if (const std::string* submit_url = value.FindStringKey("formSubmitURL"))
+        raw_password_info.form_action = *submit_url;
+
+      if (const std::string* realm = value.FindStringKey("httpRealm"))
+        raw_password_info.realm = *realm;
 
       autofill::PasswordForm form;
       if (CreatePasswordFormFromRawInfo(raw_password_info, &form))
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni
index c6ac9e5a..f82aea2 100644
--- a/chromecast/chromecast.gni
+++ b/chromecast/chromecast.gni
@@ -116,6 +116,9 @@
   # within cast_shell. Enable for desktop builds to ensure that Chromium CQ
   # builds the external Mojo broker code.
   enable_external_mojo_services = is_cast_desktop_build
+
+  # Recording happens at this sample rate. Must be 16000, 48000 or 96000 Hz.
+  audio_input_sample_rate = 16000
 }
 
 declare_args() {
diff --git a/chromecast/media/audio/BUILD.gn b/chromecast/media/audio/BUILD.gn
index efa3ccc..2e000eb 100644
--- a/chromecast/media/audio/BUILD.gn
+++ b/chromecast/media/audio/BUILD.gn
@@ -80,4 +80,9 @@
     "MAXIMUM_OUTPUT_BUFFER_SIZE_IN_FRAMES=$maximum_output_buffer_size_in_frames",
     "DEFAULT_OUTPUT_BUFFER_SIZE_IN_FRAMES=$default_output_buffer_size_in_frames",
   ]
+
+  if (use_alsa) {
+    # Currently, this flag will only be used in cast_audio_manager_alsa.cc
+    flags += [ "AUDIO_INPUT_SAMPLE_RATE=$audio_input_sample_rate" ]
+  }
 }
diff --git a/chromecast/media/audio/cast_audio_manager_alsa.cc b/chromecast/media/audio/cast_audio_manager_alsa.cc
index bc4af575..6112900 100644
--- a/chromecast/media/audio/cast_audio_manager_alsa.cc
+++ b/chromecast/media/audio/cast_audio_manager_alsa.cc
@@ -9,6 +9,7 @@
 
 #include "base/memory/free_deleter.h"
 #include "base/stl_util.h"
+#include "chromecast/media/audio/audio_buildflags.h"
 #include "chromecast/media/cma/backend/cma_backend_factory.h"
 #include "media/audio/alsa/alsa_input.h"
 #include "media/audio/alsa/alsa_wrapper.h"
@@ -18,7 +19,7 @@
 
 namespace {
 // TODO(alokp): Query the preferred value from media backend.
-const int kDefaultSampleRate = 48000;
+const int kDefaultSampleRate = BUILDFLAG(AUDIO_INPUT_SAMPLE_RATE);
 
 // TODO(jyw): Query the preferred value from media backend.
 static const int kDefaultInputBufferSize = 1024;
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index 97177fb..336381e 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -183,6 +183,7 @@
     "//chromeos/dbus/power:test_support",
     "//chromeos/dbus/session_manager",
     "//chromeos/dbus/shill:test_support",
+    "//chromeos/tpm:test_support",
     "//components/account_id",
     "//dbus",
     "//dbus:test_support",
diff --git a/chromeos/dbus/auth_policy/BUILD.gn b/chromeos/dbus/auth_policy/BUILD.gn
index a5db8a2..ea69359 100644
--- a/chromeos/dbus/auth_policy/BUILD.gn
+++ b/chromeos/dbus/auth_policy/BUILD.gn
@@ -13,13 +13,15 @@
     ":authpolicy_proto",
     "//base",
     "//chromeos/dbus:common",
-    "//chromeos/dbus/cryptohome",
+    "//components/account_id",
+    "//dbus",
+
+    # For FakeAuthPolicyClient
     "//chromeos/dbus/cryptohome:cryptohome_proto",
     "//chromeos/dbus/session_manager",
-    "//components/account_id",
+    "//chromeos/tpm",
     "//components/policy:cloud_policy_proto_generated_compile",
     "//components/policy/proto",
-    "//dbus",
   ]
 
   sources = [
diff --git a/chromeos/dbus/auth_policy/DEPS b/chromeos/dbus/auth_policy/DEPS
new file mode 100644
index 0000000..adea6980
--- /dev/null
+++ b/chromeos/dbus/auth_policy/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "fake_auth_policy_client.*\.cc": [
+    "+chromeos/tpm",
+  ],
+}
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client.cc b/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
index 5fb2a75..606495f 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
@@ -14,10 +14,9 @@
 #include "base/task/post_task.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/cryptohome/tpm_util.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
+#include "chromeos/tpm/install_attributes.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/proto/cloud_policy.pb.h"
 #include "dbus/message.h"
@@ -79,7 +78,7 @@
     const authpolicy::JoinDomainRequest& request,
     int password_fd,
     JoinCallback callback) {
-  DCHECK(!tpm_util::IsActiveDirectoryLocked());
+  DCHECK(!InstallAttributes::Get()->IsActiveDirectoryManaged());
   authpolicy::ErrorType error = authpolicy::ERROR_NONE;
   std::string machine_domain;
   if (!started_) {
@@ -120,7 +119,7 @@
     const authpolicy::AuthenticateUserRequest& request,
     int password_fd,
     AuthCallback callback) {
-  DCHECK(tpm_util::IsActiveDirectoryLocked());
+  DCHECK(InstallAttributes::Get()->IsActiveDirectoryManaged());
   authpolicy::ErrorType error = authpolicy::ERROR_NONE;
   authpolicy::ActiveDirectoryAccountInfo account_info;
   if (auth_error_ != authpolicy::ERROR_NONE) {
@@ -190,7 +189,7 @@
     return;
   }
 
-  if (!tpm_util::IsActiveDirectoryLocked()) {
+  if (!InstallAttributes::Get()->IsActiveDirectoryManaged()) {
     // Pretend that policy was fetched and cached inside authpolicyd.
     std::move(callback).Run(
         authpolicy::ERROR_DEVICE_POLICY_CACHED_BUT_NOT_SENT);
@@ -211,7 +210,7 @@
 
 void FakeAuthPolicyClient::RefreshUserPolicy(const AccountId& account_id,
                                              RefreshPolicyCallback callback) {
-  DCHECK(tpm_util::IsActiveDirectoryLocked());
+  DCHECK(InstallAttributes::Get()->IsActiveDirectoryManaged());
   if (!started_) {
     LOG(ERROR) << "authpolicyd not started";
     std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE);
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc b/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
index 534bab7a..1a39402 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
@@ -7,9 +7,8 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "chromeos/dbus/cryptohome/cryptohome_client.h"
-#include "chromeos/dbus/cryptohome/tpm_util.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
+#include "chromeos/tpm/stub_install_attributes.h"
 #include "components/account_id/account_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -37,7 +36,6 @@
 
   void SetUp() override {
     ::testing::Test::SetUp();
-    CryptohomeClient::InitializeFake();
     SessionManagerClient::InitializeFakeInMemory();
     AuthPolicyClient::InitializeFake();
     authpolicy_client()->DisableOperationDelayForTesting();
@@ -46,7 +44,6 @@
   void TearDown() override {
     AuthPolicyClient::Shutdown();
     SessionManagerClient::Shutdown();
-    CryptohomeClient::Shutdown();
   }
 
   void JoinAdDomain(const std::string& machine_name,
@@ -81,10 +78,6 @@
                                           std::move(callback));
   }
 
-  void LockDeviceActiveDirectory() {
-    EXPECT_TRUE(tpm_util::LockDeviceActiveDirectoryForTesting(std::string()));
-  }
-
   void WaitForServiceToBeAvailable() {
     authpolicy_client()->WaitForServiceToBeAvailable(base::BindOnce(
         &FakeAuthPolicyClientTest::OnWaitForServiceToBeAvailableCalled,
@@ -96,9 +89,15 @@
     service_is_available_called_num_++;
   }
 
+  void LockDevice() {
+    install_attributes_.Get()->SetActiveDirectoryManaged("example.com",
+                                                         "device_id");
+  }
+
   int service_is_available_called_num_ = 0;
 
  private:
+  ScopedStubInstallAttributes install_attributes_;
   base::MessageLoop loop_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAuthPolicyClientTest);
@@ -240,7 +239,7 @@
 // Test AuthenticateUser.
 TEST_F(FakeAuthPolicyClientTest, AuthenticateUser_ByAccountId) {
   authpolicy_client()->SetStarted(true);
-  LockDeviceActiveDirectory();
+  LockDevice();
   // Check that account_id do not change.
   AuthenticateUser(
       kCorrectUserName, kAccountId,
@@ -260,7 +259,7 @@
                      EXPECT_EQ(authpolicy::ERROR_DBUS_FAILURE, error);
                      EXPECT_TRUE(domain.empty());
                    }));
-  LockDeviceActiveDirectory();
+  LockDevice();
   AuthenticateUser(
       kCorrectUserName, std::string() /* account_id */,
       base::BindOnce([](authpolicy::ErrorType error,
@@ -291,7 +290,7 @@
       base::BindOnce([](authpolicy::ErrorType error) {
         EXPECT_EQ(authpolicy::ERROR_DEVICE_POLICY_CACHED_BUT_NOT_SENT, error);
       }));
-  LockDeviceActiveDirectory();
+  LockDevice();
   base::RunLoop loop;
   authpolicy_client()->RefreshDevicePolicy(base::BindOnce(
       [](base::OnceClosure closure, authpolicy::ErrorType error) {
@@ -305,7 +304,7 @@
 // Tests that RefreshDevicePolicy stores device policy in the session manager.
 TEST_F(FakeAuthPolicyClientTest, RefreshDevicePolicyStoresPolicy) {
   authpolicy_client()->SetStarted(true);
-  LockDeviceActiveDirectory();
+  LockDevice();
 
   {
     // Call RefreshDevicePolicy.
diff --git a/chromeos/dbus/cryptohome/tpm_util.cc b/chromeos/dbus/cryptohome/tpm_util.cc
index 6cc4afd..283cc89 100644
--- a/chromeos/dbus/cryptohome/tpm_util.cc
+++ b/chromeos/dbus/cryptohome/tpm_util.cc
@@ -14,13 +14,6 @@
 namespace chromeos {
 namespace tpm_util {
 
-namespace {
-
-constexpr char kAttrMode[] = "enterprise.mode";
-constexpr char kDeviceModeEnterpriseAD[] = "enterprise_ad";
-
-}  // namespace
-
 bool TpmIsEnabled() {
   bool result = false;
   CryptohomeClient::Get()->CallTpmIsEnabledAndBlock(&result);
@@ -87,18 +80,5 @@
   return result;
 }
 
-bool IsActiveDirectoryLocked() {
-  std::string mode;
-  return InstallAttributesGet(kAttrMode, &mode) &&
-         mode == kDeviceModeEnterpriseAD;
-}
-
-bool LockDeviceActiveDirectoryForTesting(const std::string& realm) {
-  return InstallAttributesSet("enterprise.owned", "true") &&
-         InstallAttributesSet(kAttrMode, kDeviceModeEnterpriseAD) &&
-         InstallAttributesSet("enterprise.realm", realm) &&
-         InstallAttributesFinalize();
-}
-
 }  // namespace tpm_util
 }  // namespace chromeos
diff --git a/chromeos/dbus/cryptohome/tpm_util.h b/chromeos/dbus/cryptohome/tpm_util.h
index 69e3ba5..e2d0eaf4 100644
--- a/chromeos/dbus/cryptohome/tpm_util.h
+++ b/chromeos/dbus/cryptohome/tpm_util.h
@@ -43,15 +43,6 @@
 COMPONENT_EXPORT(CRYPTOHOME_CLIENT) bool InstallAttributesIsInvalid();
 COMPONENT_EXPORT(CRYPTOHOME_CLIENT) bool InstallAttributesIsFirstInstall();
 
-// Blocking call to InstallAttributesGet. Checks if the device is locked for
-// Active Directory management.
-COMPONENT_EXPORT(CRYPTOHOME_CLIENT) bool IsActiveDirectoryLocked();
-
-// Blocking calls to InstallAttributesSet. Sets install attributes for an Active
-// Directory managed device and persists them on disk.
-COMPONENT_EXPORT(CRYPTOHOME_CLIENT)
-bool LockDeviceActiveDirectoryForTesting(const std::string& realm);
-
 }  // namespace tpm_util
 }  // namespace chromeos
 
diff --git a/chromeos/policy/OWNERS b/chromeos/policy/OWNERS
index 01fea61..846e01e 100644
--- a/chromeos/policy/OWNERS
+++ b/chromeos/policy/OWNERS
@@ -1,4 +1,5 @@
 set noparent
+antrim@chromium.org
 atwilson@chromium.org
 bartfab@chromium.org
 emaxx@chromium.org
diff --git a/chromeos/settings/cros_settings_provider.cc b/chromeos/settings/cros_settings_provider.cc
index 7b6761d..15fe882 100644
--- a/chromeos/settings/cros_settings_provider.cc
+++ b/chromeos/settings/cros_settings_provider.cc
@@ -19,20 +19,6 @@
 
 CrosSettingsProvider::~CrosSettingsProvider() = default;
 
-void CrosSettingsProvider::Set(const std::string& path,
-                               const base::Value& value) {
-  // We don't allow changing any of the cros settings without prefix
-  // "cros.session." in the guest mode.
-  // It should not reach here from UI in the guest mode, but just in case.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kGuestSession) &&
-      !base::StartsWith(path, "cros.session.", base::CompareCase::SENSITIVE)) {
-    LOG(ERROR) << "Ignoring the guest request to change: " << path;
-    return;
-  }
-  DoSet(path, value);
-}
-
 void CrosSettingsProvider::NotifyObservers(const std::string& path) {
   if (!notify_cb_.is_null())
     notify_cb_.Run(path);
diff --git a/chromeos/settings/cros_settings_provider.h b/chromeos/settings/cros_settings_provider.h
index 3f92367..fbe4222b 100644
--- a/chromeos/settings/cros_settings_provider.h
+++ b/chromeos/settings/cros_settings_provider.h
@@ -41,9 +41,6 @@
   explicit CrosSettingsProvider(const NotifyObserversCallback& notify_cb);
   virtual ~CrosSettingsProvider();
 
-  // Sets |in_value| to given |path| in cros settings.
-  void Set(const std::string& path, const base::Value& in_value);
-
   // Gets settings value of given |path| to |out_value|.
   virtual const base::Value* Get(const std::string& path) const = 0;
 
@@ -66,10 +63,6 @@
   void NotifyObservers(const std::string& path);
 
  private:
-  // Does the real job for Set().
-  virtual void DoSet(const std::string& path,
-                     const base::Value& in_value) = 0;
-
   // Callback used to notify about setting changes.
   NotifyObserversCallback notify_cb_;
 };
diff --git a/chromeos/settings/system_settings_provider.cc b/chromeos/settings/system_settings_provider.cc
index 01aaffae..0ca9e45 100644
--- a/chromeos/settings/system_settings_provider.cc
+++ b/chromeos/settings/system_settings_provider.cc
@@ -58,33 +58,6 @@
       new base::Value(FineGrainedTimeZoneDetectionEnabled()));
 }
 
-void SystemSettingsProvider::DoSet(const std::string& path,
-                                   const base::Value& in_value) {
-  // TODO(olsen): crbug.com/433840 - separate read path and write path.
-  // The write path which goes through CrosSettings and SystemSettingsProvider,
-  // should more simply go straight through TimezoneUtil.
-
-  // Guest, public, or child accounts cannot change the time zone.
-  // TODO(olsen): This logic is duplicated in TimezoneUtil::CanSetSystemTimezone
-  // and can be removed once the write path goes through there.
-  if (!LoginState::Get()->IsUserLoggedIn() ||
-      LoginState::Get()->IsGuestSessionUser() ||
-      LoginState::Get()->IsPublicSessionUser() ||
-      LoginState::Get()->IsChildUser()) {
-    return;
-  }
-
-  if (path == kSystemTimezone) {
-    base::string16 timezone_id;
-    if (!in_value.GetAsString(&timezone_id))
-      return;
-    // This will call TimezoneChanged.
-    system::TimezoneSettings::GetInstance()->SetTimezoneFromID(timezone_id);
-  }
-  // kPerUserTimezoneEnabled is read-only.
-  // kFineGrainedTimeZoneResolveEnabled is read-only.
-}
-
 const base::Value* SystemSettingsProvider::Get(const std::string& path) const {
   if (path == kSystemTimezone)
     return timezone_value_.get();
diff --git a/chromeos/settings/system_settings_provider.h b/chromeos/settings/system_settings_provider.h
index 1c64f24..97b8fe7 100644
--- a/chromeos/settings/system_settings_provider.h
+++ b/chromeos/settings/system_settings_provider.h
@@ -41,9 +41,6 @@
   // Code common to both constructors.
   void Init();
 
-  // CrosSettingsProvider implementation.
-  void DoSet(const std::string& path, const base::Value& in_value) override;
-
   std::unique_ptr<base::Value> timezone_value_;
   std::unique_ptr<base::Value> per_user_timezone_enabled_value_;
   std::unique_ptr<base::Value> fine_grained_time_zone_enabled_value_;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 08b1fd9..7bdeabed7 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -126,8 +126,6 @@
     "form_types.h",
     "label_formatter.cc",
     "label_formatter.h",
-    "label_formatter_test_utils.cc",
-    "label_formatter_test_utils.h",
     "label_formatter_utils.cc",
     "label_formatter_utils.h",
     "metrics/address_form_event_logger.cc",
@@ -489,13 +487,10 @@
   testonly = true
   sources = [
     "address_combobox_model_unittest.cc",
-    "address_email_form_label_formatter_unittest.cc",
     "address_field_unittest.cc",
-    "address_form_label_formatter_unittest.cc",
     "address_i18n_unittest.cc",
     "address_normalization_manager_unittest.cc",
     "address_normalizer_impl_unittest.cc",
-    "address_phone_form_label_formatter_unittest.cc",
     "address_rewriter_unittest.cc",
     "address_unittest.cc",
     "autocomplete_history_manager_unittest.cc",
@@ -517,7 +512,6 @@
     "autofill_profile_validator_unittest.cc",
     "autofill_subject_unittest.cc",
     "autofill_type_unittest.cc",
-    "contact_form_label_formatter_unittest.cc",
     "contact_info_unittest.cc",
     "country_combobox_model_unittest.cc",
     "country_names_unittest.cc",
@@ -528,8 +522,6 @@
     "form_data_importer_unittest.cc",
     "form_field_unittest.cc",
     "form_structure_unittest.cc",
-    "label_formatter_unittest.cc",
-    "label_formatter_utils_unittest.cc",
     "name_field_unittest.cc",
     "payments/autofill_wallet_data_type_controller_unittest.cc",
     "payments/credit_card_save_manager_unittest.cc",
@@ -581,6 +573,17 @@
     ]
   }
 
+  if (!is_ios && !is_android) {
+    sources += [
+      "address_email_form_label_formatter_unittest.cc",
+      "address_form_label_formatter_unittest.cc",
+      "address_phone_form_label_formatter_unittest.cc",
+      "contact_form_label_formatter_unittest.cc",
+      "label_formatter_unittest.cc",
+      "label_formatter_utils_unittest.cc",
+    ]
+  }
+
   defines = [ "CHROME_VERSION_MAJOR=" + chrome_version_major ]
 
   deps = [
diff --git a/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc b/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc
index 16e0dbe..504118f7 100644
--- a/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc
+++ b/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc
@@ -14,7 +14,6 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
 #include "components/autofill/core/browser/label_formatter_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -85,20 +84,21 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{
           &profile1, &profile2, &profile3, &profile4, &profile5, &profile6}),
-      ElementsAre(
-          ConstructLabelLines(
-              base::ASCIIToUTF16("19 North Sq, Boston, MA 02113"),
-              FormatExpectedLabel("(617) 523-2338", "sarah.revere@aol.com")),
+      ElementsAre(ConstructLabelLines(
+          base::ASCIIToUTF16("19 North Sq, Boston, MA 02113"),
+          ConstructLabelLine({base::ASCIIToUTF16("(617) 523-2338"),
+                              base::ASCIIToUTF16("sarah.revere@aol.com")}),
           ConstructLabelLines(
               base::ASCIIToUTF16("151 Irving Ave, Hyannis, MA 02601"),
               base::ASCIIToUTF16("(617) 514-1600")),
           ConstructLabelLines(
               base::ASCIIToUTF16("19 North Sq, Boston, MA 02113"),
               base::ASCIIToUTF16("paul1775@gmail.com")),
-          FormatExpectedLabel("(617) 324-0000", "dina@mit.edu"),
+          ConstructLabelLine({base::ASCIIToUTF16("(617) 324-0000"),
+                              base::ASCIIToUTF16("dina@mit.edu")}),
           base::ASCIIToUTF16(
               "Old North Church, 193 Salem St, Boston, MA 02113"),
-          base::string16()));
+          base::string16())));
 }
 
 TEST(AddressContactFormLabelFormatterTest,
@@ -142,20 +142,24 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{
           &profile1, &profile2, &profile3, &profile4, &profile5, &profile6}),
-      ElementsAre(
+      ElementsAre(ConstructLabelLines(ConstructLabelLine(
+          {base::ASCIIToUTF16("Sarah Revere"),
+           base::ASCIIToUTF16("Boston, MA 02113")},
+          ConstructLabelLine({base::ASCIIToUTF16("(617) 523-2338"),
+                              base::ASCIIToUTF16("sarah.revere@aol.com")}),
           ConstructLabelLines(
-              FormatExpectedLabel("Sarah Revere", "Boston, MA 02113"),
-              FormatExpectedLabel("(617) 523-2338", "sarah.revere@aol.com")),
-          ConstructLabelLines(
-              FormatExpectedLabel("Jackie L Kennedy", "Hyannis, MA 02601"),
+              ConstructLabelLine({base::ASCIIToUTF16("Jackie L Kennedy"),
+                                  base::ASCIIToUTF16("Hyannis, MA 02601")}),
               base::ASCIIToUTF16("(617) 514-1600")),
           ConstructLabelLines(
-              FormatExpectedLabel("Paul Revere", "Boston, MA 02113"),
+              ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"),
+                                  base::ASCIIToUTF16("Boston, MA 02113")}),
               base::ASCIIToUTF16("paul1775@gmail.com")),
           ConstructLabelLines(
               base::ASCIIToUTF16("Dina Katabi"),
-              FormatExpectedLabel("(617) 324-0000", "dina@mit.edu")),
-          base::ASCIIToUTF16("Boston, MA 02113"), base::string16()));
+              ConstructLabelLine({base::ASCIIToUTF16("(617) 324-0000"),
+                                  base::ASCIIToUTF16("dina@mit.edu")})),
+          base::ASCIIToUTF16("Boston, MA 02113"), base::string16()))));
 }
 
 TEST(AddressContactFormLabelFormatterTest,
@@ -201,16 +205,22 @@
           &profile1, &profile2, &profile3, &profile4, &profile5, &profile6}),
       ElementsAre(
           ConstructLabelLines(
-              FormatExpectedLabel("Sarah Revere", "19 North Sq"),
-              FormatExpectedLabel("(617) 523-2338", "sarah.revere@aol.com")),
+              ConstructLabelLine(
+                  {base::ASCIIToUTF16("Sarah Revere", "19 North Sq")}),
+              ConstructLabelLine({base::ASCIIToUTF16("(617) 523-2338"),
+                                  base::ASCIIToUTF16("sarah.revere@aol.com")})),
           ConstructLabelLines(
-              FormatExpectedLabel("Jackie L Kennedy", "151 Irving Ave"),
+              ConstructLabelLine({base::ASCIIToUTF16("Jackie L Kennedy"),
+                                  base::ASCIIToUTF16("151 Irving Ave")}),
               base::ASCIIToUTF16("(617) 514-1600")),
-          ConstructLabelLines(FormatExpectedLabel("Paul Revere", "19 North Sq"),
-                              base::ASCIIToUTF16("paul1775@gmail.com")),
+          ConstructLabelLines(
+              ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"),
+                                  base::ASCIIToUTF16("19 North Sq")}),
+              base::ASCIIToUTF16("paul1775@gmail.com")),
           ConstructLabelLines(
               base::ASCIIToUTF16("Dina Katabi"),
-              FormatExpectedLabel("(617) 324-0000", "dina@mit.edu")),
+              ConstructLabelLine({base::ASCIIToUTF16("(617) 324-0000"),
+                                  base::ASCIIToUTF16("dina@mit.edu")})),
           base::ASCIIToUTF16("Old North Church, 193 Salem St"),
           base::string16()));
 }
@@ -256,19 +266,23 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{
           &profile1, &profile2, &profile3, &profile4, &profile5, &profile6}),
-      ElementsAre(ConstructLabelLines(
-                      FormatExpectedLabel("Sarah Revere", "(617) 523-2338"),
-                      base::ASCIIToUTF16("19 North Sq, Boston, MA 02113")),
-                  ConstructLabelLines(
-                      FormatExpectedLabel("Jackie L Kennedy", "(617) 514-1600"),
-                      base::ASCIIToUTF16("151 Irving Ave, Hyannis, MA 02601")),
-                  ConstructLabelLines(
-                      base::ASCIIToUTF16("Paul Revere"),
-                      base::ASCIIToUTF16("19 North Sq, Boston, MA 02113")),
-                  FormatExpectedLabel("Dina Katabi", "(617) 324-0000"),
-                  base::ASCIIToUTF16(
-                      "Old North Church, 193 Salem St, Boston, MA 02113"),
-                  base::string16()));
+      ElementsAre(
+          ConstructLabelLines(
+              ConstructLabelLine({base::ASCIIToUTF16("Sarah Revere"),
+                                  base::ASCIIToUTF16("(617) 523-2338")}),
+              base::ASCIIToUTF16("19 North Sq, Boston, MA 02113")),
+          ConstructLabelLines(
+              ConstructLabelLine({base::ASCIIToUTF16("Jackie L Kennedy"),
+                                  base::ASCIIToUTF16("(617) 514-1600")}),
+              base::ASCIIToUTF16("151 Irving Ave, Hyannis, MA 02601")),
+          ConstructLabelLines(
+              base::ASCIIToUTF16("Paul Revere"),
+              base::ASCIIToUTF16("19 North Sq, Boston, MA 02113")),
+          ConstructLabelLine({base::ASCIIToUTF16("Dina Katabi"),
+                              base::ASCIIToUTF16("(617) 324-0000")}),
+          base::ASCIIToUTF16(
+              "Old North Church, 193 Salem St, Boston, MA 02113"),
+          base::string16()));
 }
 
 TEST(AddressContactFormLabelFormatterTest,
@@ -314,15 +328,18 @@
           &profile1, &profile2, &profile3, &profile4, &profile5, &profile6}),
       ElementsAre(
           ConstructLabelLines(
-              FormatExpectedLabel("Sarah Revere", "sarah.revere@aol.com"),
+              ConstructLabelLine({base::ASCIIToUTF16("Sarah Revere"),
+                                  base::ASCIIToUTF16("sarah.revere@aol.com")}),
               base::ASCIIToUTF16("19 North Sq, Boston, MA 02113")),
           ConstructLabelLines(
               base::ASCIIToUTF16("Jackie L Kennedy"),
               base::ASCIIToUTF16("151 Irving Ave, Hyannis, MA 02601")),
           ConstructLabelLines(
-              FormatExpectedLabel("Paul Revere", "paul1775@gmail.com"),
+              ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"),
+                                  base::ASCIIToUTF16("paul1775@gmail.com")}),
               base::ASCIIToUTF16("19 North Sq, Boston, MA 02113")),
-          FormatExpectedLabel("Dina Katabi", "dina@mit.edu"),
+          ConstructLabelLine({base::ASCIIToUTF16("Dina Katabi"),
+                              base::ASCIIToUTF16("dina@mit.edu")}),
           base::ASCIIToUTF16(
               "Old North Church, 193 Salem St, Boston, MA 02113"),
           base::string16()));
@@ -353,11 +370,13 @@
           ConstructLabelLines(
               base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301, Vila Mariana, "
                                 "São Paulo-SP, 04094-050"),
-              FormatExpectedLabel("(11) 2648-0254", "tarsila@aol.com")),
+              ConstructLabelLine({base::ASCIIToUTF16("(11) 2648-0254"),
+                                  base::ASCIIToUTF16("tarsila@aol.com")})),
           ConstructLabelLines(
               base::UTF8ToUTF16("Estr. Dona Castorina, 110, Jardim Botânico, "
                                 "Rio de Janeiro-RJ, 22460-320"),
-              FormatExpectedLabel("(21) 98765-0000", "aavila@uol.com.br"))));
+              ConstructLabelLine({base::ASCIIToUTF16("(21) 98765-0000"),
+                                  base::ASCIIToUTF16("aavila@uol.com.br")}))));
 }
 
 TEST(AddressContactFormLabelFormatterTest,
@@ -383,14 +402,18 @@
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
       ElementsAre(
           ConstructLabelLines(
-              FormatExpectedLabel("Tarsila do Amaral",
-                                  "Vila Mariana, São Paulo-SP, 04094-050"),
-              FormatExpectedLabel("(11) 2648-0254", "tarsila@aol.com")),
+              ConstructLabelLine(
+                  {base::ASCIIToUTF16("Tarsila do Amaral"),
+                   base::UTF8ToUTF16("Vila Mariana, São Paulo-SP, 04094-050")}),
+              ConstructLabelLine({base::ASCIIToUTF16("(11) 2648-0254"),
+                                  base::ASCIIToUTF16("tarsila@aol.com")})),
           ConstructLabelLines(
-              FormatExpectedLabel(
-                  "Artur Avila",
-                  "Jardim Botânico, Rio de Janeiro-RJ, 22460-320"),
-              FormatExpectedLabel("(21) 98765-0000", "aavila@uol.com.br"))));
+              ConstructLabelLine(
+                  {base::ASCIIToUTF16("Artur Avila"),
+                   base::UTF8ToUTF16(
+                       "Jardim Botânico, Rio de Janeiro-RJ, 22460-320")}),
+              ConstructLabelLine({base::ASCIIToUTF16("(21) 98765-0000"),
+                                  base::ASCIIToUTF16("aavila@uol.com.br")}))));
 }
 
 TEST(AddressContactFormLabelFormatterTest,
@@ -416,12 +439,17 @@
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
       ElementsAre(
           ConstructLabelLines(
-              FormatExpectedLabel("Tarsila do Amaral",
-                                  "Av. Pedro Álvares Cabral, 1301"),
-              FormatExpectedLabel("(11) 2648-0254", "tarsila@aol.com")),
+              ConstructLabelLine(
+                  {base::ASCIIToUTF16("Tarsila do Amaral"),
+                   base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}),
+              ConstructLabelLine({base::ASCIIToUTF16("(11) 2648-0254"),
+                                  base::ASCIIToUTF16("tarsila@aol.com")})),
           ConstructLabelLines(
-              FormatExpectedLabel("Artur Avila", "Estr. Dona Castorina, 110"),
-              FormatExpectedLabel("(21) 98765-0000", "aavila@uol.com.br"))));
+              ConstructLabelLine(
+                  {base::ASCIIToUTF16("Artur Avila"),
+                   base::ASCIIToUTF16("Estr. Dona Castorina, 110")}),
+              ConstructLabelLine({base::ASCIIToUTF16("(21) 98765-0000"),
+                                  base::ASCIIToUTF16("aavila@uol.com.br")}))));
 }
 
 TEST(AddressContactFormLabelFormatterTest,
@@ -447,11 +475,13 @@
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
       ElementsAre(
           ConstructLabelLines(
-              FormatExpectedLabel("Tarsila do Amaral", "(11) 2648-0254"),
+              ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"),
+                                  base::ASCIIToUTF16("(11) 2648-0254")}),
               base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301, Vila Mariana, "
                                 "São Paulo-SP, 04094-050")),
           ConstructLabelLines(
-              FormatExpectedLabel("Artur Avila", "(21) 98765-0000"),
+              ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"),
+                                  base::ASCIIToUTF16("(21) 98765-0000")}),
               base::UTF8ToUTF16("Estr. Dona Castorina, 110, Jardim Botânico, "
                                 "Rio de Janeiro-RJ, 22460-320"))));
 }
@@ -479,11 +509,13 @@
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
       ElementsAre(
           ConstructLabelLines(
-              FormatExpectedLabel("Tarsila do Amaral", "tarsila@aol.com"),
+              ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"),
+                                  base::ASCIIToUTF16("tarsila@aol.com")}),
               base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301, Vila Mariana, "
                                 "São Paulo-SP, 04094-050")),
           ConstructLabelLines(
-              FormatExpectedLabel("Artur Avila", "aavila@uol.com.br"),
+              ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"),
+                                  base::ASCIIToUTF16("aavila@uol.com.br")}),
               base::UTF8ToUTF16("Estr. Dona Castorina, 110, Jardim Botânico, "
                                 "Rio de Janeiro-RJ, 22460-320"))));
 }
@@ -504,7 +536,8 @@
   // Checks that only address fields in the form are shown in the label.
   EXPECT_THAT(formatter->GetLabels(std::vector<AutofillProfile*>{&profile}),
               ElementsAre(ConstructLabelLines(
-                  FormatExpectedLabel("Sarah Revere", "(617) 523-2338"),
+                  ConstructLabelLine({base::ASCIIToUTF16("Sarah Revere"),
+                                      base::ASCIIToUTF16("(617) 523-2338")}),
                   base::ASCIIToUTF16("02113"))));
 }
 
diff --git a/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc b/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc
index 0949e8a..5e41bf7 100644
--- a/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc
+++ b/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc
@@ -14,7 +14,7 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
+#include "components/autofill/core/browser/label_formatter_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -70,7 +70,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("333 Washington St", "jfk@gmail.com"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("333 Washington St"),
+                                      base::ASCIIToUTF16("jfk@gmail.com")}),
                   base::ASCIIToUTF16("151 Irving Ave"),
                   base::ASCIIToUTF16("paul1775@gmail.com"), base::string16()));
 }
@@ -105,7 +106,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "jfk@gmail.com"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("jfk@gmail.com")}),
                   base::ASCIIToUTF16("Jackie Kennedy"),
                   base::ASCIIToUTF16("paul1775@gmail.com"), base::string16()));
 }
@@ -140,7 +142,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("333 Washington St", "jfk@gmail.com"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("333 Washington St"),
+                                      base::ASCIIToUTF16("jfk@gmail.com")}),
                   base::ASCIIToUTF16("151 Irving Ave"),
                   base::ASCIIToUTF16("paul1775@gmail.com"), base::string16()));
 }
@@ -174,7 +177,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "333 Washington St"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("333 Washington St")}),
                   base::ASCIIToUTF16("Jackie Kennedy"), base::string16(),
                   base::ASCIIToUTF16("141 Franklin St")));
 }
@@ -199,10 +203,12 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("Av. Pedro Álvares Cabral, 1301",
-                                      "tarsila@aol.com"),
-                  FormatExpectedLabel("Estr. Dona Castorina, 110",
-                                      "aavila@uol.com.br")));
+      ElementsAre(
+          ConstructLabelLine(
+              {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"),
+               base::ASCIIToUTF16("tarsila@aol.com")}),
+          ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"),
+                              base::ASCIIToUTF16("aavila@uol.com.br")})));
 }
 
 TEST(AddressEmailFormLabelFormatterTest,
@@ -226,8 +232,11 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("Tarsila do Amaral", "tarsila@aol.com"),
-                  FormatExpectedLabel("Artur Avila", "aavila@uol.com.br")));
+      ElementsAre(
+          ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"),
+                              base::ASCIIToUTF16("tarsila@aol.com")}),
+          ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"),
+                              base::ASCIIToUTF16("aavila@uol.com.br")})));
 }
 
 TEST(AddressEmailFormLabelFormatterTest,
@@ -251,10 +260,12 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("Av. Pedro Álvares Cabral, 1301",
-                                      "tarsila@aol.com"),
-                  FormatExpectedLabel("Estr. Dona Castorina, 110",
-                                      "aavila@uol.com.br")));
+      ElementsAre(
+          ConstructLabelLine(
+              {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"),
+               base::ASCIIToUTF16("tarsila@aol.com")}),
+          ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"),
+                              base::ASCIIToUTF16("aavila@uol.com.br")})));
 }
 
 TEST(AddressEmailFormLabelFormatterTest,
@@ -278,10 +289,12 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(
-          FormatExpectedLabel("Tarsila do Amaral",
-                              "Av. Pedro Álvares Cabral, 1301"),
-          FormatExpectedLabel("Artur Avila", "Estr. Dona Castorina, 110")));
+      ElementsAre(ConstructLabelLine(
+                      {base::ASCIIToUTF16("Tarsila do Amaral"),
+                       base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}),
+                  ConstructLabelLine(
+                      {base::ASCIIToUTF16("Artur Avila"),
+                       base::ASCIIToUTF16("Estr. Dona Castorina, 110")})));
 }
 
 TEST(AddressEmailFormLabelFormatterTest,
@@ -300,7 +313,8 @@
   // Checks that only address fields in the form are shown in the label.
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "Brookline, MA")));
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("Brookline, MA")})));
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/address_form_label_formatter_unittest.cc b/components/autofill/core/browser/address_form_label_formatter_unittest.cc
index 92ba1a9..77af96cc 100644
--- a/components/autofill/core/browser/address_form_label_formatter_unittest.cc
+++ b/components/autofill/core/browser/address_form_label_formatter_unittest.cc
@@ -12,7 +12,7 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
+#include "components/autofill/core/browser/label_formatter_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -62,12 +62,13 @@
   const std::unique_ptr<LabelFormatter> formatter =
       LabelFormatter::Create("en-US", ADDRESS_HOME_LINE1, GetFieldTypes());
 
-  EXPECT_THAT(
-      formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
-                                                         &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "Brookline, MA 02445"),
-                  base::ASCIIToUTF16("Hyannis, MA"),
-                  base::ASCIIToUTF16("Paul Revere"), base::string16()));
+  EXPECT_THAT(formatter->GetLabels(std::vector<AutofillProfile*>{
+                  &profile1, &profile2, &profile3, &profile4}),
+              ElementsAre(ConstructLabelLine(
+                              {base::ASCIIToUTF16("John F Kennedy"),
+                               base::ASCIIToUTF16("Brookline, MA 02445")}),
+                          base::ASCIIToUTF16("Hyannis, MA"),
+                          base::ASCIIToUTF16("Paul Revere"), base::string16()));
 }
 
 TEST(AddressFormLabelFormatterTest,
@@ -100,7 +101,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "333 Washington St"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("333 Washington St")}),
                   base::ASCIIToUTF16("151 Irving Ave"),
                   base::ASCIIToUTF16("Paul Revere"), base::string16()));
 }
@@ -138,10 +140,11 @@
   const std::unique_ptr<LabelFormatter> formatter =
       LabelFormatter::Create("pt-BR", ADDRESS_HOME_LINE1, GetFieldTypes());
 
-  EXPECT_THAT(formatter->GetLabels(std::vector<AutofillProfile*>{&profile1}),
-              ElementsAre(FormatExpectedLabel("Tarsila do Amaral",
-                                              "Vila Mariana, São "
-                                              "Paulo-SP, 04094-050")));
+  EXPECT_THAT(
+      formatter->GetLabels(std::vector<AutofillProfile*>{&profile1}),
+      ElementsAre(ConstructLabelLine(
+          {base::ASCIIToUTF16("Tarsila do Amaral"),
+           base::UTF8ToUTF16("Vila Mariana, São Paulo-SP, 04094-050")})));
 }
 
 TEST(AddressFormLabelFormatterTest,
@@ -156,8 +159,9 @@
       LabelFormatter::Create("pt-BR", ADDRESS_HOME_ZIP, GetFieldTypes());
 
   EXPECT_THAT(formatter->GetLabels(std::vector<AutofillProfile*>{&profile1}),
-              ElementsAre(FormatExpectedLabel(
-                  "Tarsila do Amaral", "Av. Pedro Álvares Cabral, 1301")));
+              ElementsAre(ConstructLabelLine(
+                  {base::ASCIIToUTF16("Tarsila do Amaral"),
+                   base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")})));
 }
 
 TEST(AddressFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) {
diff --git a/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc b/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc
index 01b71f8f..345332c 100644
--- a/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc
+++ b/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc
@@ -14,7 +14,7 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
+#include "components/autofill/core/browser/label_formatter_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -64,7 +64,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("(617) 730-2000", "333 Washington St"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("(617) 730-2000"),
+                                      base::ASCIIToUTF16("333 Washington St")}),
                   base::ASCIIToUTF16("151 Irving Ave"),
                   base::ASCIIToUTF16("(617) 523-2338"), base::string16()));
 }
@@ -99,7 +100,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "(617) 730-2000"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("(617) 730-2000")}),
                   base::ASCIIToUTF16("Jackie Kennedy"),
                   base::ASCIIToUTF16("(617) 523-2338"), base::string16()));
 }
@@ -134,7 +136,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("333 Washington St", "(617) 730-2000"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("333 Washington St"),
+                                      base::ASCIIToUTF16("(617) 730-2000")}),
                   base::ASCIIToUTF16("151 Irving Ave"),
                   base::ASCIIToUTF16("(617) 523-2338"), base::string16()));
 }
@@ -169,7 +172,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "333 Washington St"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("333 Washington St")}),
                   base::ASCIIToUTF16("Jackie Kennedy"),
                   base::ASCIIToUTF16("Paul Revere House, 19 North Square"),
                   base::string16()));
@@ -195,10 +199,12 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(
-          FormatExpectedLabel("(11) 2648-0254",
-                              "Av. Pedro Álvares Cabral, 1301"),
-          FormatExpectedLabel("(21) 98765-0000", "Estr. Dona Castorina, 110")));
+      ElementsAre(ConstructLabelLine(
+                      {base::ASCIIToUTF16("(11) 2648-0254"),
+                       base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}),
+                  ConstructLabelLine(
+                      {base::ASCIIToUTF16("(21) 98765-0000"),
+                       base::ASCIIToUTF16("Estr. Dona Castorina, 110")})));
 }
 
 TEST(AddressPhoneFormLabelFormatterTest,
@@ -222,8 +228,10 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("Tarsila do Amaral", "(11) 2648-0254"),
-                  FormatExpectedLabel("Artur Avila", "(21) 98765-0000")));
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"),
+                                      base::ASCIIToUTF16("(11) 2648-0254")}),
+                  ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"),
+                                      base::ASCIIToUTF16("(21) 98765-0000")})));
 }
 
 TEST(AddressPhoneFormLabelFormatterTest,
@@ -248,9 +256,11 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
       ElementsAre(
-          FormatExpectedLabel("Av. Pedro Álvares Cabral, 1301",
-                              "(11) 2648-0254"),
-          FormatExpectedLabel("Estr. Dona Castorina, 110", "(21) 98765-0000")));
+          ConstructLabelLine(
+              {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"),
+               base::ASCIIToUTF16("(11) 2648-0254")}),
+          ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"),
+                              base::ASCIIToUTF16("(21) 98765-0000")})));
 }
 
 TEST(AddressPhoneFormLabelFormatterTest,
@@ -274,10 +284,12 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(
-          FormatExpectedLabel("Tarsila do Amaral",
-                              "Av. Pedro Álvares Cabral, 1301"),
-          FormatExpectedLabel("Artur Avila", "Estr. Dona Castorina, 110")));
+      ElementsAre(ConstructLabelLine(
+                      {base::ASCIIToUTF16("Tarsila do Amaral"),
+                       base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}),
+                  ConstructLabelLine(
+                      {base::ASCIIToUTF16("Artur Avila"),
+                       base::ASCIIToUTF16("Estr. Dona Castorina, 110")})));
 }
 
 TEST(AddressPhoneFormLabelFormatterTest,
@@ -293,8 +305,10 @@
       {NAME_FULL, PHONE_HOME_WHOLE_NUMBER, ADDRESS_HOME_ZIP});
 
   // Checks that only address fields in the form are shown in the label.
-  EXPECT_THAT(formatter->GetLabels(std::vector<AutofillProfile*>{&profile1}),
-              ElementsAre(FormatExpectedLabel("John F Kennedy", "02445")));
+  EXPECT_THAT(
+      formatter->GetLabels(std::vector<AutofillProfile*>{&profile1}),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("02445")})));
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/contact_form_label_formatter_unittest.cc b/components/autofill/core/browser/contact_form_label_formatter_unittest.cc
index 67add44d..3d98f61 100644
--- a/components/autofill/core/browser/contact_form_label_formatter_unittest.cc
+++ b/components/autofill/core/browser/contact_form_label_formatter_unittest.cc
@@ -14,7 +14,7 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
+#include "components/autofill/core/browser/label_formatter_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,7 +63,8 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("(617) 730-2000", "jfk@gmail.com"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("(617) 730-2000"),
+                                      base::ASCIIToUTF16("jfk@gmail.com")}),
                   base::ASCIIToUTF16("jackie@outlook.com"),
                   base::ASCIIToUTF16("(617) 523-2338"), base::string16()));
 }
@@ -97,9 +98,11 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "(617) 730-2000"),
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                                      base::ASCIIToUTF16("(617) 730-2000")}),
                   base::ASCIIToUTF16("Jackie Kennedy"),
-                  FormatExpectedLabel("Paul Revere", "(617) 523-2338"),
+                  ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"),
+                                      base::ASCIIToUTF16("(617) 523-2338")}),
                   base::string16()));
 }
 
@@ -132,9 +135,12 @@
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2,
                                                          &profile3, &profile4}),
-      ElementsAre(FormatExpectedLabel("John F Kennedy", "jfk@gmail.com"),
-                  FormatExpectedLabel("Jackie Kennedy", "jackie@outlook.com"),
-                  base::ASCIIToUTF16("Paul Revere"), base::string16()));
+      ElementsAre(
+          ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"),
+                              base::ASCIIToUTF16("jfk@gmail.com")}),
+          ConstructLabelLine({base::ASCIIToUTF16("Jackie Kennedy"),
+                              base::ASCIIToUTF16("jackie@outlook.com")}),
+          base::ASCIIToUTF16("Paul Revere"), base::string16()));
 }
 
 TEST(ContactFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) {
@@ -157,8 +163,11 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("(11) 2648-0254", "tarsila@aol.com"),
-                  FormatExpectedLabel("(21) 98765-0000", "aavila@uol.com.br")));
+      ElementsAre(
+          ConstructLabelLine({base::ASCIIToUTF16("(11) 2648-0254"),
+                              base::ASCIIToUTF16("tarsila@aol.com")}),
+          ConstructLabelLine({base::ASCIIToUTF16("(21) 98765-0000"),
+                              base::ASCIIToUTF16("aavila@uol.com.br")})));
 }
 
 TEST(ContactFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedEmail) {
@@ -181,8 +190,10 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("Tarsila do Amaral", "(11) 2648-0254"),
-                  FormatExpectedLabel("Artur Avila", "(21) 98765-0000")));
+      ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"),
+                                      base::ASCIIToUTF16("(11) 2648-0254")}),
+                  ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"),
+                                      base::ASCIIToUTF16("(21) 98765-0000")})));
 }
 
 TEST(ContactFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedPhone) {
@@ -205,8 +216,11 @@
 
   EXPECT_THAT(
       formatter->GetLabels(std::vector<AutofillProfile*>{&profile1, &profile2}),
-      ElementsAre(FormatExpectedLabel("Tarsila do Amaral", "tarsila@aol.com"),
-                  FormatExpectedLabel("Artur Avila", "aavila@uol.com.br")));
+      ElementsAre(
+          ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"),
+                              base::ASCIIToUTF16("tarsila@aol.com")}),
+          ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"),
+                              base::ASCIIToUTF16("aavila@uol.com.br")})));
 }
 
 TEST(ContactFormLabelFormatterTest, GetLabelsForNameAndPhoneWithFocusedName) {
diff --git a/components/autofill/core/browser/label_formatter_test_utils.cc b/components/autofill/core/browser/label_formatter_test_utils.cc
deleted file mode 100644
index 2410cd71..0000000
--- a/components/autofill/core/browser/label_formatter_test_utils.cc
+++ /dev/null
@@ -1,22 +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.
-
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
-
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/grit/components_scaled_resources.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace autofill {
-
-base::string16 FormatExpectedLabel(base::StringPiece label_part1,
-                                   base::StringPiece label_part2) {
-  return l10n_util::GetStringFUTF16(IDS_AUTOFILL_SUGGESTION_LABEL,
-                                    base::UTF8ToUTF16(label_part1),
-                                    base::UTF8ToUTF16(label_part2));
-}
-
-}  // namespace autofill
\ No newline at end of file
diff --git a/components/autofill/core/browser/label_formatter_test_utils.h b/components/autofill/core/browser/label_formatter_test_utils.h
deleted file mode 100644
index 73ca5c1..0000000
--- a/components/autofill/core/browser/label_formatter_test_utils.h
+++ /dev/null
@@ -1,20 +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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_TEST_UTILS_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_TEST_UTILS_H_
-
-#include "base/strings/string16.h"
-#include "base/strings/string_piece.h"
-
-namespace autofill {
-
-// Returns the the string to display to users according to the localized
-// string IDS_AUTOFILL_SUGGESTION_LABEL, e.g. label_part1 • label_part2.
-base::string16 FormatExpectedLabel(base::StringPiece label_part1,
-                                   base::StringPiece label_part2);
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_TEST_UTILS_H_
diff --git a/components/autofill/core/browser/label_formatter_utils.cc b/components/autofill/core/browser/label_formatter_utils.cc
index b75ec06..69e51e7 100644
--- a/components/autofill/core/browser/label_formatter_utils.cc
+++ b/components/autofill/core/browser/label_formatter_utils.cc
@@ -122,10 +122,8 @@
 }
 
 base::string16 ConstructLabelLine(const std::vector<base::string16>& parts) {
-  return parts.size() == kMaxNumberOfParts
-             ? l10n_util::GetStringFUTF16(IDS_AUTOFILL_SUGGESTION_LABEL,
-                                          parts.front(), parts.back())
-             : base::JoinString(parts, base::string16());
+  return base::JoinString(parts, l10n_util::GetStringUTF16(
+                                     IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR));
 }
 
 base::string16 ConstructLabelLines(const base::string16& top_line,
diff --git a/components/autofill/core/browser/label_formatter_utils.h b/components/autofill/core/browser/label_formatter_utils.h
index d12d6c9..3ded23ba 100644
--- a/components/autofill/core/browser/label_formatter_utils.h
+++ b/components/autofill/core/browser/label_formatter_utils.h
@@ -30,8 +30,6 @@
 
 }  // namespace label_formatter_groups
 
-const size_t kMaxNumberOfParts = 2;
-
 // Indicates where to split the label text when the label spans two lines.
 // This is used in the kAutofillUseImprovedLabelDisambiguation feature.
 constexpr char kMultilineLabelDelimiter[] = "\n";
@@ -76,16 +74,9 @@
 void AddLabelPartIfNotEmpty(const base::string16& part,
                             std::vector<base::string16>* parts);
 
-// Returns the text to show to the user. |parts| may have 0, 1, or 2 elements.
-//
-// If |parts| is empty, then an empty string is returned. This might happen
-// when (A) a profile has only name and address information and (B) the user
-// with this profile interacts with a contact form, which excludes address
-// fields and includes name, email address, and phone number fields.
-//
-// If |parts| has a single element, then the string is returned. This might
-// happen when (A) a profile has only name and email address information and
-// (B) the user with this profile interacts with a contact form.
+// Returns the text to show to the user. If there is more than one element in
+// |parts|, then a separator, |IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR|, is
+// inserted between them.
 base::string16 ConstructLabelLine(const std::vector<base::string16>& parts);
 
 // Returns the text to be displayed in a multiline label plus maybe a
diff --git a/components/autofill/core/browser/label_formatter_utils_unittest.cc b/components/autofill/core/browser/label_formatter_utils_unittest.cc
index 833ccbb..c0383ae 100644
--- a/components/autofill/core/browser/label_formatter_utils_unittest.cc
+++ b/components/autofill/core/browser/label_formatter_utils_unittest.cc
@@ -4,7 +4,12 @@
 
 #include "components/autofill/core/browser/label_formatter_utils.h"
 
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/grit/components_scaled_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace autofill {
 
@@ -71,4 +76,20 @@
   EXPECT_EQ(expected_group_bitmask, group_bitmask);
 }
 
+TEST(LabelFormatterUtilsTest, ConstructLabelLine) {
+  EXPECT_EQ(base::string16(), ConstructLabelLine({}));
+
+  base::string16 name = base::ASCIIToUTF16("Blaise Pascal");
+  base::string16 phone = base::ASCIIToUTF16("01 53 01 82 00");
+  base::string16 email = base::ASCIIToUTF16("b.pascal@orange.fr");
+
+  base::string16 separator =
+      l10n_util::GetStringUTF16(IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR);
+
+  EXPECT_EQ(name, ConstructLabelLine({name}));
+  EXPECT_EQ(base::JoinString({name, separator, phone, separator, email},
+                             base::string16()),
+            ConstructLabelLine({name, phone, email}));
+}
+
 }  // namespace autofill
\ No newline at end of file
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index e3c2ba2..df8df65 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -38,7 +38,7 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_structure.h"
-#include "components/autofill/core/browser/label_formatter_test_utils.h"
+#include "components/autofill/core/browser/label_formatter_utils.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/autofill/core/browser/suggestion_selection.h"
 #include "components/autofill/core/browser/sync_utils.h"
@@ -2566,10 +2566,12 @@
       ElementsAre(AllOf(
           testing::Field(
               &Suggestion::label,
-              FormatExpectedLabel("(978) 674-4120", "hoa.pham@comcast.net")),
+              ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"),
+                                  base::ASCIIToUTF16("hoa.pham@comcast.net")})),
           testing::Field(
               &Suggestion::additional_label,
-              FormatExpectedLabel("(978) 674-4120", "hoa.pham@comcast.net")),
+              ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"),
+                                  base::ASCIIToUTF16("hoa.pham@comcast.net")})),
           testing::Field(&Suggestion::icon, "userAccountAvatarIcon"))));
 }
 #endif  // #if !defined(OS_ANDROID) && !defined(OS_IOS)
@@ -2624,13 +2626,16 @@
           AutofillType(NAME_FULL), base::string16(), false,
           std::vector<ServerFieldType>{NAME_FULL, ADDRESS_HOME_STREET_ADDRESS,
                                        PHONE_HOME_WHOLE_NUMBER}),
-      ElementsAre(AllOf(testing::Field(&Suggestion::label,
-                                       FormatExpectedLabel("(978) 674-4120",
-                                                           "401 Merrimack St")),
-                        testing::Field(&Suggestion::additional_label,
-                                       FormatExpectedLabel("(978) 674-4120",
-                                                           "401 Merrimack St")),
-                        testing::Field(&Suggestion::icon, "locationOnIcon"))));
+      ElementsAre(AllOf(
+          testing::Field(
+              &Suggestion::label,
+              ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"),
+                                  base::ASCIIToUTF16("401 Merrimack St")})),
+          testing::Field(
+              &Suggestion::additional_label,
+              ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"),
+                                  base::ASCIIToUTF16("401 Merrimack St")})),
+          testing::Field(&Suggestion::icon, "locationOnIcon"))));
 }
 #endif  // #if !defined(OS_ANDROID) && !defined(OS_IOS)
 
@@ -2649,18 +2654,21 @@
       /*enabled_features=*/{features::kAutofillUseImprovedLabelDisambiguation},
       /*disabled_features=*/{});
 
-  EXPECT_THAT(personal_data_->GetProfileSuggestions(
-                  AutofillType(NAME_FULL), base::string16(), false,
-                  std::vector<ServerFieldType>{
-                      NAME_FULL, ADDRESS_HOME_STREET_ADDRESS, EMAIL_ADDRESS}),
-              ElementsAre(AllOf(
-                  testing::Field(&Suggestion::label,
-                                 FormatExpectedLabel("401 Merrimack St",
-                                                     "hoa.pham@comcast.net")),
-                  testing::Field(&Suggestion::additional_label,
-                                 FormatExpectedLabel("401 Merrimack St",
-                                                     "hoa.pham@comcast.net")),
-                  testing::Field(&Suggestion::icon, "locationOnIcon"))));
+  EXPECT_THAT(
+      personal_data_->GetProfileSuggestions(
+          AutofillType(NAME_FULL), base::string16(), false,
+          std::vector<ServerFieldType>{NAME_FULL, ADDRESS_HOME_STREET_ADDRESS,
+                                       EMAIL_ADDRESS}),
+      ElementsAre(AllOf(
+          testing::Field(
+              &Suggestion::label,
+              ConstructLabelLine({base::ASCIIToUTF16("401 Merrimack St"),
+                                  base::ASCIIToUTF16("hoa.pham@comcast.net")})),
+          testing::Field(
+              &Suggestion::additional_label,
+              ConstructLabelLine({base::ASCIIToUTF16("401 Merrimack St"),
+                                  base::ASCIIToUTF16("hoa.pham@comcast.net")})),
+          testing::Field(&Suggestion::icon, "locationOnIcon"))));
 }
 #endif  // #if !defined(OS_ANDROID) && !defined(OS_IOS)
 
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
index 028ac77..4547ed5 100644
--- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -49,7 +49,6 @@
 using syncer::EntityChange;
 using syncer::EntityChangeList;
 using syncer::EntityData;
-using syncer::EntityDataPtr;
 using syncer::HasInitialSyncDone;
 using syncer::IsEmptyMetadataBatch;
 using syncer::KeyAndData;
@@ -223,15 +222,13 @@
   }
 
   std::string GetClientTag(const AutofillSpecifics& specifics) {
-    std::string tag =
-        bridge()->GetClientTag(SpecificsToEntity(specifics).value());
+    std::string tag = bridge()->GetClientTag(*SpecificsToEntity(specifics));
     EXPECT_FALSE(tag.empty());
     return tag;
   }
 
   std::string GetStorageKey(const AutofillSpecifics& specifics) {
-    std::string key =
-        bridge()->GetStorageKey(SpecificsToEntity(specifics).value());
+    std::string key = bridge()->GetStorageKey(*SpecificsToEntity(specifics));
     EXPECT_FALSE(key.empty());
     return key;
   }
@@ -246,12 +243,13 @@
     return changes;
   }
 
-  EntityDataPtr SpecificsToEntity(const AutofillSpecifics& specifics) {
-    EntityData data;
-    *data.specifics.mutable_autofill() = specifics;
-    data.client_tag_hash = syncer::GenerateSyncableHash(
-        syncer::AUTOFILL, bridge()->GetClientTag(data));
-    return data.PassToPtr();
+  std::unique_ptr<EntityData> SpecificsToEntity(
+      const AutofillSpecifics& specifics) {
+    auto data = std::make_unique<EntityData>();
+    *data->specifics.mutable_autofill() = specifics;
+    data->client_tag_hash = syncer::GenerateSyncableHash(
+        syncer::AUTOFILL, bridge()->GetClientTag(*data));
+    return data;
   }
 
   std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse(
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
index d7d794e0..4b1986b 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
@@ -53,7 +53,6 @@
 using syncer::EntityChange;
 using syncer::EntityChangeList;
 using syncer::EntityData;
-using syncer::EntityDataPtr;
 using syncer::KeyAndData;
 using syncer::MockModelTypeChangeProcessor;
 using syncer::ModelType;
@@ -293,12 +292,13 @@
     return data;
   }
 
-  EntityDataPtr SpecificsToEntity(const AutofillProfileSpecifics& specifics) {
-    EntityData data;
-    *data.specifics.mutable_autofill_profile() = specifics;
-    data.client_tag_hash = syncer::GenerateSyncableHash(
-        syncer::AUTOFILL_PROFILE, bridge()->GetClientTag(data));
-    return data.PassToPtr();
+  std::unique_ptr<EntityData> SpecificsToEntity(
+      const AutofillProfileSpecifics& specifics) {
+    auto data = std::make_unique<EntityData>();
+    *data->specifics.mutable_autofill_profile() = specifics;
+    data->client_tag_hash = syncer::GenerateSyncableHash(
+        syncer::AUTOFILL_PROFILE, bridge()->GetClientTag(*data));
+    return data;
   }
 
   std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse(
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
index eb1f65e..a7650358 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
@@ -45,11 +45,12 @@
   DISALLOW_COPY_AND_ASSIGN(TestAutofillTable);
 };
 
-EntityData SpecificsToEntity(const sync_pb::AutofillWalletSpecifics& specifics,
-                             const std::string& client_tag) {
-  EntityData data;
-  *data.specifics.mutable_autofill_wallet() = specifics;
-  data.client_tag_hash =
+std::unique_ptr<EntityData> SpecificsToEntity(
+    const sync_pb::AutofillWalletSpecifics& specifics,
+    const std::string& client_tag) {
+  auto data = std::make_unique<syncer::EntityData>();
+  *data->specifics.mutable_autofill_wallet() = specifics;
+  data->client_tag_hash =
       syncer::GenerateSyncableHash(syncer::AUTOFILL_WALLET_DATA, client_tag);
   return data;
 }
@@ -72,20 +73,17 @@
   entity_data.push_back(EntityChange::CreateAdd(
       address_id,
       SpecificsToEntity(CreateAutofillWalletSpecificsForAddress(address_id),
-                        /*client_tag=*/"address-address1")
-          .PassToPtr()));
+                        /*client_tag=*/"address-address1")));
   entity_data.push_back(EntityChange::CreateAdd(
       "card1",
       SpecificsToEntity(CreateAutofillWalletSpecificsForCard(
                             /*id=*/"card1", /*billing_address_id=*/address_id),
-                        /*client_tag=*/"card-card1")
-          .PassToPtr()));
+                        /*client_tag=*/"card-card1")));
   entity_data.push_back(EntityChange::CreateAdd(
       "deadbeef",
       SpecificsToEntity(CreateAutofillWalletSpecificsForPaymentsCustomerData(
                             /*specifics_id=*/"deadbeef"),
-                        /*client_tag=*/"customer-deadbeef")
-          .PassToPtr()));
+                        /*client_tag=*/"customer-deadbeef")));
 
   std::vector<CreditCard> wallet_cards;
   std::vector<AutofillProfile> wallet_addresses;
@@ -201,4 +199,4 @@
 }
 
 }  // namespace
-}  // namespace autofill
\ No newline at end of file
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
index f793b93..6d10220e 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
@@ -45,7 +45,6 @@
 using sync_pb::WalletMetadataSpecifics;
 using syncer::DataBatch;
 using syncer::EntityData;
-using syncer::EntityDataPtr;
 using syncer::KeyAndData;
 using syncer::MockModelTypeChangeProcessor;
 using syncer::ModelType;
@@ -347,17 +346,18 @@
     real_processor_->OnUpdateReceived(state, std::move(updates));
   }
 
-  EntityData SpecificsToEntity(const WalletMetadataSpecifics& specifics,
-                               bool is_deleted = false) {
-    EntityData data;
-    *data.specifics.mutable_wallet_metadata() = specifics;
-    data.client_tag_hash = syncer::GenerateSyncableHash(
-        syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(data));
+  std::unique_ptr<EntityData> SpecificsToEntity(
+      const WalletMetadataSpecifics& specifics,
+      bool is_deleted = false) {
+    auto data = std::make_unique<EntityData>();
+    *data->specifics.mutable_wallet_metadata() = specifics;
+    data->client_tag_hash = syncer::GenerateSyncableHash(
+        syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(*data));
     if (is_deleted) {
       // Specifics had to be set in order to generate the client tag. Since
       // deleted entity is defined by specifics being empty, we need to clear
       // them now.
-      data.specifics = sync_pb::EntitySpecifics();
+      data->specifics = sync_pb::EntitySpecifics();
     }
     return data;
   }
@@ -366,7 +366,7 @@
       const WalletMetadataSpecifics& specifics,
       bool is_deleted = false) {
     auto data = std::make_unique<syncer::UpdateResponseData>();
-    data->entity = SpecificsToEntity(specifics, is_deleted).PassToPtr();
+    data->entity = SpecificsToEntity(specifics, is_deleted);
     data->response_version = response_version;
     return data;
   }
@@ -465,7 +465,7 @@
   ResetBridge();
   WalletMetadataSpecifics specifics =
       CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId);
-  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kAddr1SyncTag);
 }
 
@@ -473,7 +473,7 @@
   ResetBridge();
   WalletMetadataSpecifics specifics =
       CreateWalletMetadataSpecificsForCard(kCard1SpecificsId);
-  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kCard1SyncTag);
 }
 
@@ -482,7 +482,7 @@
   ResetBridge();
   WalletMetadataSpecifics specifics =
       CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId);
-  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics)),
             GetAddressStorageKey(kAddr1SpecificsId));
 }
 
@@ -490,7 +490,7 @@
   ResetBridge();
   WalletMetadataSpecifics specifics =
       CreateWalletMetadataSpecificsForCard(kCard1SpecificsId);
-  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics)),
             GetCardStorageKey(kCard1SpecificsId));
 }
 
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index 9950071..c595c29b 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -57,7 +57,6 @@
 using syncer::DataBatch;
 using syncer::EntityChange;
 using syncer::EntityData;
-using syncer::EntityDataPtr;
 using syncer::HasInitialSyncDone;
 using syncer::KeyAndData;
 using syncer::MockModelTypeChangeProcessor;
@@ -329,11 +328,12 @@
     EXPECT_EQ(addresses_count, addresses_metadata.size());
   }
 
-  EntityData SpecificsToEntity(const AutofillWalletSpecifics& specifics) {
-    EntityData data;
-    *data.specifics.mutable_autofill_wallet() = specifics;
-    data.client_tag_hash = syncer::GenerateSyncableHash(
-        syncer::AUTOFILL_WALLET_DATA, bridge()->GetClientTag(data));
+  std::unique_ptr<EntityData> SpecificsToEntity(
+      const AutofillWalletSpecifics& specifics) {
+    auto data = std::make_unique<EntityData>();
+    *data->specifics.mutable_autofill_wallet() = specifics;
+    data->client_tag_hash = syncer::GenerateSyncableHash(
+        syncer::AUTOFILL_WALLET_DATA, bridge()->GetClientTag(*data));
     return data;
   }
 
@@ -353,7 +353,7 @@
   std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse(
       const AutofillWalletSpecifics& specifics) {
     auto data = std::make_unique<syncer::UpdateResponseData>();
-    data->entity = SpecificsToEntity(specifics).PassToPtr();
+    data->entity = SpecificsToEntity(specifics);
     return data;
   }
 
@@ -392,14 +392,14 @@
 TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForAddress) {
   AutofillWalletSpecifics specifics =
       CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId);
-  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kAddr1SyncTag);
 }
 
 TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCard) {
   AutofillWalletSpecifics specifics =
       CreateAutofillWalletSpecificsForCard(kCard1SpecificsId);
-  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kCard1SyncTag);
 }
 
@@ -407,7 +407,7 @@
   AutofillWalletSpecifics specifics =
       CreateAutofillWalletSpecificsForPaymentsCustomerData(
           kCustomerDataSyncTag);
-  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+  EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kCustomerDataSyncTag);
 }
 
@@ -415,21 +415,21 @@
 TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) {
   AutofillWalletSpecifics specifics1 =
       CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId);
-  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics1)),
+  EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics1)),
             kAddr1SpecificsId);
 }
 
 TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) {
   AutofillWalletSpecifics specifics2 =
       CreateAutofillWalletSpecificsForCard(kCard1SpecificsId);
-  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics2)),
+  EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics2)),
             kCard1SpecificsId);
 }
 
 TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) {
   AutofillWalletSpecifics specifics3 =
       CreateAutofillWalletSpecificsForPaymentsCustomerData(kCustomerDataId);
-  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics3)),
+  EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics3)),
             kCustomerDataId);
 }
 
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 634a03d..98f3d8ce 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -205,13 +205,8 @@
 
 // Controls whether password generation is offered automatically on fields
 // perceived as eligible for generation.
-#if defined(OS_ANDROID)
-const base::Feature kAutomaticPasswordGeneration = {
-    "AutomaticPasswordGeneration", base::FEATURE_DISABLED_BY_DEFAULT};
-#else
 const base::Feature kAutomaticPasswordGeneration = {
     "AutomaticPasswordGeneration", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
 
 #if defined(OS_ANDROID)
 // Controls whether the Autofill manual fallback for Addresses and Payments is
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index ace23a5..453771e 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -166,10 +166,9 @@
     </message>
   </if>
 
-  <!-- Autofill suggestion label with delimiter -->
-  <message name="IDS_AUTOFILL_SUGGESTION_LABEL" desc="Text with disambiguating information to help users select the correct Autofill profile. Sometimes more than one type of information, such as a phone number and an email address or a name and a street address, is shown. A symbol, in this case a bullet •, is used to separate the two parts of the label that will appear on the same line, e.g. (877) 733-7699 • fanfeedback@redsox.com or George Washington • 465 Huntington Ave. A bullet • is preferred for separating the label parts; however, if the bullet • resembles another symbol in the language, please translate the bullet • as a symbol (A) that is not easily mistaken for a number or letter in the language and (B) that is typically used to separate elements.">
-    <ph name="LEFT_PART">$1<ex>(877) 733-7699</ex></ph> • <ph name="RIGHT_PART">$2<ex>fanfeedback@redsox.com</ex></ph>
-  </message>
+  <!-- Autofill suggestion label separator -->
+  <message name="IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR" desc="A separator to place between different elements of a suggestion's label. Labels sometimes have more than one type of information, such as a phone number and an email address or a street address, a phone number, and an email address. A symbol, in this case a bullet •, with a white space before it and a white space after it, is used to separate the parts of the label that appear on the same line, e.g. (877) 733-7699 • fanfeedback@redsox.com or 465 Huntington Ave • (617) 267-9300 • matthewt@mfa.org. A bullet • is preferred for separating the label parts; however, if the bullet • resembles another symbol in the language, please translate the bullet • as a symbol (A) that is not easily mistaken for a number or letter in the language and (B) that is typically used to separate elements.">
+  ''' • '''</message>
 
   <!-- Autofill credit card suggestion popup -->
   <message name="IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]">
diff --git a/components/browser_sync/browser_sync_client.cc b/components/browser_sync/browser_sync_client.cc
index eba56fd..9c285221 100644
--- a/components/browser_sync/browser_sync_client.cc
+++ b/components/browser_sync/browser_sync_client.cc
@@ -4,7 +4,6 @@
 
 #include "components/browser_sync/browser_sync_client.h"
 
-#include "components/sync/device_info/device_info_sync_service.h"
 #include "components/sync/model/model_type_store_service.h"
 
 namespace browser_sync {
@@ -17,9 +16,4 @@
   return GetModelTypeStoreService()->GetSyncDataPath();
 }
 
-const syncer::LocalDeviceInfoProvider*
-BrowserSyncClient::GetLocalDeviceInfoProvider() {
-  return GetDeviceInfoSyncService()->GetLocalDeviceInfoProvider();
-}
-
 }  // namespace browser_sync
diff --git a/components/browser_sync/browser_sync_client.h b/components/browser_sync/browser_sync_client.h
index 94dfca4..eedb660 100644
--- a/components/browser_sync/browser_sync_client.h
+++ b/components/browser_sync/browser_sync_client.h
@@ -55,7 +55,6 @@
   ~BrowserSyncClient() override;
 
   base::FilePath GetSyncDataPath() final;
-  const syncer::LocalDeviceInfoProvider* GetLocalDeviceInfoProvider() final;
   virtual syncer::ModelTypeStoreService* GetModelTypeStoreService() = 0;
 
   // Returns a weak pointer to the ModelTypeControllerDelegate specified by
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 7d43ba6..4963e046 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -418,9 +418,6 @@
                 .get())));
   }
 
-  // TODO(crbug.com/919489): Enable security events once their controller
-  // delegate is wired properly.
-
   // Forward both on-disk and in-memory storage modes to the same delegate,
   // since behavior for USER_CONSENTS does not differ (they are always
   // persisted).
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
index ccd7f88..48dda57 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -18,7 +18,6 @@
 #include "base/observer_list.h"
 #include "base/sequence_checker.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
 #include "components/data_reduction_proxy/core/browser/db_data_owner.h"
 #include "components/data_use_measurement/core/data_use_measurement.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
@@ -46,6 +45,7 @@
 
 class DataReductionProxyCompressionStats;
 class DataReductionProxyIOData;
+class DataReductionProxyPingbackClient;
 class DataReductionProxyServiceObserver;
 class DataReductionProxySettings;
 
@@ -135,12 +135,6 @@
   // Sets the reporting fraction in the pingback client.
   void SetPingbackReportingFraction(float pingback_reporting_fraction);
 
-  // Sets |pingback_client_| to be used for testing purposes.
-  void SetPingbackClientForTesting(
-      DataReductionProxyPingbackClient* pingback_client) {
-    pingback_client_.reset(pingback_client);
-  }
-
   // Notifies |this| that the user has requested to clear the browser
   // cache. This method is not called if only a subset of site entries are
   // cleared.
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 7791b8b..7c20617e 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -43,11 +43,5 @@
     "DataReductionProxyBlockOnBadGatewayResponse",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables populating the previews page ID from NavigationUIData to the
-// pingbacks.
-const base::Feature kDataReductionProxyPopulatePreviewsPageIDToPingback{
-    "DataReductionProxyPopulatePreviewsPageIDToPingback",
-    base::FEATURE_ENABLED_BY_DEFAULT};
-
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index 66612bde..6192e135 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -16,7 +16,6 @@
 extern const base::Feature kDataReductionProxyEnabledWithNetworkService;
 extern const base::Feature kDataSaverUseOnDeviceSafeBrowsing;
 extern const base::Feature kDataReductionProxyBlockOnBadGatewayResponse;
-extern const base::Feature kDataReductionProxyPopulatePreviewsPageIDToPingback;
 
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc b/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
index 99cb2cb5..81d39d1 100644
--- a/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
+++ b/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
@@ -31,7 +31,6 @@
 using syncer::EntityChange;
 using syncer::EntityChangeList;
 using syncer::EntityData;
-using syncer::EntityDataPtr;
 using syncer::KeyAndData;
 using syncer::MetadataBatch;
 using syncer::MetadataChangeList;
@@ -401,11 +400,11 @@
     return bridge()->GetStorageKeyInternal(url);
   }
 
-  EntityDataPtr SpecificsToEntity(const TypedUrlSpecifics& specifics) {
-    EntityData data;
-    data.client_tag_hash = "ignored";
-    *data.specifics.mutable_typed_url() = specifics;
-    return data.PassToPtr();
+  std::unique_ptr<EntityData> SpecificsToEntity(
+      const TypedUrlSpecifics& specifics) {
+    auto data = std::make_unique<EntityData>();
+    *data->specifics.mutable_typed_url() = specifics;
+    return data;
   }
 
   EntityChangeList CreateEntityChangeList(
diff --git a/components/metrics/file_metrics_provider.cc b/components/metrics/file_metrics_provider.cc
index 938cc89..06d1fc2 100644
--- a/components/metrics/file_metrics_provider.cc
+++ b/components/metrics/file_metrics_provider.cc
@@ -79,21 +79,6 @@
   }
 };
 
-enum EmbeddedProfileResult : int {
-  EMBEDDED_PROFILE_ATTEMPT,
-  EMBEDDED_PROFILE_FOUND,
-  EMBEDDED_PROFILE_FALLBACK,
-  EMBEDDED_PROFILE_DROPPED,
-  EMBEDDED_PROFILE_WAS_BASE,
-  EMBEDDED_PROFILE_WAS_FULL,
-  EMBEDDED_PROFILE_ACTION_MAX
-};
-
-void RecordEmbeddedProfileResult(EmbeddedProfileResult result) {
-  UMA_HISTOGRAM_ENUMERATION("UMA.FileMetricsProvider.EmbeddedProfileResult",
-                            result, EMBEDDED_PROFILE_ACTION_MAX);
-}
-
 void DeleteFileWhenPossible(const base::FilePath& path) {
   // Open (with delete) and then immediately close the file by going out of
   // scope. This is the only cross-platform safe way to delete a file that may
@@ -635,33 +620,13 @@
     SourceInfo* source,
     SystemProfileProto* system_profile_proto,
     base::HistogramSnapshotManager* snapshot_manager) {
-  RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT);
   if (PersistentSystemProfile::GetSystemProfile(
           *source->allocator->memory_allocator(), system_profile_proto)) {
     system_profile_proto->mutable_stability()->set_from_previous_run(true);
     RecordHistogramSnapshotsFromSource(snapshot_manager, source);
-    RecordEmbeddedProfileResult(EMBEDDED_PROFILE_FOUND);
-
-    if (system_profile_proto->hardware().has_cpu()) {
-      RecordEmbeddedProfileResult(EMBEDDED_PROFILE_WAS_FULL);
-    } else {
-      RecordEmbeddedProfileResult(EMBEDDED_PROFILE_WAS_BASE);
-    }
     return true;
   }
 
-  RecordEmbeddedProfileResult(EMBEDDED_PROFILE_DROPPED);
-
-  // TODO(bcwhite): Remove these once crbug/695880 is resolved.
-  int histogram_count = 0;
-  base::PersistentHistogramAllocator::Iterator histogram_iter(
-      source->allocator.get());
-  while (histogram_iter.GetNext()) {
-    ++histogram_count;
-  }
-  UMA_HISTOGRAM_COUNTS_10000(
-      "UMA.FileMetricsProvider.EmbeddedProfile.DroppedHistogramCount",
-      histogram_count);
   return false;
 }
 
@@ -849,8 +814,6 @@
     if (source->association == ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN) {
       if (PersistentSystemProfile::HasSystemProfile(
               *source->allocator->memory_allocator())) {
-        RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT);
-        RecordEmbeddedProfileResult(EMBEDDED_PROFILE_FALLBACK);
         sources_with_profile_.splice(sources_with_profile_.end(),
                                      sources_for_previous_run_, temp);
       }
diff --git a/components/omnibox/browser/autocomplete_match_classification.h b/components/omnibox/browser/autocomplete_match_classification.h
index a08eafad..1dad527 100644
--- a/components/omnibox/browser/autocomplete_match_classification.h
+++ b/components/omnibox/browser/autocomplete_match_classification.h
@@ -24,8 +24,8 @@
 // true, this will return "[ho]w [to] t[ie] a t[ie]."
 TermMatches FindTermMatches(base::string16 find_text,
                             base::string16 text,
-                            bool allow_prefix_matching,
-                            bool allow_mid_word_matching);
+                            bool allow_prefix_matching = true,
+                            bool allow_mid_word_matching = false);
 
 // Return an ACMatchClassifications structure given the |matches| to highlight.
 // |matches| can be retrieved from calling FindTermMatches. |text_length| should
diff --git a/components/omnibox/browser/autocomplete_provider.cc b/components/omnibox/browser/autocomplete_provider.cc
index c81612b2..ebdf86b 100644
--- a/components/omnibox/browser/autocomplete_provider.cc
+++ b/components/omnibox/browser/autocomplete_provider.cc
@@ -80,6 +80,7 @@
     const base::string16& text,
     const bool text_is_search_query,
     const ACMatchClassifications& original_class) {
+  // TODO (manukh) Move this function to autocomplete_match_classification
   DCHECK(!find_text.empty());
 
   if (text.empty())
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc
index 19e723a..1259510a 100644
--- a/components/omnibox/browser/search_provider.cc
+++ b/components/omnibox/browser/search_provider.cc
@@ -1526,8 +1526,7 @@
   match.contents = navigation.match_contents();
   match.contents_class = navigation.match_contents_class();
   match.description = navigation.description();
-  AutocompleteMatch::ClassifyMatchInString(input, match.description,
-      ACMatchClassification::NONE, &match.description_class);
+  match.description_class = navigation.description_class();
 
   match.RecordAdditionalInfo(
       kRelevanceFromServerKey,
diff --git a/components/omnibox/browser/search_suggestion_parser.cc b/components/omnibox/browser/search_suggestion_parser.cc
index 9c2831cd..9c347691 100644
--- a/components/omnibox/browser/search_suggestion_parser.cc
+++ b/components/omnibox/browser/search_suggestion_parser.cc
@@ -24,6 +24,7 @@
 #include "base/values.h"
 #include "components/omnibox/browser/autocomplete_i18n.h"
 #include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match_classification.h"
 #include "components/omnibox/browser/autocomplete_provider.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/url_prefix.h"
@@ -231,8 +232,12 @@
       description_(description) {
   DCHECK(url_.is_valid());
   CalculateAndClassifyMatchContents(true, input_text);
+  ClassifyDescription(input_text);
 }
 
+SearchSuggestionParser::NavigationResult::NavigationResult(
+    const NavigationResult& other) = default;
+
 SearchSuggestionParser::NavigationResult::~NavigationResult() {}
 
 void
@@ -286,6 +291,14 @@
   return (from_keyword_ || !keyword_provider_requested) ? 800 : 150;
 }
 
+void SearchSuggestionParser::NavigationResult::ClassifyDescription(
+    const base::string16& input_text) {
+  TermMatches term_matches = FindTermMatches(input_text, description_);
+  description_class_ = ClassifyTermMatches(term_matches, description_.size(),
+                                           ACMatchClassification::MATCH,
+                                           ACMatchClassification::NONE);
+}
+
 // SearchSuggestionParser::Results ---------------------------------------------
 
 SearchSuggestionParser::Results::Results()
diff --git a/components/omnibox/browser/search_suggestion_parser.h b/components/omnibox/browser/search_suggestion_parser.h
index 7512dfed..9e195b1 100644
--- a/components/omnibox/browser/search_suggestion_parser.h
+++ b/components/omnibox/browser/search_suggestion_parser.h
@@ -224,10 +224,14 @@
                      int relevance,
                      bool relevance_from_server,
                      const base::string16& input_text);
+    NavigationResult(const NavigationResult& other);
     ~NavigationResult() override;
 
     const GURL& url() const { return url_; }
     const base::string16& description() const { return description_; }
+    const ACMatchClassifications& description_class() const {
+      return description_class_;
+    }
     const base::string16& formatted_url() const { return formatted_url_; }
 
     // Fills in |match_contents_| and |match_contents_class_| to reflect how
@@ -242,6 +246,8 @@
                            bool keyword_provider_requested) const override;
 
    private:
+    void ClassifyDescription(const base::string16& input_text);
+
     // The suggested url for navigation.
     GURL url_;
 
@@ -251,6 +257,7 @@
 
     // The suggested navigational result description; generally the site name.
     base::string16 description_;
+    ACMatchClassifications description_class_;
   };
 
   typedef std::vector<SuggestResult> SuggestResults;
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index e563406..5f73b6e7 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -93,17 +93,12 @@
   return form;
 }
 
-// Creates an EntityData/EntityDataPtr around a copy of the given specifics.
-syncer::EntityDataPtr SpecificsToEntity(
+// Creates an EntityData around a copy of the given specifics.
+std::unique_ptr<syncer::EntityData> SpecificsToEntity(
     const sync_pb::PasswordSpecifics& specifics) {
-  syncer::EntityData data;
-  // These tests do not care about the tag hash, but EntityData and friends
-  // cannot differentiate between the default EntityData object if the hash
-  // is unset, which causes pass/copy operations to no-op and things start to
-  // break, so we throw in a junk value and forget about it.
-  data.client_tag_hash = "junk";
-  *data.specifics.mutable_password() = specifics;
-  return data.PassToPtr();
+  auto data = std::make_unique<syncer::EntityData>();
+  *data->specifics.mutable_password() = specifics;
+  return data;
 }
 
 // A mini database class the supports Add/Update/Remove functionality. It also
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index 41e56bd..5c2d5ff 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -1263,6 +1263,12 @@
   optional int32 custom_charge_stop = 3;
 }
 
+// Settings that control USB power share policy.
+message DeviceUsbPowerShareProto {
+  // Setting that controls whether USB power share is enabled on this device.
+  optional bool enabled = 1;
+}
+
 message ChromeDeviceSettingsProto {
   reserved 61;
   optional DevicePolicyRefreshRateProto device_policy_refresh_rate = 1;
@@ -1372,4 +1378,5 @@
   optional DeviceAdvancedBatteryChargeModeProto
       device_advanced_battery_charge_mode = 86;
   optional DeviceBatteryChargeModeProto device_battery_charge_mode = 87;
+  optional DeviceUsbPowerShareProto device_usb_power_share = 88;
 }
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 7b86e82..ce65aa5 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -572,6 +572,7 @@
         'DeviceBatteryChargeMode',
         'DeviceBatteryChargeCustomStartCharging',
         'DeviceBatteryChargeCustomStopCharging',
+        'DeviceUsbPowerShareEnabled'
       ],
     },
     {
@@ -15344,6 +15345,32 @@
           If this policy is left unset, boot on AC is disabled and cannot be enabled by the user.'''
     },
     {
+      'name': 'DeviceUsbPowerShareEnabled',
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:75-'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': False
+      },
+      'example_value': True,
+      'id': 553,
+      'caption': '''Enable USB power share''',
+      'tags': [],
+      'desc': '''Enable the USB power share power management policy.
+
+          Certain devices have a specific USB port marked with a lightning bolt or battery icon that can be used to charge devices like a mobile phone using the system battery. This policy affects the charging behavior of this port while the system is in the sleep and shut down modes. This policy does not affect the other USB ports and the charging behavior while the system is awake.
+
+          When awake, the USB port will always provide power.
+
+          When sleeping, if this policy is set to true, then power will be supplied to the USB port when the device is plugged into the wall charger or if the battery level is > 50%. Otherwise no power is supplied.
+
+          When shut down, if this policy is set to true, then power will be supplied to the USB port when the device is plugged into the wall charger. Otherwise no power is supplied.
+
+          If this policy is left unset, the policy is enabled and cannot be disabled by the user.'''
+    },
+    {
       'name': 'SignedHTTPExchangeEnabled',
       'type': 'main',
       'schema': { 'type': 'boolean' },
@@ -15771,5 +15798,5 @@
   },
   'placeholders': [],
   'deleted_policy_ids': [412],
-  'highest_id_currently_used':  552
+  'highest_id_currently_used':  553
 }
diff --git a/components/reading_list/core/reading_list_store_unittest.cc b/components/reading_list/core/reading_list_store_unittest.cc
index f10549b..9dfcbc5 100644
--- a/components/reading_list/core/reading_list_store_unittest.cc
+++ b/components/reading_list/core/reading_list_store_unittest.cc
@@ -199,12 +199,11 @@
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       entry.AsReadingListSpecifics();
 
-  syncer::EntityData data;
-  data.client_tag_hash = "http://read.example.com/";
-  *data.specifics.mutable_reading_list() = *specifics;
+  auto data = std::make_unique<syncer::EntityData>();
+  *data->specifics.mutable_reading_list() = *specifics;
 
   remote_input.push_back(syncer::EntityChange::CreateAdd(
-      "http://read.example.com/", data.PassToPtr()));
+      "http://read.example.com/", std::move(data)));
 
   std::unique_ptr<syncer::MetadataChangeList> metadata_changes(
       reading_list_store_->CreateMetadataChangeList());
@@ -224,14 +223,13 @@
   entry.SetRead(true, AdvanceAndGetTime(&clock_));
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       entry.AsReadingListSpecifics();
-  syncer::EntityData data;
-  data.client_tag_hash = "http://read.example.com/";
-  *data.specifics.mutable_reading_list() = *specifics;
+  auto data = std::make_unique<syncer::EntityData>();
+  *data->specifics.mutable_reading_list() = *specifics;
 
   syncer::EntityChangeList add_changes;
 
   add_changes.push_back(syncer::EntityChange::CreateAdd(
-      "http://read.example.com/", data.PassToPtr()));
+      "http://read.example.com/", std::move(data)));
   auto error = reading_list_store_->ApplySyncChanges(
       reading_list_store_->CreateMetadataChangeList(), std::move(add_changes));
   AssertCounts(1, 0, 0);
@@ -250,15 +248,14 @@
   new_entry.SetRead(true, AdvanceAndGetTime(&clock_));
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       new_entry.AsReadingListSpecifics();
-  syncer::EntityData data;
-  data.client_tag_hash = "http://unread.example.com/";
-  *data.specifics.mutable_reading_list() = *specifics;
+  auto data = std::make_unique<syncer::EntityData>();
+  *data->specifics.mutable_reading_list() = *specifics;
 
   EXPECT_CALL(processor_, Put("http://unread.example.com/", _, _));
 
   syncer::EntityChangeList add_changes;
   add_changes.push_back(syncer::EntityChange::CreateAdd(
-      "http://unread.example.com/", data.PassToPtr()));
+      "http://unread.example.com/", std::move(data)));
   auto error = reading_list_store_->ApplySyncChanges(
       reading_list_store_->CreateMetadataChangeList(), std::move(add_changes));
   AssertCounts(0, 0, 1);
@@ -280,15 +277,14 @@
 
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       old_entry.AsReadingListSpecifics();
-  syncer::EntityData data;
-  data.client_tag_hash = "http://unread.example.com/";
-  *data.specifics.mutable_reading_list() = *specifics;
+  auto data = std::make_unique<syncer::EntityData>();
+  *data->specifics.mutable_reading_list() = *specifics;
 
   EXPECT_CALL(processor_, Put("http://unread.example.com/", _, _));
 
   syncer::EntityChangeList add_changes;
   add_changes.push_back(syncer::EntityChange::CreateAdd(
-      "http://unread.example.com/", data.PassToPtr()));
+      "http://unread.example.com/", std::move(data)));
   auto error = reading_list_store_->ApplySyncChanges(
       reading_list_store_->CreateMetadataChangeList(), std::move(add_changes));
   AssertCounts(0, 0, 1);
diff --git a/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc b/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
index 2ca5793b..2fc0a51 100644
--- a/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
+++ b/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
@@ -108,7 +108,8 @@
     ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(false));
   }
 
-  syncer::EntityDataPtr MakeEntityData(const SendTabToSelfEntry& entry) {
+  std::unique_ptr<syncer::EntityData> MakeEntityData(
+      const SendTabToSelfEntry& entry) {
     SendTabToSelfLocal specifics = entry.AsLocalProto();
 
     auto entity_data = std::make_unique<syncer::EntityData>();
@@ -116,10 +117,7 @@
     *(entity_data->specifics.mutable_send_tab_to_self()) =
         specifics.specifics();
     entity_data->non_unique_name = entry.GetURL().spec();
-    // The client_tag_hash field is unused by the send_tab_to_self_bridge, but
-    // is required for a valid entity_data.
-    entity_data->client_tag_hash = "someclienttaghash";
-    return entity_data->PassToPtr();
+    return entity_data;
   }
 
   // Helper method to reduce duplicated code between tests. Wraps the given
@@ -133,12 +131,9 @@
 
       *(entity_data->specifics.mutable_send_tab_to_self()) = specifics;
       entity_data->non_unique_name = specifics.url();
-      // The client_tag_hash field is unused by the send_tab_to_self_bridge, but
-      // is required for a valid entity_data.
-      entity_data->client_tag_hash = "someclienttaghash";
 
       changes.push_back(syncer::EntityChange::CreateAdd(
-          specifics.guid(), entity_data->PassToPtr()));
+          specifics.guid(), std::move(entity_data)));
     }
     return changes;
   }
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 99e1df0f..ed89a48a 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -1079,15 +1079,14 @@
       account_id, access_token_, token_service_,
       base::BindOnce(&GaiaCookieManagerService::OnUbertokenFetchComplete,
                      base::Unretained(this)),
-      GetURLLoaderFactory(),
       base::BindRepeating(
-          [](SigninClient* client, GaiaAuthConsumer* consumer,
-             scoped_refptr<network::SharedURLLoaderFactory> url_loader)
-              -> std::unique_ptr<GaiaAuthFetcher> {
+          [](SigninClient* client,
+             scoped_refptr<network::SharedURLLoaderFactory> url_loader,
+             GaiaAuthConsumer* consumer) -> std::unique_ptr<GaiaAuthFetcher> {
             return client->CreateGaiaAuthFetcher(
                 consumer, gaia::GaiaSource::kChrome, url_loader);
           },
-          base::Unretained(signin_client_)));
+          base::Unretained(signin_client_), GetURLLoaderFactory()));
 }
 
 void GaiaCookieManagerService::StartFetchingMultiLogin(
diff --git a/components/signin/core/browser/ubertoken_fetcher_impl.cc b/components/signin/core/browser/ubertoken_fetcher_impl.cc
index deae759e..61501805 100644
--- a/components/signin/core/browser/ubertoken_fetcher_impl.cc
+++ b/components/signin/core/browser/ubertoken_fetcher_impl.cc
@@ -19,8 +19,8 @@
 namespace {
 std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
     gaia::GaiaSource source,
-    GaiaAuthConsumer* consumer,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    GaiaAuthConsumer* consumer) {
   return std::make_unique<GaiaAuthFetcher>(consumer, source,
                                            url_loader_factory);
 }
@@ -41,8 +41,9 @@
                            /*access_token=*/"",
                            token_service,
                            std::move(ubertoken_callback),
-                           url_loader_factory,
-                           base::BindRepeating(CreateGaiaAuthFetcher, source),
+                           base::BindRepeating(CreateGaiaAuthFetcher,
+                                               source,
+                                               url_loader_factory),
                            is_bound_to_channel_id) {}
 
 UbertokenFetcherImpl::UbertokenFetcherImpl(
@@ -50,13 +51,11 @@
     const std::string& access_token,
     OAuth2TokenService* token_service,
     CompletionCallback ubertoken_callback,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     GaiaAuthFetcherFactory factory,
     bool is_bound_to_channel_id)
     : OAuth2TokenService::Consumer("uber_token_fetcher"),
       token_service_(token_service),
       ubertoken_callback_(std::move(ubertoken_callback)),
-      url_loader_factory_(url_loader_factory),
       is_bound_to_channel_id_(is_bound_to_channel_id),
       gaia_auth_fetcher_factory_(factory),
       account_id_(account_id),
@@ -66,7 +65,6 @@
   DCHECK(!account_id.empty());
   DCHECK(token_service);
   DCHECK(!ubertoken_callback_.is_null());
-  DCHECK(url_loader_factory);
 
   if (access_token_.empty()) {
     RequestAccessToken();
@@ -148,8 +146,7 @@
 }
 
 void UbertokenFetcherImpl::ExchangeTokens() {
-  gaia_auth_fetcher_ =
-      gaia_auth_fetcher_factory_.Run(this, url_loader_factory_);
+  gaia_auth_fetcher_ = gaia_auth_fetcher_factory_.Run(this);
   gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(
       access_token_, is_bound_to_channel_id_);
 }
diff --git a/components/signin/core/browser/ubertoken_fetcher_impl.h b/components/signin/core/browser/ubertoken_fetcher_impl.h
index 9a07e0f..423e675f 100644
--- a/components/signin/core/browser/ubertoken_fetcher_impl.h
+++ b/components/signin/core/browser/ubertoken_fetcher_impl.h
@@ -33,8 +33,7 @@
 
 using GaiaAuthFetcherFactory =
     base::RepeatingCallback<std::unique_ptr<GaiaAuthFetcher>(
-        GaiaAuthConsumer*,
-        scoped_refptr<network::SharedURLLoaderFactory>)>;
+        GaiaAuthConsumer*)>;
 
 // Allows to retrieve an uber-auth token.
 class UbertokenFetcherImpl : public UbertokenFetcher,
@@ -49,7 +48,8 @@
                               const std::string& token)>;
 
   // Constructs an instance and starts fetching the access token and ubertoken
-  // sequencially for |account_id|.
+  // sequentially for |account_id|. Uses a default GaiaAuthFetcherFactory which
+  // returns base GaiaAuthFetcher instances.
   UbertokenFetcherImpl(
       const std::string& account_id,
       OAuth2TokenService* token_service,
@@ -64,7 +64,6 @@
       const std::string& access_token,
       OAuth2TokenService* token_service,
       CompletionCallback ubertoken_callback,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       GaiaAuthFetcherFactory factory,
       bool is_bound_to_channel_id = true);
   ~UbertokenFetcherImpl() override;
@@ -89,7 +88,6 @@
 
   OAuth2TokenService* token_service_;
   CompletionCallback ubertoken_callback_;
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   bool is_bound_to_channel_id_;  // defaults to true
   GaiaAuthFetcherFactory gaia_auth_fetcher_factory_;
   std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index bae14df..7f83b66 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -115,24 +115,6 @@
 
 jumbo_static_library("sync") {
   sources = [
-    "device_info/device_count_metrics_provider.cc",
-    "device_info/device_count_metrics_provider.h",
-    "device_info/device_info.cc",
-    "device_info/device_info.h",
-    "device_info/device_info_sync_bridge.cc",
-    "device_info/device_info_sync_bridge.h",
-    "device_info/device_info_sync_service.cc",
-    "device_info/device_info_sync_service.h",
-    "device_info/device_info_sync_service_impl.cc",
-    "device_info/device_info_sync_service_impl.h",
-    "device_info/device_info_tracker.h",
-    "device_info/device_info_util.cc",
-    "device_info/device_info_util.h",
-    "device_info/local_device_info_provider.h",
-    "device_info/local_device_info_provider_impl.cc",
-    "device_info/local_device_info_provider_impl.h",
-    "device_info/local_device_info_util.cc",
-    "device_info/local_device_info_util.h",
     "driver/about_sync_util.cc",
     "driver/about_sync_util.h",
     "driver/async_directory_type_controller.cc",
@@ -638,6 +620,46 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
+jumbo_static_library("device_info") {
+  sources = [
+    "device_info/device_count_metrics_provider.cc",
+    "device_info/device_count_metrics_provider.h",
+    "device_info/device_info.cc",
+    "device_info/device_info.h",
+    "device_info/device_info_sync_bridge.cc",
+    "device_info/device_info_sync_bridge.h",
+    "device_info/device_info_sync_service.cc",
+    "device_info/device_info_sync_service.h",
+    "device_info/device_info_sync_service_impl.cc",
+    "device_info/device_info_sync_service_impl.h",
+    "device_info/device_info_tracker.h",
+    "device_info/device_info_util.cc",
+    "device_info/device_info_util.h",
+    "device_info/local_device_info_provider.h",
+    "device_info/local_device_info_provider_impl.cc",
+    "device_info/local_device_info_provider_impl.h",
+    "device_info/local_device_info_util.cc",
+    "device_info/local_device_info_util.h",
+  ]
+
+  configs += [ "//build/config:precompiled_headers" ]
+
+  public_deps = [
+    ":base",
+    ":sync",
+    "//base",
+    "//components/sync/protocol",
+  ]
+  deps = [
+    "//components/keyed_service/core",
+    "//components/metrics",
+    "//components/version_info",
+    "//ui/base",
+  ]
+
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+}
+
 jumbo_static_library("js") {
   sources = [
     "js/js_backend.h",
@@ -1027,6 +1049,7 @@
   ]
 
   deps = [
+    ":device_info",
     ":sync",
     ":test_support_base",
     ":test_support_driver",
diff --git a/components/sync/device_info/device_info_sync_bridge_unittest.cc b/components/sync/device_info/device_info_sync_bridge_unittest.cc
index 8e178fd1..74769598 100644
--- a/components/sync/device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync/device_info/device_info_sync_bridge_unittest.cc
@@ -138,16 +138,12 @@
   return state;
 }
 
-// Creates an EntityData/EntityDataPtr around a copy of the given specifics.
-EntityDataPtr SpecificsToEntity(const DeviceInfoSpecifics& specifics) {
-  EntityData data;
-  // These tests do not care about the tag hash, but EntityData and friends
-  // cannot differentiate between the default EntityData object if the hash
-  // is unset, which causes pass/copy operations to no-op and things start to
-  // break, so we throw in a junk value and forget about it.
-  data.client_tag_hash = "junk";
-  *data.specifics.mutable_device_info() = specifics;
-  return data.PassToPtr();
+// Creates an EntityData around a copy of the given specifics.
+std::unique_ptr<EntityData> SpecificsToEntity(
+    const DeviceInfoSpecifics& specifics) {
+  auto data = std::make_unique<EntityData>();
+  *data->specifics.mutable_device_info() = specifics;
+  return data;
 }
 
 std::string CacheGuidToTag(const std::string& guid) {
@@ -202,11 +198,6 @@
     return local_device_info_.get();
   }
 
-  std::string GetSyncUserAgent() const override {
-    NOTIMPLEMENTED();
-    return std::string();
-  }
-
   std::unique_ptr<Subscription> RegisterOnInitializedCallback(
       const base::RepeatingClosure& callback) override {
     NOTIMPLEMENTED();
diff --git a/components/sync/device_info/local_device_info_provider.h b/components/sync/device_info/local_device_info_provider.h
index e8bc8e35..7d9b394 100644
--- a/components/sync/device_info/local_device_info_provider.h
+++ b/components/sync/device_info/local_device_info_provider.h
@@ -31,11 +31,6 @@
   // freed by the caller and should not be stored.
   virtual const DeviceInfo* GetLocalDeviceInfo() const = 0;
 
-  // Constructs a user agent string (ASCII) suitable for use by the syncapi
-  // for any HTTP communication. This string is used by the sync backend for
-  // classifying client types when calculating statistics.
-  virtual std::string GetSyncUserAgent() const = 0;
-
   // Registers a callback to be called when local device info becomes available.
   // The callback will remain registered until the
   // returned Subscription is destroyed, which must occur before the
diff --git a/components/sync/device_info/local_device_info_provider_impl.cc b/components/sync/device_info/local_device_info_provider_impl.cc
index 7ad6967..f9da1b2 100644
--- a/components/sync/device_info/local_device_info_provider_impl.cc
+++ b/components/sync/device_info/local_device_info_provider_impl.cc
@@ -35,11 +35,6 @@
   return local_device_info_.get();
 }
 
-std::string LocalDeviceInfoProviderImpl::GetSyncUserAgent() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return MakeUserAgentForSync(channel_);
-}
-
 std::unique_ptr<LocalDeviceInfoProvider::Subscription>
 LocalDeviceInfoProviderImpl::RegisterOnInitializedCallback(
     const base::RepeatingClosure& callback) {
@@ -54,7 +49,7 @@
   DCHECK(!cache_guid.empty());
 
   local_device_info_ = std::make_unique<DeviceInfo>(
-      cache_guid, session_name, version_, GetSyncUserAgent(),
+      cache_guid, session_name, version_, MakeUserAgentForSync(channel_),
       GetLocalDeviceType(), signin_scoped_device_id_callback_.Run());
 
   // Notify observers.
diff --git a/components/sync/device_info/local_device_info_provider_impl.h b/components/sync/device_info/local_device_info_provider_impl.h
index f8b6825..965aadc 100644
--- a/components/sync/device_info/local_device_info_provider_impl.h
+++ b/components/sync/device_info/local_device_info_provider_impl.h
@@ -34,7 +34,6 @@
   void Clear() override;
   version_info::Channel GetChannel() const override;
   const DeviceInfo* GetLocalDeviceInfo() const override;
-  std::string GetSyncUserAgent() const override;
   std::unique_ptr<Subscription> RegisterOnInitializedCallback(
       const base::RepeatingClosure& callback) override;
 
diff --git a/components/sync/device_info/local_device_info_provider_impl_unittest.cc b/components/sync/device_info/local_device_info_provider_impl_unittest.cc
index ef420c04..4903964 100644
--- a/components/sync/device_info/local_device_info_provider_impl_unittest.cc
+++ b/components/sync/device_info/local_device_info_provider_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/sync/device_info/local_device_info_provider_impl.h"
 
 #include "base/test/mock_callback.h"
+#include "components/sync/driver/sync_util.h"
 #include "components/version_info/version_string.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -56,7 +57,7 @@
   ASSERT_NE(nullptr, local_device_info);
   EXPECT_EQ(std::string(kLocalDeviceGuid), local_device_info->guid());
   EXPECT_EQ(kLocalDeviceSessionName, local_device_info->client_name());
-  EXPECT_EQ(provider_->GetSyncUserAgent(),
+  EXPECT_EQ(MakeUserAgentForSync(provider_->GetChannel()),
             local_device_info->sync_user_agent());
 
   provider_->Clear();
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc
index f786bc8..508c26a 100644
--- a/components/sync/driver/glue/sync_engine_backend.cc
+++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -18,7 +18,6 @@
 #include "components/invalidation/public/object_id_invalidation_map.h"
 #include "components/sync/base/invalidation_adapter.h"
 #include "components/sync/base/sync_base_switches.h"
-#include "components/sync/device_info/local_device_info_provider_impl.h"
 #include "components/sync/engine/cycle/commit_counters.h"
 #include "components/sync/engine/cycle/status_counters.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 401d3992..6d60b35 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -21,8 +21,6 @@
 #include "components/sync/base/report_unrecoverable_error.h"
 #include "components/sync/base/stop_source.h"
 #include "components/sync/base/sync_base_switches.h"
-#include "components/sync/device_info/device_info_sync_service.h"
-#include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/driver/backend_migrator.h"
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/directory_data_type_controller.h"
@@ -140,12 +138,12 @@
                               base::Unretained(this)),
           base::BindRepeating(&ProfileSyncService::CredentialsChanged,
                               base::Unretained(this)))),
+      channel_(init_params.channel),
       debug_identifier_(init_params.debug_identifier),
       autofill_enable_account_wallet_storage_(
           init_params.autofill_enable_account_wallet_storage),
-      sync_service_url_(GetSyncServiceURL(
-          *base::CommandLine::ForCurrentProcess(),
-          sync_client_->GetLocalDeviceInfoProvider()->GetChannel())),
+      sync_service_url_(
+          GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(), channel_)),
       crypto_(
           base::BindRepeating(&ProfileSyncService::NotifyObservers,
                               base::Unretained(this)),
@@ -196,9 +194,8 @@
                           base::Unretained(this)));
 
   sync_stopped_reporter_ = std::make_unique<SyncStoppedReporter>(
-      sync_service_url_,
-      sync_client_->GetLocalDeviceInfoProvider()->GetSyncUserAgent(),
-      url_loader_factory_, SyncStoppedReporter::ResultCallback());
+      sync_service_url_, MakeUserAgentForSync(channel_), url_loader_factory_,
+      SyncStoppedReporter::ResultCallback());
 
   if (identity_manager_)
     identity_manager_->AddObserver(this);
@@ -459,8 +456,7 @@
   params.extensions_activity = sync_client_->GetExtensionsActivity();
   params.event_handler = GetJsEventHandler();
   params.service_url = sync_service_url();
-  params.sync_user_agent =
-      sync_client_->GetLocalDeviceInfoProvider()->GetSyncUserAgent();
+  params.sync_user_agent = MakeUserAgentForSync(channel_);
   params.http_factory_getter = MakeHttpPostProviderFactoryGetter();
   params.authenticated_account_id = GetAuthenticatedAccountInfo().account_id;
   DCHECK(!params.authenticated_account_id.empty() || IsLocalSyncEnabled());
@@ -497,9 +493,8 @@
       std::make_unique<EngineComponentsFactoryImpl>(
           EngineSwitchesFromCommandLine());
   params.unrecoverable_error_handler = GetUnrecoverableErrorHandler();
-  params.report_unrecoverable_error_function = base::BindRepeating(
-      ReportUnrecoverableError,
-      sync_client_->GetLocalDeviceInfoProvider()->GetChannel());
+  params.report_unrecoverable_error_function =
+      base::BindRepeating(ReportUnrecoverableError, channel_);
   params.saved_nigori_state = crypto_.TakeSavedNigoriState();
   sync_prefs_.GetInvalidationVersions(&params.invalidation_versions);
   params.poll_interval = sync_prefs_.GetPollInterval();
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index 93e8ada..d2f621e2 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -41,6 +41,7 @@
 #include "components/sync/engine/sync_engine.h"
 #include "components/sync/engine/sync_engine_host.h"
 #include "components/sync/js/sync_js_controller.h"
+#include "components/version_info/channel.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "services/identity/public/cpp/identity_manager.h"
@@ -95,6 +96,7 @@
     NetworkTimeUpdateCallback network_time_update_callback;
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory;
     network::NetworkConnectionTracker* network_connection_tracker = nullptr;
+    version_info::Channel channel = version_info::Channel::UNKNOWN;
     std::string debug_identifier;
     bool autofill_enable_account_wallet_storage = false;
 
@@ -381,6 +383,8 @@
   // Only null after Shutdown().
   std::unique_ptr<SyncAuthManager> auth_manager_;
 
+  const version_info::Channel channel_;
+
   // An identifier representing this instance for debugging purposes.
   const std::string debug_identifier_;
 
diff --git a/components/sync/driver/profile_sync_service_bundle.cc b/components/sync/driver/profile_sync_service_bundle.cc
index 2fbb534c..10a206ae 100644
--- a/components/sync/driver/profile_sync_service_bundle.cc
+++ b/components/sync/driver/profile_sync_service_bundle.cc
@@ -22,13 +22,7 @@
 using testing::Return;
 
 ProfileSyncServiceBundle::ProfileSyncServiceBundle()
-    : local_device_info_provider_(
-          version_info::Channel::UNKNOWN,
-          "someversion",
-          /*signin_scoped_device_id_callback=*/base::BindRepeating([]() {
-            return std::string();
-          })),
-      identity_test_env_(&test_url_loader_factory_, &pref_service_) {
+    : identity_test_env_(&test_url_loader_factory_, &pref_service_) {
   SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
   identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
   identity_provider_ = std::make_unique<invalidation::ProfileIdentityProvider>(
@@ -41,8 +35,6 @@
 ProfileSyncServiceBundle::CreateSyncClientMock() {
   auto sync_client = std::make_unique<testing::NiceMock<SyncClientMock>>();
   ON_CALL(*sync_client, GetPrefService()).WillByDefault(Return(&pref_service_));
-  ON_CALL(*sync_client, GetLocalDeviceInfoProvider())
-      .WillByDefault(Return(&local_device_info_provider_));
   ON_CALL(*sync_client, GetSyncApiComponentFactory())
       .WillByDefault(Return(&component_factory_));
   // Used by control types.
diff --git a/components/sync/driver/profile_sync_service_bundle.h b/components/sync/driver/profile_sync_service_bundle.h
index c871abd..780ce1b 100644
--- a/components/sync/driver/profile_sync_service_bundle.h
+++ b/components/sync/driver/profile_sync_service_bundle.h
@@ -12,7 +12,6 @@
 #include "base/memory/ref_counted.h"
 #include "components/invalidation/impl/fake_invalidation_service.h"
 #include "components/invalidation/impl/profile_identity_provider.h"
-#include "components/sync/device_info/local_device_info_provider_impl.h"
 #include "components/sync/driver/profile_sync_service.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
 #include "components/sync/driver/sync_client_mock.h"
@@ -71,13 +70,8 @@
     return &fake_invalidation_service_;
   }
 
-  LocalDeviceInfoProvider* local_device_info_provider() {
-    return &local_device_info_provider_;
-  }
-
  private:
   sync_preferences::TestingPrefServiceSyncable pref_service_;
-  LocalDeviceInfoProviderImpl local_device_info_provider_;
   identity::IdentityTestEnvironment identity_test_env_;
   testing::NiceMock<SyncApiComponentFactoryMock> component_factory_;
   std::unique_ptr<invalidation::ProfileIdentityProvider> identity_provider_;
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h
index 63f4763..90db4a2 100644
--- a/components/sync/driver/sync_client.h
+++ b/components/sync/driver/sync_client.h
@@ -23,7 +23,6 @@
 
 namespace syncer {
 
-class LocalDeviceInfoProvider;
 class SyncApiComponentFactory;
 class SyncableService;
 class SyncService;
@@ -49,10 +48,6 @@
   // It is only used when sync is running against a local backend.
   virtual base::FilePath GetLocalSyncBackendFolder() = 0;
 
-  // Provides access to information about the local device.
-  virtual const syncer::LocalDeviceInfoProvider*
-  GetLocalDeviceInfoProvider() = 0;
-
   // Returns a vector with all supported datatypes and their controllers.
   virtual DataTypeController::TypeVector CreateDataTypeControllers(
       SyncService* sync_service) = 0;
diff --git a/components/sync/driver/sync_client_mock.h b/components/sync/driver/sync_client_mock.h
index e8f6afd..2d7d700 100644
--- a/components/sync/driver/sync_client_mock.h
+++ b/components/sync/driver/sync_client_mock.h
@@ -19,7 +19,6 @@
   MOCK_METHOD0(GetPrefService, PrefService*());
   MOCK_METHOD0(GetSyncDataPath, base::FilePath());
   MOCK_METHOD0(GetLocalSyncBackendFolder, base::FilePath());
-  MOCK_METHOD0(GetLocalDeviceInfoProvider, LocalDeviceInfoProvider*());
   MOCK_METHOD1(CreateDataTypeControllers,
                DataTypeController::TypeVector(SyncService* sync_service));
   MOCK_METHOD0(GetPasswordStateChangedCallback, base::RepeatingClosure());
diff --git a/components/sync/driver/sync_user_settings_impl.cc b/components/sync/driver/sync_user_settings_impl.cc
index 38df2d8..727b28c5 100644
--- a/components/sync/driver/sync_user_settings_impl.cc
+++ b/components/sync/driver/sync_user_settings_impl.cc
@@ -187,9 +187,13 @@
     types.RetainAll(registered_types_);
   }
 
+  static_assert(44 == ModelType::NUM_ENTRIES,
+                "If adding a new sync data type, update the list below below if"
+                " you want to disable the new data type for local sync.");
   types.PutAll(ControlTypes());
   if (prefs_->IsLocalSyncEnabled()) {
     types.Remove(APP_LIST);
+    types.Remove(SECURITY_EVENTS);
     types.Remove(USER_CONSENTS);
     types.Remove(USER_EVENTS);
   }
diff --git a/components/sync/engine/non_blocking_sync_common.h b/components/sync/engine/non_blocking_sync_common.h
index a0fc0e1..f4264b8c 100644
--- a/components/sync/engine/non_blocking_sync_common.h
+++ b/components/sync/engine/non_blocking_sync_common.h
@@ -25,7 +25,7 @@
   ~CommitRequestData();
 
   // Fields sent to the sync server.
-  EntityDataPtr entity;
+  std::unique_ptr<EntityData> entity;
   int64_t base_version = 0;
 
   // Fields not sent to the sync server. However, they are kept to be sent back
@@ -63,7 +63,7 @@
   UpdateResponseData();
   ~UpdateResponseData();
 
-  EntityDataPtr entity;
+  std::unique_ptr<EntityData> entity;
 
   int64_t response_version = 0;
   std::string encryption_key_name;
diff --git a/components/sync/engine_impl/model_type_worker.cc b/components/sync/engine_impl/model_type_worker.cc
index f3032fe..59fa5b6 100644
--- a/components/sync/engine_impl/model_type_worker.cc
+++ b/components/sync/engine_impl/model_type_worker.cc
@@ -243,21 +243,21 @@
     const sync_pb::SyncEntity& update_entity,
     UpdateResponseData* response_data) {
   response_data->response_version = update_entity.version();
-  EntityData data;
+  auto data = std::make_unique<syncer::EntityData>();
   // Prepare the message for the model thread.
-  data.id = update_entity.id_string();
-  data.client_tag_hash = update_entity.client_defined_unique_tag();
-  data.creation_time = ProtoTimeToTime(update_entity.ctime());
-  data.modification_time = ProtoTimeToTime(update_entity.mtime());
-  data.non_unique_name = update_entity.name();
-  data.is_folder = update_entity.folder();
-  data.parent_id = update_entity.parent_id_string();
+  data->id = update_entity.id_string();
+  data->client_tag_hash = update_entity.client_defined_unique_tag();
+  data->creation_time = ProtoTimeToTime(update_entity.ctime());
+  data->modification_time = ProtoTimeToTime(update_entity.mtime());
+  data->non_unique_name = update_entity.name();
+  data->is_folder = update_entity.folder();
+  data->parent_id = update_entity.parent_id_string();
 
   // Handle deprecated positioning fields. Relevant only for bookmarks.
   bool has_position_scheme = false;
   SyncPositioningScheme sync_positioning_scheme;
   if (update_entity.has_unique_position()) {
-    data.unique_position = update_entity.unique_position();
+    data->unique_position = update_entity.unique_position();
     has_position_scheme = true;
     sync_positioning_scheme = SyncPositioningScheme::UNIQUE_POSITION;
   } else if (update_entity.has_position_in_parent() ||
@@ -278,7 +278,7 @@
                       update_entity.originator_client_item_id());
 
     if (update_entity.has_position_in_parent()) {
-      data.unique_position =
+      data->unique_position =
           UniquePosition::FromInt64(update_entity.position_in_parent(), suffix)
               .ToProto();
       has_position_scheme = true;
@@ -286,7 +286,7 @@
     } else {
       // If update_entity has insert_after_item_id, use 0 index.
       DCHECK(update_entity.has_insert_after_item_id());
-      data.unique_position = UniquePosition::FromInt64(0, suffix).ToProto();
+      data->unique_position = UniquePosition::FromInt64(0, suffix).ToProto();
       has_position_scheme = true;
       sync_positioning_scheme = SyncPositioningScheme::INSERT_AFTER_ITEM_ID;
     }
@@ -303,10 +303,10 @@
 
   // Populate |originator_cache_guid| and |originator_client_item_id|. This is
   // relevant only for bookmarks.
-  data.originator_cache_guid = update_entity.originator_cache_guid();
-  data.originator_client_item_id = update_entity.originator_client_item_id();
+  data->originator_cache_guid = update_entity.originator_cache_guid();
+  data->originator_client_item_id = update_entity.originator_client_item_id();
 
-  data.server_defined_unique_tag = update_entity.server_defined_unique_tag();
+  data->server_defined_unique_tag = update_entity.server_defined_unique_tag();
 
   // Deleted entities must use the default instance of EntitySpecifics in
   // order for EntityData to correctly reflect that they are deleted.
@@ -324,38 +324,39 @@
     // Make sure the worker defers password entities if the encryption key
     // hasn't been received yet.
     if (!cryptographer->CanDecrypt(specifics.password().encrypted())) {
-      data.specifics = specifics;
-      response_data->entity = data.PassToPtr();
+      data->specifics = specifics;
+      response_data->entity = std::move(data);
       return DECRYPTION_PENDING;
     }
     response_data->encryption_key_name =
         specifics.password().encrypted().key_name();
-    if (!DecryptPasswordSpecifics(*cryptographer, specifics, &data.specifics)) {
+    if (!DecryptPasswordSpecifics(*cryptographer, specifics,
+                                  &data->specifics)) {
       return FAILED_TO_DECRYPT;
     }
-    response_data->entity = data.PassToPtr();
+    response_data->entity = std::move(data);
     return SUCCESS;
   }
 
   // Check if specifics are encrypted and try to decrypt if so.
   if (!specifics.has_encrypted()) {
     // No encryption.
-    data.specifics = specifics;
-    response_data->entity = data.PassToPtr();
+    data->specifics = specifics;
+    response_data->entity = std::move(data);
     return SUCCESS;
   }
   if (cryptographer && cryptographer->CanDecrypt(specifics.encrypted())) {
     // Encrypted and we know the key.
-    if (!DecryptSpecifics(*cryptographer, specifics, &data.specifics)) {
+    if (!DecryptSpecifics(*cryptographer, specifics, &data->specifics)) {
       return FAILED_TO_DECRYPT;
     }
-    response_data->entity = data.PassToPtr();
+    response_data->entity = std::move(data);
     response_data->encryption_key_name = specifics.encrypted().key_name();
     return SUCCESS;
   }
   // Can't decrypt right now.
-  data.specifics = specifics;
-  response_data->entity = data.PassToPtr();
+  data->specifics = specifics;
+  response_data->entity = std::move(data);
   return DECRYPTION_PENDING;
 }
 
@@ -569,32 +570,32 @@
   for (auto it = entries_pending_decryption_.begin();
        it != entries_pending_decryption_.end();) {
     const UpdateResponseData& encrypted_update = *it->second;
-    EntityDataPtr data = encrypted_update.entity;
+    const EntityData& data = *encrypted_update.entity;
 
     sync_pb::EntitySpecifics specifics;
     std::string encryption_key_name;
 
-    if (data->specifics.password().has_encrypted()) {
-      encryption_key_name = data->specifics.password().encrypted().key_name();
-      if (!cryptographer_->CanDecrypt(data->specifics.password().encrypted())) {
+    if (data.specifics.password().has_encrypted()) {
+      encryption_key_name = data.specifics.password().encrypted().key_name();
+      if (!cryptographer_->CanDecrypt(data.specifics.password().encrypted())) {
         ++it;
         continue;
       }
-      if (!DecryptPasswordSpecifics(*cryptographer_, data->specifics,
+      if (!DecryptPasswordSpecifics(*cryptographer_, data.specifics,
                                     &specifics)) {
         ++it;
         continue;
       }
     } else {
-      DCHECK(data->specifics.has_encrypted());
-      encryption_key_name = data->specifics.encrypted().key_name();
+      DCHECK(data.specifics.has_encrypted());
+      encryption_key_name = data.specifics.encrypted().key_name();
 
-      if (!cryptographer_->CanDecrypt(data->specifics.encrypted())) {
+      if (!cryptographer_->CanDecrypt(data.specifics.encrypted())) {
         ++it;
         continue;
       }
 
-      if (!DecryptSpecifics(*cryptographer_, data->specifics, &specifics)) {
+      if (!DecryptSpecifics(*cryptographer_, data.specifics, &specifics)) {
         // Decryption error should be permanent (e.g. corrupt data), since
         // CanDecrypt() above claims decryption keys are up-to-date. Let's
         // ignore this update to avoid blocking other updates.
@@ -606,7 +607,8 @@
     auto decrypted_update = std::make_unique<UpdateResponseData>();
     decrypted_update->response_version = encrypted_update.response_version;
     decrypted_update->encryption_key_name = encryption_key_name;
-    decrypted_update->entity = data->UpdateSpecifics(specifics);
+    decrypted_update->entity = std::move(it->second->entity);
+    decrypted_update->entity->specifics = std::move(specifics);
     pending_updates_.push_back(std::move(decrypted_update));
     it = entries_pending_decryption_.erase(it);
   }
diff --git a/components/sync/engine_impl/model_type_worker_unittest.cc b/components/sync/engine_impl/model_type_worker_unittest.cc
index c2cf7872..b36800af 100644
--- a/components/sync/engine_impl/model_type_worker_unittest.cc
+++ b/components/sync/engine_impl/model_type_worker_unittest.cc
@@ -730,7 +730,7 @@
 
   ASSERT_TRUE(processor()->HasUpdateResponse(kHash1));
   const UpdateResponseData& update = processor()->GetUpdateResponse(kHash1);
-  const EntityData& entity = update.entity.value();
+  const EntityData& entity = *update.entity;
 
   EXPECT_FALSE(entity.id.empty());
   EXPECT_EQ(tag_hash, entity.client_tag_hash);
@@ -1465,7 +1465,7 @@
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(&cryptographer, entity,
                                                         &response_data));
-  const EntityData& data = response_data.entity.value();
+  const EntityData& data = *response_data.entity;
   EXPECT_FALSE(data.id.empty());
   EXPECT_FALSE(data.parent_id.empty());
   EXPECT_FALSE(data.is_folder);
@@ -1501,7 +1501,7 @@
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(&cryptographer, entity,
                                                         &response_data));
-  const EntityData& data = response_data.entity.value();
+  const EntityData& data = *response_data.entity;
   EXPECT_TRUE(
       syncer::UniquePosition::FromProto(data.unique_position).IsValid());
 
@@ -1529,7 +1529,7 @@
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(&cryptographer, entity,
                                                         &response_data));
-  const EntityData& data = response_data.entity.value();
+  const EntityData& data = *response_data.entity;
   EXPECT_TRUE(
       syncer::UniquePosition::FromProto(data.unique_position).IsValid());
   histogram_tester.ExpectUniqueSample(
@@ -1559,7 +1559,7 @@
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(&cryptographer, entity,
                                                         &response_data));
-  const EntityData& data = response_data.entity.value();
+  const EntityData& data = *response_data.entity;
   EXPECT_FALSE(
       syncer::UniquePosition::FromProto(data.unique_position).IsValid());
   histogram_tester.ExpectUniqueSample("Sync.Entities.PositioningScheme",
@@ -1584,7 +1584,7 @@
   EXPECT_EQ(ModelTypeWorker::SUCCESS,
             ModelTypeWorker::PopulateUpdateResponseData(&cryptographer, entity,
                                                         &response_data));
-  const EntityData& data = response_data.entity.value();
+  const EntityData& data = *response_data.entity;
   EXPECT_FALSE(
       syncer::UniquePosition::FromProto(data.unique_position).IsValid());
   histogram_tester.ExpectTotalCount("Sync.Entities.PositioningScheme",
diff --git a/components/sync/engine_impl/non_blocking_type_commit_contribution.cc b/components/sync/engine_impl/non_blocking_type_commit_contribution.cc
index b7838704..93c9bfe4 100644
--- a/components/sync/engine_impl/non_blocking_type_commit_contribution.cc
+++ b/components/sync/engine_impl/non_blocking_type_commit_contribution.cc
@@ -180,7 +180,7 @@
 void NonBlockingTypeCommitContribution::PopulateCommitProto(
     const CommitRequestData& commit_entity,
     sync_pb::SyncEntity* commit_proto) {
-  const EntityData& entity_data = commit_entity.entity.value();
+  const EntityData& entity_data = *commit_entity.entity;
   commit_proto->set_id_string(entity_data.id);
   // Populate client_defined_unique_tag only for non-bookmark data types.
   if (!entity_data.specifics.has_bookmark()) {
diff --git a/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc b/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
index 01ddc51..285a3799 100644
--- a/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
+++ b/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
@@ -52,23 +52,23 @@
   base::Time modification_time =
       creation_time + base::TimeDelta::FromSeconds(1);
 
-  EntityData data;
+  auto data = std::make_unique<syncer::EntityData>();
 
-  data.client_tag_hash = kTag;
-  data.specifics = GeneratePreferenceSpecifics(kTag, kValue);
+  data->client_tag_hash = kTag;
+  data->specifics = GeneratePreferenceSpecifics(kTag, kValue);
 
   // These fields are not really used for much, but we set them anyway
   // to make this item look more realistic.
-  data.creation_time = creation_time;
-  data.modification_time = modification_time;
-  data.non_unique_name = "Name:";
+  data->creation_time = creation_time;
+  data->modification_time = modification_time;
+  data->non_unique_name = "Name:";
 
   CommitRequestData request_data;
-  request_data.entity = data.PassToPtr();
   request_data.sequence_number = 2;
   request_data.base_version = kBaseVersion;
-  base::Base64Encode(base::SHA1HashString(data.specifics.SerializeAsString()),
+  base::Base64Encode(base::SHA1HashString(data->specifics.SerializeAsString()),
                      &request_data.specifics_hash);
+  request_data.entity = std::move(data);
 
   SyncEntity entity;
   NonBlockingTypeCommitContribution::PopulateCommitProto(request_data, &entity);
@@ -95,28 +95,28 @@
   base::Time modification_time =
       creation_time + base::TimeDelta::FromSeconds(1);
 
-  EntityData data;
+  auto data = std::make_unique<syncer::EntityData>();
 
-  data.id = "bookmark";
-  data.specifics = GenerateBookmarkSpecifics(kURL, kTitle);
+  data->id = "bookmark";
+  data->specifics = GenerateBookmarkSpecifics(kURL, kTitle);
 
   // These fields are not really used for much, but we set them anyway
   // to make this item look more realistic.
-  data.creation_time = creation_time;
-  data.modification_time = modification_time;
-  data.non_unique_name = "Name:";
-  data.parent_id = "ParentOf:";
-  data.is_folder = true;
+  data->creation_time = creation_time;
+  data->modification_time = modification_time;
+  data->non_unique_name = "Name:";
+  data->parent_id = "ParentOf:";
+  data->is_folder = true;
   syncer::UniquePosition uniquePosition = syncer::UniquePosition::FromInt64(
       10, syncer::UniquePosition::RandomSuffix());
-  data.unique_position = uniquePosition.ToProto();
+  data->unique_position = uniquePosition.ToProto();
 
   CommitRequestData request_data;
-  request_data.entity = data.PassToPtr();
   request_data.sequence_number = 2;
   request_data.base_version = kBaseVersion;
-  base::Base64Encode(base::SHA1HashString(data.specifics.SerializeAsString()),
+  base::Base64Encode(base::SHA1HashString(data->specifics.SerializeAsString()),
                      &request_data.specifics_hash);
+  request_data.entity = std::move(data);
 
   SyncEntity entity;
   NonBlockingTypeCommitContribution::PopulateCommitProto(request_data, &entity);
@@ -145,21 +145,21 @@
   const std::string kSignonRealm = "signon_realm";
   const int64_t kBaseVersion = 7;
 
-  EntityData data;
-  data.client_tag_hash = kTag;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->client_tag_hash = kTag;
   sync_pb::PasswordSpecificsData* password_data =
-      data.specifics.mutable_password()->mutable_client_only_encrypted_data();
+      data->specifics.mutable_password()->mutable_client_only_encrypted_data();
   password_data->set_signon_realm(kSignonRealm);
 
-  data.specifics.mutable_password()->mutable_unencrypted_metadata()->set_url(
+  data->specifics.mutable_password()->mutable_unencrypted_metadata()->set_url(
       kMetadataUrl);
 
   auto request_data = std::make_unique<CommitRequestData>();
-  request_data->entity = data.PassToPtr();
   request_data->sequence_number = 2;
   request_data->base_version = kBaseVersion;
-  base::Base64Encode(base::SHA1HashString(data.specifics.SerializeAsString()),
+  base::Base64Encode(base::SHA1HashString(data->specifics.SerializeAsString()),
                      &request_data->specifics_hash);
+  request_data->entity = std::move(data);
 
   base::ObserverList<TypeDebugInfoObserver>::Unchecked observers;
   DataTypeDebugInfoEmitter debug_info_emitter(PASSWORDS, &observers);
@@ -207,21 +207,21 @@
   const std::string kSignonRealm = "signon_realm";
   const int64_t kBaseVersion = 7;
 
-  EntityData data;
-  data.client_tag_hash = kTag;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->client_tag_hash = kTag;
   sync_pb::PasswordSpecificsData* password_data =
-      data.specifics.mutable_password()->mutable_client_only_encrypted_data();
+      data->specifics.mutable_password()->mutable_client_only_encrypted_data();
   password_data->set_signon_realm(kSignonRealm);
 
-  data.specifics.mutable_password()->mutable_unencrypted_metadata()->set_url(
+  data->specifics.mutable_password()->mutable_unencrypted_metadata()->set_url(
       kMetadataUrl);
 
   auto request_data = std::make_unique<CommitRequestData>();
-  request_data->entity = data.PassToPtr();
   request_data->sequence_number = 2;
   request_data->base_version = kBaseVersion;
-  base::Base64Encode(base::SHA1HashString(data.specifics.SerializeAsString()),
+  base::Base64Encode(base::SHA1HashString(data->specifics.SerializeAsString()),
                      &request_data->specifics_hash);
+  request_data->entity = std::move(data);
 
   base::ObserverList<TypeDebugInfoObserver>::Unchecked observers;
   DataTypeDebugInfoEmitter debug_info_emitter(PASSWORDS, &observers);
diff --git a/components/sync/engine_impl/uss_migrator_unittest.cc b/components/sync/engine_impl/uss_migrator_unittest.cc
index 1470187..dfd0a50 100644
--- a/components/sync/engine_impl/uss_migrator_unittest.cc
+++ b/components/sync/engine_impl/uss_migrator_unittest.cc
@@ -137,7 +137,7 @@
   const UpdateResponseData* update =
       std::move(processor()->GetNthUpdateResponse(0).at(0));
   ASSERT_TRUE(update);
-  const EntityData& entity = update->entity.value();
+  const EntityData& entity = *update->entity;
 
   EXPECT_FALSE(entity.id.empty());
   EXPECT_EQ(kHash1, entity.client_tag_hash);
@@ -169,11 +169,11 @@
   std::vector<const UpdateResponseData*> updates =
       processor()->GetNthUpdateResponse(0);
   ASSERT_TRUE(updates.at(0));
-  EXPECT_EQ(kTag1, updates.at(0)->entity.value().specifics.preference().name());
+  EXPECT_EQ(kTag1, updates.at(0)->entity->specifics.preference().name());
   ASSERT_TRUE(updates.at(1));
-  EXPECT_EQ(kTag2, updates.at(1)->entity.value().specifics.preference().name());
+  EXPECT_EQ(kTag2, updates.at(1)->entity->specifics.preference().name());
   ASSERT_TRUE(updates.at(2));
-  EXPECT_EQ(kTag3, updates.at(2)->entity.value().specifics.preference().name());
+  EXPECT_EQ(kTag3, updates.at(2)->entity->specifics.preference().name());
 
   const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
   EXPECT_EQ(kToken1, state.progress_marker().token());
@@ -203,11 +203,11 @@
   std::vector<const UpdateResponseData*> updates =
       processor()->GetNthUpdateResponse(0);
   ASSERT_TRUE(updates.at(0));
-  EXPECT_EQ(kTag1, updates.at(0)->entity.value().specifics.preference().name());
+  EXPECT_EQ(kTag1, updates.at(0)->entity->specifics.preference().name());
   ASSERT_TRUE(updates.at(1));
-  EXPECT_EQ(kTag2, updates.at(1)->entity.value().specifics.preference().name());
+  EXPECT_EQ(kTag2, updates.at(1)->entity->specifics.preference().name());
   ASSERT_TRUE(updates.at(2));
-  EXPECT_EQ(kTag3, updates.at(2)->entity.value().specifics.preference().name());
+  EXPECT_EQ(kTag3, updates.at(2)->entity->specifics.preference().name());
 
   const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
   EXPECT_EQ(kToken1, state.progress_marker().token());
diff --git a/components/sync/model/entity_change.cc b/components/sync/model/entity_change.cc
index 7bb572f..b7726d3 100644
--- a/components/sync/model/entity_change.cc
+++ b/components/sync/model/entity_change.cc
@@ -4,6 +4,8 @@
 
 #include "components/sync/model/entity_change.h"
 
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 
 namespace syncer {
@@ -11,28 +13,30 @@
 // static
 std::unique_ptr<EntityChange> EntityChange::CreateAdd(
     const std::string& storage_key,
-    EntityDataPtr data) {
-  return base::WrapUnique(new EntityChange(storage_key, ACTION_ADD, data));
+    std::unique_ptr<EntityData> data) {
+  return base::WrapUnique(
+      new EntityChange(storage_key, ACTION_ADD, std::move(data)));
 }
 
 // static
 std::unique_ptr<EntityChange> EntityChange::CreateUpdate(
     const std::string& storage_key,
-    EntityDataPtr data) {
-  return base::WrapUnique(new EntityChange(storage_key, ACTION_UPDATE, data));
+    std::unique_ptr<EntityData> data) {
+  return base::WrapUnique(
+      new EntityChange(storage_key, ACTION_UPDATE, std::move(data)));
 }
 
 // static
 std::unique_ptr<EntityChange> EntityChange::CreateDelete(
     const std::string& storage_key) {
   return base::WrapUnique(
-      new EntityChange(storage_key, ACTION_DELETE, EntityDataPtr()));
+      new EntityChange(storage_key, ACTION_DELETE, nullptr));
 }
 
 EntityChange::EntityChange(const std::string& storage_key,
                            ChangeType type,
-                           EntityDataPtr data)
-    : storage_key_(storage_key), type_(type), data_(data) {}
+                           std::unique_ptr<EntityData> data)
+    : storage_key_(storage_key), type_(type), data_(std::move(data)) {}
 
 EntityChange::~EntityChange() {}
 
diff --git a/components/sync/model/entity_change.h b/components/sync/model/entity_change.h
index 6e3d228..01ec2893 100644
--- a/components/sync/model/entity_change.h
+++ b/components/sync/model/entity_change.h
@@ -18,11 +18,12 @@
  public:
   enum ChangeType { ACTION_ADD, ACTION_UPDATE, ACTION_DELETE };
 
-  static std::unique_ptr<EntityChange> CreateAdd(const std::string& storage_key,
-                                                 EntityDataPtr data);
+  static std::unique_ptr<EntityChange> CreateAdd(
+      const std::string& storage_key,
+      std::unique_ptr<EntityData> data);
   static std::unique_ptr<EntityChange> CreateUpdate(
       const std::string& storage_key,
-      EntityDataPtr data);
+      std::unique_ptr<EntityData> data);
   static std::unique_ptr<EntityChange> CreateDelete(
       const std::string& storage_key);
 
@@ -30,16 +31,16 @@
 
   std::string storage_key() const { return storage_key_; }
   ChangeType type() const { return type_; }
-  const EntityData& data() const { return data_.value(); }
+  const EntityData& data() const { return *data_; }
 
  private:
   EntityChange(const std::string& storage_key,
                ChangeType type,
-               EntityDataPtr data);
+               std::unique_ptr<EntityData> data);
 
   std::string storage_key_;
   ChangeType type_;
-  EntityDataPtr data_;
+  std::unique_ptr<EntityData> data_;
 
   DISALLOW_COPY_AND_ASSIGN(EntityChange);
 };
diff --git a/components/sync/model/entity_data.cc b/components/sync/model/entity_data.cc
index efdeb68..e5aea6a 100644
--- a/components/sync/model/entity_data.cc
+++ b/components/sync/model/entity_data.cc
@@ -10,7 +10,7 @@
 
 #include "base/json/json_writer.h"
 #include "base/logging.h"
-#include "base/no_destructor.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/memory_usage_estimator.h"
@@ -67,39 +67,8 @@
   return *this;
 }
 
-EntityDataPtr EntityData::PassToPtr() {
-  // Check the entity is valid before passing it out.
-  DCHECK(base::IsStringUTF8(non_unique_name));
-
-  EntityDataPtr target;
-  target.swap_value(this);
-  return target;
-}
-
-EntityDataPtr EntityData::UpdateId(const std::string& new_id) const {
-  EntityData entity_data(*this);
-  entity_data.id = new_id;
-  EntityDataPtr target;
-  target.swap_value(&entity_data);
-  return target;
-}
-
-EntityDataPtr EntityData::UpdateClientTagHash(
-    const std::string& new_client_tag_hash) const {
-  EntityData entity_data(*this);
-  entity_data.client_tag_hash = new_client_tag_hash;
-  EntityDataPtr target;
-  target.swap_value(&entity_data);
-  return target;
-}
-
-EntityDataPtr EntityData::UpdateSpecifics(
-    const sync_pb::EntitySpecifics& new_specifics) const {
-  EntityData entity_data(*this);
-  entity_data.specifics = new_specifics;
-  EntityDataPtr target;
-  target.swap_value(&entity_data);
-  return target;
+std::unique_ptr<EntityData> EntityData::Clone() const {
+  return base::WrapUnique(new EntityData(*this));
 }
 
 #define ADD_TO_DICT(dict, value) \
@@ -149,19 +118,6 @@
   return memory_usage;
 }
 
-void EntityDataTraits::SwapValue(EntityData* dest, EntityData* src) {
-  std::swap(*dest, *src);
-}
-
-bool EntityDataTraits::HasValue(const EntityData& value) {
-  return !value.client_tag_hash.empty() || !value.id.empty();
-}
-
-const EntityData& EntityDataTraits::DefaultValue() {
-  static base::NoDestructor<EntityData> default_instance;
-  return *default_instance;
-}
-
 void PrintTo(const EntityData& entity_data, std::ostream* os) {
   std::string specifics;
   base::JSONWriter::WriteWithOptions(
diff --git a/components/sync/model/entity_data.h b/components/sync/model/entity_data.h
index 30a8cb7..6616740c 100644
--- a/components/sync/model/entity_data.h
+++ b/components/sync/model/entity_data.h
@@ -5,31 +5,16 @@
 #ifndef COMPONENTS_SYNC_MODEL_ENTITY_DATA_H_
 #define COMPONENTS_SYNC_MODEL_ENTITY_DATA_H_
 
-#include <iosfwd>
-#include <map>
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "components/sync/base/proto_value_ptr.h"
 #include "components/sync/protocol/sync.pb.h"
 
 namespace syncer {
 
-struct EntityData;
-
-struct EntityDataTraits {
-  static void SwapValue(EntityData* dest, EntityData* src);
-  static bool HasValue(const EntityData& value);
-  static const EntityData& DefaultValue();
-};
-
-using EntityDataPtr = ProtoValuePtr<EntityData, EntityDataTraits>;
-using EntityDataList = std::vector<EntityDataPtr>;
-
 // A light-weight container for sync entity data which represents either
 // local data created on the local model side or remote data created on
 // ModelTypeWorker.
@@ -42,6 +27,8 @@
 
   EntityData& operator=(EntityData&&);
 
+  std::unique_ptr<EntityData> Clone() const;
+
   // Typically this is a server assigned sync ID, although for a local change
   // that represents a new entity this field might be either empty or contain
   // a temporary client sync ID.
@@ -95,29 +82,6 @@
   // specifics hasn't been set.
   bool is_deleted() const { return specifics.ByteSize() == 0; }
 
-  // Transfers this struct's data to EntityDataPtr.
-  // The return value must be assigned into another EntityDataPtr.
-  EntityDataPtr PassToPtr() WARN_UNUSED_RESULT;
-
-  // Makes a copy of EntityData and updates its id to |new_id|. This is needed
-  // when entity id is updated with commit response while EntityData for next
-  // local change is cached in ProcessorEntity.
-  EntityDataPtr UpdateId(const std::string& new_id) const WARN_UNUSED_RESULT;
-
-  // Makes a copy of EntityData and updates its client tag hash to
-  // |new_client_tag_hash|. This is needed when a Wallet entity id is updated
-  // and it has no client_tag_hash.
-  // TODO(crbug.com/874001): Remove this when we have a longer term fix for
-  // wallet data.
-  EntityDataPtr UpdateClientTagHash(
-      const std::string& new_client_tag_hash) const WARN_UNUSED_RESULT;
-
-  // Makes a copy of EntityData and updates its specifics to |new_specifics|.
-  // This is needed when specifics is updated after decryption in the
-  // ModelTypeWorker::DecryptStoredEntities().
-  EntityDataPtr UpdateSpecifics(
-      const sync_pb::EntitySpecifics& new_specifics) const WARN_UNUSED_RESULT;
-
   // Dumps all info into a DictionaryValue and returns it.
   std::unique_ptr<base::DictionaryValue> ToDictionaryValue();
 
@@ -125,8 +89,7 @@
   size_t EstimateMemoryUsage() const;
 
  private:
-  // Allow copy ctor so that UpdateId and UpdateSpecifics can make a copy of
-  // this EntityData.
+  // Copy constructor is private to be used only in Clone().
   EntityData(const EntityData& src);
 
   DISALLOW_ASSIGN(EntityData);
diff --git a/components/sync/model/entity_data_unittest.cc b/components/sync/model/entity_data_unittest.cc
index 85646f3d..991a39ca5 100644
--- a/components/sync/model/entity_data_unittest.cc
+++ b/components/sync/model/entity_data_unittest.cc
@@ -24,58 +24,4 @@
   EXPECT_FALSE(data.is_deleted());
 }
 
-TEST_F(EntityDataTest, Swap) {
-  EntityData data;
-  AddDefaultFieldValue(BOOKMARKS, &data.specifics);
-  data.id = "id";
-  data.originator_cache_guid = "originator_cache_guid";
-  data.originator_client_item_id = "originator_client_item_id";
-  data.server_defined_unique_tag = "server_defined_unique_tag";
-  data.client_tag_hash = "client_tag_hash";
-  data.non_unique_name = "non_unique_name";
-  data.creation_time = base::Time::FromTimeT(10);
-  data.modification_time = base::Time::FromTimeT(20);
-  data.parent_id = "parent_id";
-  data.is_folder = true;
-
-  UniquePosition unique_position =
-      UniquePosition::InitialPosition(UniquePosition::RandomSuffix());
-
-  data.unique_position = unique_position.ToProto();
-
-  // Remember addresses of some data within EntitySpecific and UniquePosition
-  // to make sure that the underlying data isn't copied.
-  const sync_pb::BookmarkSpecifics* bookmark_specifics =
-      &data.specifics.bookmark();
-  const std::string* unique_position_value = &data.unique_position.value();
-
-  EntityDataPtr ptr(data.PassToPtr());
-
-  // Compare addresses of the data wrapped by EntityDataPtr to make sure that
-  // the underlying objects are exactly the same.
-  EXPECT_EQ(bookmark_specifics, &ptr->specifics.bookmark());
-  EXPECT_EQ(unique_position_value, &ptr->unique_position.value());
-
-  // Compare other fields.
-  EXPECT_EQ("id", ptr->id);
-  EXPECT_EQ("originator_cache_guid", ptr->originator_cache_guid);
-  EXPECT_EQ("originator_client_item_id", ptr->originator_client_item_id);
-  EXPECT_EQ("server_defined_unique_tag", ptr->server_defined_unique_tag);
-  EXPECT_EQ("client_tag_hash", ptr->client_tag_hash);
-  EXPECT_EQ("non_unique_name", ptr->non_unique_name);
-  EXPECT_EQ("parent_id", ptr->parent_id);
-  EXPECT_EQ(base::Time::FromTimeT(10), ptr->creation_time);
-  EXPECT_EQ(base::Time::FromTimeT(20), ptr->modification_time);
-  EXPECT_EQ(true, ptr->is_folder);
-  EXPECT_EQ(false, data.is_folder);
-}
-
-TEST_F(EntityDataTest, UpdateClientTagHash) {
-  EntityData data;
-  ASSERT_TRUE(data.client_tag_hash.empty());
-
-  EntityDataPtr new_data(data.UpdateClientTagHash("test!"));
-  EXPECT_EQ("test!", new_data->client_tag_hash);
-}
-
 }  // namespace syncer
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index 2535885..3dab9253 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -642,8 +642,8 @@
       // wallet_data entity has a client tag.
       continue;
     }
-    update->entity = update->entity->UpdateClientTagHash(GenerateSyncableHash(
-        type, bridge->GetClientTag(update->entity.value())));
+    update->entity->client_tag_hash =
+        GenerateSyncableHash(type, bridge->GetClientTag(*update->entity));
   }
 }
 
@@ -688,9 +688,9 @@
   // has.
   bool is_initial_sync = !model_type_state_.initial_sync_done();
   if (is_initial_sync || HasClearAllDirective(model_type_state)) {
-    error = OnFullUpdateReceived(model_type_state, updates);
+    error = OnFullUpdateReceived(model_type_state, std::move(updates));
   } else {
-    error = OnIncrementalUpdateReceived(model_type_state, updates);
+    error = OnIncrementalUpdateReceived(model_type_state, std::move(updates));
     ExpireEntriesIfNeeded(model_type_state.progress_marker());
   }
 
@@ -720,9 +720,9 @@
 }
 
 ProcessorEntity* ClientTagBasedModelTypeProcessor::ProcessUpdate(
-    const UpdateResponseData& update,
+    std::unique_ptr<UpdateResponseData> update,
     EntityChangeList* entity_changes) {
-  const EntityData& data = update.entity.value();
+  const EntityData& data = *update->entity;
   const std::string& client_tag_hash = data.client_tag_hash;
 
   // Filter out updates without a client tag hash (including permanent nodes,
@@ -752,57 +752,78 @@
   }
 
   if (entity) {
-    entity->RecordEntityUpdateLatency(update.response_version, type_);
+    entity->RecordEntityUpdateLatency(update->response_version, type_);
   }
 
-  if (entity && entity->UpdateIsReflection(update.response_version)) {
+  if (entity && entity->UpdateIsReflection(update->response_version)) {
     // Seen this update before; just ignore it.
     return nullptr;
   }
 
+  // Grab a raw pointer in case the entity data needs to be cloned later if the
+  // received entity has an out of date encryption.
+  EntityData* entity_data = update->entity.get();
+
+  ConflictResolution::Type resolution_type = ConflictResolution::TYPE_SIZE;
   if (entity && entity->IsUnsynced()) {
     // Handle conflict resolution.
-    ConflictResolution::Type resolution_type =
-        ResolveConflict(update, entity, entity_changes);
+    resolution_type = ResolveConflict(*update, entity, entity_changes);
     UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict", resolution_type,
                               ConflictResolution::TYPE_SIZE);
   } else {
     // Handle simple create/delete/update.
+    base::Optional<EntityChange::ChangeType> change_type;
+
     if (entity == nullptr) {
       entity = CreateEntity(data);
-      entity_changes->push_back(
-          EntityChange::CreateAdd(entity->storage_key(), update.entity));
+      change_type = EntityChange::ACTION_ADD;
     } else if (data.is_deleted()) {
-      // The entity was deleted; inform the bridge. Note that the local data
-      // can never be deleted at this point because it would have either been
-      // acked (the add case) or pending (the conflict case).
       DCHECK(!entity->metadata().is_deleted());
-      entity_changes->push_back(
-          EntityChange::CreateDelete(entity->storage_key()));
+      change_type = EntityChange::ACTION_DELETE;
     } else if (!entity->MatchesData(data)) {
-      // Specifics have changed, so update the bridge.
-      entity_changes->push_back(
-          EntityChange::CreateUpdate(entity->storage_key(), update.entity));
+      change_type = EntityChange::ACTION_UPDATE;
     }
-    entity->RecordAcceptedUpdate(update);
+    entity->RecordAcceptedUpdate(*update);
+    // Inform the bridge about the changes if needed.
+    if (change_type) {
+      switch (change_type.value()) {
+        case EntityChange::ACTION_ADD:
+          entity_changes->push_back(EntityChange::CreateAdd(
+              entity->storage_key(), std::move(update->entity)));
+          break;
+        case EntityChange::ACTION_DELETE:
+          // The entity was deleted; inform the bridge. Note that the local data
+          // can never be deleted at this point because it would have either
+          // been acked (the add case) or pending (the conflict case).
+          entity_changes->push_back(
+              EntityChange::CreateDelete(entity->storage_key()));
+          break;
+        case EntityChange::ACTION_UPDATE:
+          // Specifics have changed, so update the bridge.
+          entity_changes->push_back(EntityChange::CreateUpdate(
+              entity->storage_key(), std::move(update->entity)));
+          break;
+      }
+    }
   }
 
   // If the received entity has out of date encryption, we schedule another
   // commit to fix it.
-  if (model_type_state_.encryption_key_name() != update.encryption_key_name) {
+  if (model_type_state_.encryption_key_name() != update->encryption_key_name) {
     DVLOG(2) << ModelTypeToString(type_) << ": Requesting re-encrypt commit "
-             << update.encryption_key_name << " -> "
+             << update->encryption_key_name << " -> "
              << model_type_state_.encryption_key_name();
 
     entity->IncrementSequenceNumber(base::Time::Now());
-    if (entity->RequiresCommitData()) {
-      // If there is no pending commit data, then either this update wasn't
+    if (resolution_type != ConflictResolution::USE_LOCAL &&
+        resolution_type != ConflictResolution::IGNORE_REMOTE_ENCRYPTION &&
+        entity->RequiresCommitData()) {
+      // If there is no pending commit data, and then either this update wasn't
       // in conflict or the remote data won; either way the remote data is
       // the right data to re-queue for commit.
-      entity->CacheCommitData(update.entity);
+      entity->CacheCommitData(entity_data->Clone());
     }
   }
-
   return entity;
 }
 
@@ -810,7 +831,7 @@
     const UpdateResponseData& update,
     ProcessorEntity* entity,
     EntityChangeList* changes) {
-  const EntityData& remote_data = update.entity.value();
+  const EntityData& remote_data = *update.entity;
 
   ConflictResolution::Type resolution_type = ConflictResolution::TYPE_SIZE;
   std::unique_ptr<EntityData> new_data;
@@ -836,7 +857,7 @@
   } else {
     // There's a real data conflict here; let the bridge resolve it.
     ConflictResolution resolution =
-        bridge_->ResolveConflict(entity->commit_data().value(), remote_data);
+        bridge_->ResolveConflict(entity->commit_data(), remote_data);
     resolution_type = resolution.type();
     new_data = resolution.ExtractData();
   }
@@ -861,8 +882,8 @@
       if (update.entity->is_deleted()) {
         changes->push_back(EntityChange::CreateDelete(entity->storage_key()));
       } else {
-        changes->push_back(
-            EntityChange::CreateUpdate(entity->storage_key(), update.entity));
+        changes->push_back(EntityChange::CreateUpdate(entity->storage_key(),
+                                                      update.entity->Clone()));
       }
       break;
     case ConflictResolution::USE_NEW:
@@ -871,8 +892,8 @@
       // Make a new pending commit to update the server.
       entity->MakeLocalChange(std::move(new_data));
       // Update the client with the new entity.
-      changes->push_back(EntityChange::CreateUpdate(entity->storage_key(),
-                                                    entity->commit_data()));
+      changes->push_back(EntityChange::CreateUpdate(
+          entity->storage_key(), entity->commit_data().Clone()));
       break;
     case ConflictResolution::TYPE_SIZE:
       NOTREACHED();
@@ -944,7 +965,7 @@
 base::Optional<ModelError>
 ClientTagBasedModelTypeProcessor::OnFullUpdateReceived(
     const sync_pb::ModelTypeState& model_type_state,
-    const UpdateResponseDataList& updates) {
+    UpdateResponseDataList updates) {
   std::unique_ptr<MetadataChangeList> metadata_changes =
       bridge_->CreateMetadataChangeList();
   DCHECK(model_ready_to_sync_);
@@ -984,9 +1005,8 @@
       continue;
     }
     if (bridge_->SupportsGetClientTag() &&
-        client_tag_hash !=
-            GenerateSyncableHash(
-                type_, bridge_->GetClientTag(update->entity.value()))) {
+        client_tag_hash != GenerateSyncableHash(
+                               type_, bridge_->GetClientTag(*update->entity))) {
       DLOG(WARNING) << "Received unexpected client tag hash: "
                     << client_tag_hash << " for " << ModelTypeToString(type_);
       continue;
@@ -1001,10 +1021,11 @@
                   << " for " << ModelTypeToString(type_);
     }
 #endif  // DCHECK_IS_ON()
-    ProcessorEntity* entity = CreateEntity(update->entity.value());
+    ProcessorEntity* entity = CreateEntity(*update->entity);
     entity->RecordAcceptedUpdate(*update);
     const std::string& storage_key = entity->storage_key();
-    entity_data.push_back(EntityChange::CreateAdd(storage_key, update->entity));
+    entity_data.push_back(
+        EntityChange::CreateAdd(storage_key, std::move(update->entity)));
     if (!storage_key.empty())
       metadata_changes->UpdateMetadata(storage_key, entity->metadata());
   }
@@ -1018,7 +1039,7 @@
 base::Optional<ModelError>
 ClientTagBasedModelTypeProcessor::OnIncrementalUpdateReceived(
     const sync_pb::ModelTypeState& model_type_state,
-    const UpdateResponseDataList& updates) {
+    UpdateResponseDataList updates) {
   DCHECK(model_ready_to_sync_);
   DCHECK(model_type_state.initial_sync_done());
 
@@ -1037,9 +1058,9 @@
   // re-encryption phase at the end.
   std::unordered_set<std::string> already_updated;
 
-  for (const std::unique_ptr<syncer::UpdateResponseData>& update : updates) {
+  for (std::unique_ptr<syncer::UpdateResponseData>& update : updates) {
     DCHECK(update);
-    ProcessorEntity* entity = ProcessUpdate(*update, &entity_changes);
+    ProcessorEntity* entity = ProcessUpdate(std::move(update), &entity_changes);
 
     if (!entity) {
       // The update is either of the following:
@@ -1115,7 +1136,7 @@
     if (entity != nullptr && entity->RequiresCommitData()) {
       // SetCommitData will update EntityData's fields with values from
       // metadata.
-      entity->SetCommitData(data.second.get());
+      entity->SetCommitData(std::move(data.second));
     }
   }
 
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h
index fcf5877..0c7fbb7 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.h
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -131,7 +131,7 @@
   // Helper function to process the update for a single entity. If a local data
   // change is required, it will be added to |entity_changes|. The return value
   // is the tracked entity, or nullptr if the update should be ignored.
-  ProcessorEntity* ProcessUpdate(const UpdateResponseData& update,
+  ProcessorEntity* ProcessUpdate(std::unique_ptr<UpdateResponseData> update,
                                  EntityChangeList* entity_changes);
 
   // Resolve a conflict between |update| and the pending commit in |entity|.
@@ -155,13 +155,13 @@
   // any server update.
   base::Optional<ModelError> OnFullUpdateReceived(
       const sync_pb::ModelTypeState& type_state,
-      const UpdateResponseDataList& updates);
+      UpdateResponseDataList updates);
 
   // Handle any incremental updates received from the server after being
   // enabled.
   base::Optional<ModelError> OnIncrementalUpdateReceived(
       const sync_pb::ModelTypeState& type_state,
-      const UpdateResponseDataList& updates);
+      UpdateResponseDataList updates);
 
   // ModelTypeSyncBridge::GetData() callback for pending loading data upon
   // GetLocalChanges call.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index 6acfdf5..dd4e2cb 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -715,7 +715,7 @@
   const CommitRequestData* tag1_request_data =
       worker()->GetLatestPendingCommitForHash(kHash1);
   ASSERT_TRUE(tag1_request_data);
-  const EntityData& tag1_data = tag1_request_data->entity.value();
+  const EntityData& tag1_data = *tag1_request_data->entity;
 
   EXPECT_EQ(kUncommittedVersion, tag1_request_data->base_version);
   EXPECT_TRUE(tag1_data.id.empty());
@@ -783,7 +783,7 @@
   EXPECT_EQ(1U, db()->metadata_count());
   ASSERT_TRUE(worker()->GetLatestPendingCommitForHash(kHash1));
   const EntityData& out_entity1 =
-      worker()->GetLatestPendingCommitForHash(kHash1)->entity.value();
+      *worker()->GetLatestPendingCommitForHash(kHash1)->entity;
   const EntityMetadata metadata_v1 = db()->GetMetadata(kKey1);
 
   EXPECT_EQ(kId1, out_entity1.id);
@@ -809,7 +809,7 @@
   EXPECT_EQ(1U, db()->metadata_count());
   ASSERT_TRUE(worker()->GetLatestPendingCommitForHash(kHash1));
   const EntityData& out_entity2 =
-      worker()->GetLatestPendingCommitForHash(kHash1)->entity.value();
+      *worker()->GetLatestPendingCommitForHash(kHash1)->entity;
   const EntityMetadata metadata_v2 = db()->GetMetadata(kKey1);
 
   EXPECT_EQ(kValue2, out_entity2.specifics.preference().value());
@@ -838,7 +838,7 @@
     const CommitRequestData* request_data_v1 =
         worker()->GetLatestPendingCommitForHash(kHash1);
     ASSERT_TRUE(request_data_v1);
-    const EntityData& data_v1 = request_data_v1->entity.value();
+    const EntityData& data_v1 = *request_data_v1->entity;
     EXPECT_EQ(data_v1.specifics.preference().value(), kValue1);
     request_data_v1_sequence_number = request_data_v1->sequence_number;
   }
@@ -865,7 +865,7 @@
   const CommitRequestData* request_data_v2 =
       worker()->GetLatestPendingCommitForHash(kHash1);
   ASSERT_TRUE(request_data_v2);
-  const EntityData& data_v2 = request_data_v2->entity.value();
+  const EntityData& data_v2 = *request_data_v2->entity;
   const EntityMetadata metadata_v2 = db()->GetMetadata(kKey1);
 
   // Test some of the relations between old and new commit requests.
@@ -912,7 +912,7 @@
   const CommitRequestData* request_data_v1 =
       worker()->GetLatestPendingCommitForHash(kHash1);
   ASSERT_TRUE(request_data_v1);
-  const EntityData& data_v1 = request_data_v1->entity.value();
+  const EntityData& data_v1 = *request_data_v1->entity;
   const EntityMetadata metadata_v1 = db()->GetMetadata(kKey1);
 
   ASSERT_TRUE(type_processor()->IsEntityUnsynced(kKey1));
@@ -936,7 +936,7 @@
   const CommitRequestData* request_data_v2 =
       worker()->GetLatestPendingCommitForHash(kHash1);
   ASSERT_TRUE(request_data_v2);
-  const EntityData& data_v2 = request_data_v2->entity.value();
+  const EntityData& data_v2 = *request_data_v2->entity;
   const EntityMetadata metadata_v2 = db()->GetMetadata(kKey1);
 
   // Test some of the relations between old and new commit requests.
@@ -1242,6 +1242,7 @@
   worker()->FailOneCommit();
   type_processor()->GetLocalChanges(
       INT_MAX, base::BindOnce(&CaptureCommitRequest, &commit_request));
+  OnCommitDataLoaded();
   EXPECT_EQ(1U, commit_request.size());
   EXPECT_EQ(kHash1, commit_request[0]->entity->client_tag_hash);
 }
@@ -1324,6 +1325,7 @@
   // server.
   EntitySpecifics specifics2 = bridge()->WriteItem(kKey1, kValue2);
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3));
+  OnCommitDataLoaded();
 
   // Updated metadata but not data; new commit request.
   EXPECT_EQ(2U, db()->data_change_count());
@@ -1348,6 +1350,7 @@
   // the server ID should be updated.
   bridge()->SetConflictResolution(ConflictResolution::UseLocal());
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3));
+  OnCommitDataLoaded();
   // In this test setup, the processor's nudge for commit immediately pulls
   // updates from the processor and list them as pending commits, so we should
   // see two commits at this point.
@@ -1357,7 +1360,7 @@
   const CommitRequestData* tag1_request_data =
       worker()->GetLatestPendingCommitForHash(kHash1);
   ASSERT_TRUE(tag1_request_data);
-  const EntityData& tag1_data = tag1_request_data->entity.value();
+  const EntityData& tag1_data = *tag1_request_data->entity;
 
   EXPECT_EQ(1, tag1_request_data->base_version);
   EXPECT_FALSE(tag1_data.id.empty());
@@ -1448,7 +1451,7 @@
 
   // Reconnect.
   OnSyncStarting();
-
+  OnCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
   EXPECT_EQ(2U, worker()->GetNthPendingCommit(0).size());
 
@@ -1621,24 +1624,20 @@
   // WriteAndAck entity to get id from the server.
   WriteItemAndAck(kKey1, kValue1);
   worker()->UpdateWithEncryptionKey("k1");
+  OnCommitDataLoaded();
+
   EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue2);
-  worker()->VerifyPendingCommits({{kHash1}});
+  worker()->VerifyPendingCommits({{kHash1}, {kHash1}});
 
   bridge()->SetConflictResolution(ConflictResolution::UseLocal());
   // Unencrypted update needs to be re-commited with key k1.
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3), 1, "");
+  OnCommitDataLoaded();
 
   // Ensure the re-commit has the correct value.
-  EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->VerifyNthPendingCommit(1, {kHash1}, {specifics});
-  EXPECT_EQ(kValue2, db()->GetValue(kKey1));
-
-  // GetData was launched as a result of GetLocalChanges call(). Since the
-  // conflict resolution encrypted all entities, no data is required.
-  // The extra pending commit should be empty.
-  OnCommitDataLoaded();
   EXPECT_EQ(3U, worker()->GetNumPendingCommits());
-  worker()->VerifyNthPendingCommit(2, {}, {});
+  worker()->VerifyNthPendingCommit(2, {kHash1}, {specifics});
+  EXPECT_EQ(kValue2, db()->GetValue(kKey1));
 }
 
 // Test that re-encrypting enqueues the right data for USE_REMOTE conflicts.
@@ -1945,6 +1944,8 @@
   update.push_back(worker()->GenerateUpdateData(kHash1, specifics1, 1, "k1"));
   worker()->UpdateWithEncryptionKey("k1", std::move(update));
 
+  OnCommitDataLoaded();
+
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
   worker()->VerifyNthPendingCommit(1, {kHash1}, {specifics2});
 }
@@ -1966,6 +1967,8 @@
   update.push_back(worker()->GenerateUpdateData(kHash1, specifics1, 1, "k1"));
   worker()->UpdateWithEncryptionKey("k1", std::move(update));
 
+  OnCommitDataLoaded();
+
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
   worker()->VerifyNthPendingCommit(1, {kHash1}, {specifics2});
 }
diff --git a/components/sync/model_impl/processor_entity.cc b/components/sync/model_impl/processor_entity.cc
index 594e5e1..663b9ed 100644
--- a/components/sync/model_impl/processor_entity.cc
+++ b/components/sync/model_impl/processor_entity.cc
@@ -80,7 +80,7 @@
   storage_key_ = storage_key;
 }
 
-void ProcessorEntity::SetCommitData(EntityData* data) {
+void ProcessorEntity::SetCommitData(std::unique_ptr<EntityData> data) {
   DCHECK(data);
   // Update data's fields from metadata.
   data->client_tag_hash = metadata_.client_tag_hash();
@@ -90,17 +90,17 @@
   data->modification_time = ProtoTimeToTime(metadata_.modification_time());
 
   commit_data_.reset();
-  CacheCommitData(data->PassToPtr());
+  CacheCommitData(std::move(data));
 }
 
-void ProcessorEntity::CacheCommitData(const EntityDataPtr& data_ptr) {
+void ProcessorEntity::CacheCommitData(std::unique_ptr<EntityData> data) {
   DCHECK(RequiresCommitData());
-  commit_data_ = data_ptr;
+  commit_data_ = std::move(data);
   DCHECK(HasCommitData());
 }
 
 bool ProcessorEntity::HasCommitData() const {
-  return !commit_data_->client_tag_hash.empty();
+  return commit_data_ && !commit_data_->client_tag_hash.empty();
 }
 
 bool ProcessorEntity::MatchesData(const EntityData& data) const {
@@ -182,7 +182,7 @@
   // update id in cached commit data.
   if (HasCommitData() && commit_data_->id != metadata_.server_id()) {
     DCHECK(commit_data_->id.empty());
-    commit_data_ = commit_data_->UpdateId(metadata_.server_id());
+    commit_data_->id = metadata_.server_id();
   }
 }
 
@@ -221,9 +221,8 @@
   metadata_.set_modification_time(TimeToProtoTime(modification_time));
   metadata_.set_is_deleted(false);
 
-  // SetCommitData will update data's fields from metadata and wrap it into
-  // immutable EntityDataPtr.
-  SetCommitData(data.get());
+  // SetCommitData will update data's fields from metadata.
+  SetCommitData(std::move(data));
 }
 
 bool ProcessorEntity::Delete() {
@@ -253,16 +252,16 @@
     DCHECK(HasCommitData());
     DCHECK_EQ(commit_data_->client_tag_hash, metadata_.client_tag_hash());
     DCHECK_EQ(commit_data_->id, metadata_.server_id());
-    request->entity = commit_data_;
+    request->entity = std::move(commit_data_);
   } else {
     // Make an EntityData with empty specifics to indicate deletion. This is
     // done lazily here to simplify loading a pending deletion on startup.
-    EntityData data;
-    data.client_tag_hash = metadata_.client_tag_hash();
-    data.id = metadata_.server_id();
-    data.creation_time = ProtoTimeToTime(metadata_.creation_time());
-    data.modification_time = ProtoTimeToTime(metadata_.modification_time());
-    request->entity = data.PassToPtr();
+    auto data = std::make_unique<syncer::EntityData>();
+    data->client_tag_hash = metadata_.client_tag_hash();
+    data->id = metadata_.server_id();
+    data->creation_time = ProtoTimeToTime(metadata_.creation_time());
+    data->modification_time = ProtoTimeToTime(metadata_.modification_time());
+    request->entity = std::move(data);
   }
 
   request->sequence_number = metadata_.sequence_number();
@@ -303,7 +302,7 @@
     // update id in cached commit data.
     if (HasCommitData() && commit_data_->id != metadata_.server_id()) {
       DCHECK(commit_data_->id.empty());
-      commit_data_ = commit_data_->UpdateId(metadata_.server_id());
+      commit_data_->id = metadata_.server_id();
     }
   }
 }
diff --git a/components/sync/model_impl/processor_entity.h b/components/sync/model_impl/processor_entity.h
index 6781526a..023d00d 100644
--- a/components/sync/model_impl/processor_entity.h
+++ b/components/sync/model_impl/processor_entity.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/time/time.h"
 #include "components/sync/base/model_type.h"
@@ -43,7 +44,7 @@
 
   const std::string& storage_key() const { return storage_key_; }
   const sync_pb::EntityMetadata& metadata() const { return metadata_; }
-  const EntityDataPtr& commit_data() const { return commit_data_; }
+  const EntityData& commit_data() { return *commit_data_; }
   base::Time unsynced_time() const { return unsynced_time_; }
 
   // Returns true if this data is out of sync with the server.
@@ -111,12 +112,10 @@
   void SetStorageKey(const std::string& storage_key);
 
   // Takes the passed commit data updates its fields with values from metadata
-  // and caches it in the instance. The data is swapped from the input struct
-  // without copying.
-  void SetCommitData(EntityData* data);
+  // and caches it in the instance.
+  void SetCommitData(std::unique_ptr<EntityData> data);
 
-  // Caches the a copy of |data_ptr|, which doesn't copy the data itself.
-  void CacheCommitData(const EntityDataPtr& data_ptr);
+  void CacheCommitData(std::unique_ptr<EntityData> data);
 
   // Check if the instance has cached commit data.
   bool HasCommitData() const;
@@ -157,9 +156,9 @@
   // Serializable Sync metadata.
   sync_pb::EntityMetadata metadata_;
 
-  // Sync data that exists for items being committed only.
-  // The data is reset once commit confirmation is received.
-  EntityDataPtr commit_data_;
+  // Sync data that exists for items being committed only. The data is moved
+  // away when sending the commit request.
+  std::unique_ptr<EntityData> commit_data_;
 
   // The sequence number of the last item sent to the sync thread.
   int64_t commit_requested_sequence_number_;
diff --git a/components/sync/model_impl/processor_entity_unittest.cc b/components/sync/model_impl/processor_entity_unittest.cc
index 9c7414b..baf1cdc 100644
--- a/components/sync/model_impl/processor_entity_unittest.cc
+++ b/components/sync/model_impl/processor_entity_unittest.cc
@@ -54,7 +54,7 @@
   data->id = id;
   data->modification_time = mtime;
   auto update = std::make_unique<UpdateResponseData>();
-  update->entity = data->PassToPtr();
+  update->entity = std::move(data);
   update->response_version = version;
   return update;
 }
@@ -72,7 +72,7 @@
   data->id = id;
   data->modification_time = mtime;
   auto update = std::make_unique<UpdateResponseData>();
-  update->entity = data->PassToPtr();
+  update->entity = std::move(data);
   update->response_version = version;
   return update;
 }
@@ -177,7 +177,7 @@
   EXPECT_FALSE(entity->UpdateIsReflection(1));
   EXPECT_TRUE(entity->HasCommitData());
 
-  EXPECT_EQ(kValue1, entity->commit_data()->specifics.preference().value());
+  EXPECT_EQ(kValue1, entity->commit_data().specifics.preference().value());
 
   // Generate a commit request. The metadata should not change.
   const sync_pb::EntityMetadata metadata_v1 = entity->metadata();
@@ -191,9 +191,8 @@
   EXPECT_FALSE(entity->RequiresCommitData());
   EXPECT_FALSE(entity->CanClearMetadata());
   EXPECT_FALSE(entity->UpdateIsReflection(1));
-  EXPECT_TRUE(entity->HasCommitData());
 
-  const EntityData& data = request.entity.value();
+  const EntityData& data = *request.entity;
   EXPECT_EQ("", data.id);
   EXPECT_EQ(kHash, data.client_tag_hash);
   EXPECT_EQ(kName, data.non_unique_name);
@@ -411,7 +410,7 @@
   EXPECT_FALSE(entity->CanClearMetadata());
   EXPECT_FALSE(entity->HasCommitData());
 
-  const EntityData& data = request.entity.value();
+  const EntityData& data = *request.entity;
   EXPECT_EQ(kId, data.id);
   EXPECT_EQ(kHash, data.client_tag_hash);
   EXPECT_EQ("", data.non_unique_name);
@@ -478,7 +477,6 @@
   EXPECT_FALSE(entity->RequiresCommitRequest());
   EXPECT_FALSE(entity->RequiresCommitData());
   EXPECT_FALSE(entity->CanClearMetadata());
-  EXPECT_TRUE(entity->HasCommitData());
 
   // Ack the first commit.
   entity->ReceiveCommitResponse(GenerateAckData(request_v1, kId, 2), false);
@@ -493,7 +491,8 @@
   EXPECT_FALSE(entity->RequiresCommitRequest());
   EXPECT_FALSE(entity->RequiresCommitData());
   EXPECT_FALSE(entity->CanClearMetadata());
-  EXPECT_TRUE(entity->HasCommitData());
+  // Commit data has been moved already to the request.
+  EXPECT_FALSE(entity->HasCommitData());
 
   // Ack the second commit.
   entity->ReceiveCommitResponse(GenerateAckData(request_v2, kId, 3), false);
@@ -546,7 +545,7 @@
   // to SetCommitData.
   entity = RestoreFromMetadata(std::move(entity_metadata));
   auto entity_data = GenerateEntityData(kHash, kName, kValue2);
-  entity->SetCommitData(entity_data.get());
+  entity->SetCommitData(std::move(entity_data));
 
   // No verification is necessary. SetCommitData shouldn't DCHECK.
 }
@@ -565,14 +564,6 @@
   ASSERT_FALSE(entity->metadata().is_deleted());
   ASSERT_TRUE(entity->metadata().server_id().empty());
 
-  {
-    // Local creation should use a temporary server ID (which in this entity
-    // involves an empty string).
-    CommitRequestData request;
-    entity->InitializeCommitRequestData(&request);
-    EXPECT_TRUE(request.entity->id.empty());
-  }
-
   // Before anything gets committed, we receive a remote tombstone, but local
   // would usually win so the remote update is ignored.
   std::unique_ptr<UpdateResponseData> tombstone =
diff --git a/components/sync/model_impl/syncable_service_based_bridge.cc b/components/sync/model_impl/syncable_service_based_bridge.cc
index cf19eca87..34c2fb3f 100644
--- a/components/sync/model_impl/syncable_service_based_bridge.cc
+++ b/components/sync/model_impl/syncable_service_based_bridge.cc
@@ -602,7 +602,7 @@
             FROM_HERE, SyncChange::ACTION_DELETE,
             SyncData::CreateRemoteData(
                 /*id=*/kInvalidNodeId, in_memory_store_[storage_key],
-                change->data().client_tag_hash));
+                /*client_tag_hash=*/""));
 
         // For tombstones, there is no actual data, which means no client tag
         // hash either, but the processor provides the storage key.
diff --git a/components/sync/test/engine/mock_model_type_processor.cc b/components/sync/test/engine/mock_model_type_processor.cc
index 95af9259..d9a15e9 100644
--- a/components/sync/test/engine/mock_model_type_processor.cc
+++ b/components/sync/test/engine/mock_model_type_processor.cc
@@ -72,24 +72,24 @@
     const sync_pb::EntitySpecifics& specifics) {
   const int64_t base_version = GetBaseVersion(tag_hash);
 
-  EntityData data;
+  auto data = std::make_unique<syncer::EntityData>();
 
   if (HasServerAssignedId(tag_hash)) {
-    data.id = GetServerAssignedId(tag_hash);
+    data->id = GetServerAssignedId(tag_hash);
   }
 
-  data.client_tag_hash = tag_hash;
-  data.specifics = specifics;
+  data->client_tag_hash = tag_hash;
+  data->specifics = specifics;
 
   // These fields are not really used for much, but we set them anyway
   // to make this item look more realistic.
-  data.creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
-  data.modification_time =
-      data.creation_time + base::TimeDelta::FromSeconds(base_version);
-  data.non_unique_name = "Name: " + tag_hash;
+  data->creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
+  data->modification_time =
+      data->creation_time + base::TimeDelta::FromSeconds(base_version);
+  data->non_unique_name = "Name: " + tag_hash;
 
   auto request_data = std::make_unique<CommitRequestData>();
-  request_data->entity = data.PassToPtr();
+  request_data->entity = std::move(data);
   request_data->sequence_number = GetNextSequenceNumber(tag_hash);
   request_data->base_version = base_version;
   base::Base64Encode(base::SHA1HashString(specifics.SerializeAsString()),
@@ -102,24 +102,24 @@
     const std::string& tag_hash) {
   const int64_t base_version = GetBaseVersion(tag_hash);
 
-  EntityData data;
+  auto data = std::make_unique<syncer::EntityData>();
 
   if (HasServerAssignedId(tag_hash)) {
-    data.id = GetServerAssignedId(tag_hash);
+    data->id = GetServerAssignedId(tag_hash);
   }
 
-  data.client_tag_hash = tag_hash;
+  data->client_tag_hash = tag_hash;
 
   // These fields have little or no effect on behavior.  We set them anyway to
   // make the test more realistic.
-  data.creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
-  data.non_unique_name = "Name deleted";
+  data->creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
+  data->non_unique_name = "Name deleted";
 
-  data.modification_time =
-      data.creation_time + base::TimeDelta::FromSeconds(base_version);
+  data->modification_time =
+      data->creation_time + base::TimeDelta::FromSeconds(base_version);
 
   auto request_data = std::make_unique<CommitRequestData>();
-  request_data->entity = data.PassToPtr();
+  request_data->entity = std::move(data);
   request_data->sequence_number = GetNextSequenceNumber(tag_hash);
   request_data->base_version = base_version;
 
diff --git a/components/sync/test/engine/mock_model_type_worker.cc b/components/sync/test/engine/mock_model_type_worker.cc
index 4916f1ae..f70ceb88 100644
--- a/components/sync/test/engine/mock_model_type_worker.cc
+++ b/components/sync/test/engine/mock_model_type_worker.cc
@@ -94,7 +94,7 @@
   ASSERT_EQ(tag_hashes.size(), list.size());
   for (size_t i = 0; i < tag_hashes.size(); i++) {
     ASSERT_TRUE(list[i]);
-    const EntityData& data = list[i]->entity.value();
+    const EntityData& data = *list[i]->entity;
     EXPECT_EQ(tag_hashes[i], data.client_tag_hash);
     EXPECT_EQ(specifics_list[i].SerializeAsString(),
               data.specifics.SerializeAsString());
@@ -166,21 +166,21 @@
     SetServerVersion(tag_hash, version);
   }
 
-  EntityData data;
-  data.id = GenerateId(tag_hash);
-  data.client_tag_hash = tag_hash;
-  data.specifics = specifics;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = GenerateId(tag_hash);
+  data->client_tag_hash = tag_hash;
+  data->specifics = specifics;
   // These elements should have no effect on behavior, but we set them anyway
   // so we can test they are properly copied around the system if we want to.
-  data.creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
-  data.modification_time =
-      data.creation_time + base::TimeDelta::FromSeconds(version);
-  data.non_unique_name = data.specifics.has_encrypted()
-                             ? "encrypted"
-                             : data.specifics.preference().name();
+  data->creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
+  data->modification_time =
+      data->creation_time + base::TimeDelta::FromSeconds(version);
+  data->non_unique_name = data->specifics.has_encrypted()
+                              ? "encrypted"
+                              : data->specifics.preference().name();
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   response_data->response_version = version;
   response_data->encryption_key_name = ekn;
 
@@ -197,18 +197,18 @@
 
 std::unique_ptr<syncer::UpdateResponseData>
 MockModelTypeWorker::GenerateTypeRootUpdateData(const ModelType& model_type) {
-  EntityData data;
-  data.id = syncer::ModelTypeToRootTag(model_type);
-  data.parent_id = "r";
-  data.server_defined_unique_tag = syncer::ModelTypeToRootTag(model_type);
-  syncer::AddDefaultFieldValue(model_type, &data.specifics);
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = syncer::ModelTypeToRootTag(model_type);
+  data->parent_id = "r";
+  data->server_defined_unique_tag = syncer::ModelTypeToRootTag(model_type);
+  syncer::AddDefaultFieldValue(model_type, &data->specifics);
   // These elements should have no effect on behavior, but we set them anyway
   // so we can test they are properly copied around the system if we want to.
-  data.creation_time = base::Time::UnixEpoch();
-  data.modification_time = base::Time::UnixEpoch();
+  data->creation_time = base::Time::UnixEpoch();
+  data->modification_time = base::Time::UnixEpoch();
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
   return response_data;
@@ -219,18 +219,18 @@
   int64_t version = old_version + 1;
   SetServerVersion(tag_hash, version);
 
-  EntityData data;
-  data.id = GenerateId(tag_hash);
-  data.client_tag_hash = tag_hash;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = GenerateId(tag_hash);
+  data->client_tag_hash = tag_hash;
   // These elements should have no effect on behavior, but we set them anyway
   // so we can test they are properly copied around the system if we want to.
-  data.creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
-  data.modification_time =
-      data.creation_time + base::TimeDelta::FromSeconds(version);
-  data.non_unique_name = "Name Non Unique";
+  data->creation_time = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
+  data->modification_time =
+      data->creation_time + base::TimeDelta::FromSeconds(version);
+  data->non_unique_name = "Name Non Unique";
 
   auto response_data = std::make_unique<UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   response_data->response_version = version;
   response_data->encryption_key_name = model_type_state_.encryption_key_name();
 
@@ -263,7 +263,7 @@
 CommitResponseData MockModelTypeWorker::SuccessfulCommitResponse(
     const CommitRequestData& request_data,
     int64_t version_offset) {
-  const EntityData& entity = request_data.entity.value();
+  const EntityData& entity = *request_data.entity;
   const std::string& client_tag_hash = entity.client_tag_hash;
 
   CommitResponseData response_data;
diff --git a/components/sync_bookmarks/bookmark_local_changes_builder.cc b/components/sync_bookmarks/bookmark_local_changes_builder.cc
index 1f3bc55..f0b7bc6 100644
--- a/components/sync_bookmarks/bookmark_local_changes_builder.cc
+++ b/components/sync_bookmarks/bookmark_local_changes_builder.cc
@@ -40,10 +40,10 @@
     DCHECK(entity->IsUnsynced());
     const sync_pb::EntityMetadata* metadata = entity->metadata();
 
-    syncer::EntityData data;
-    data.id = metadata->server_id();
-    data.creation_time = syncer::ProtoTimeToTime(metadata->creation_time());
-    data.modification_time =
+    auto data = std::make_unique<syncer::EntityData>();
+    data->id = metadata->server_id();
+    data->creation_time = syncer::ProtoTimeToTime(metadata->creation_time());
+    data->modification_time =
         syncer::ProtoTimeToTime(metadata->modification_time());
     if (!metadata->is_deleted()) {
       const bookmarks::BookmarkNode* node = entity->bookmark_node();
@@ -52,23 +52,23 @@
       const SyncedBookmarkTracker::Entity* parent_entity =
           bookmark_tracker_->GetEntityForBookmarkNode(parent);
       DCHECK(parent_entity);
-      data.parent_id = parent_entity->metadata()->server_id();
+      data->parent_id = parent_entity->metadata()->server_id();
       // TODO(crbug.com/516866): Double check that custom passphrase works well
       // with this implementation, because:
       // 1. NonBlockingTypeCommitContribution::AdjustCommitProto() clears the
       //    title out.
       // 2. Bookmarks (maybe ancient legacy bookmarks only?) use/used |name| to
       //    encode the title.
-      data.is_folder = node->is_folder();
-      data.unique_position = metadata->unique_position();
+      data->is_folder = node->is_folder();
+      data->unique_position = metadata->unique_position();
       // Assign specifics only for the non-deletion case. In case of deletion,
       // EntityData should contain empty specifics to indicate deletion.
-      data.specifics = CreateSpecificsFromBookmarkNode(
+      data->specifics = CreateSpecificsFromBookmarkNode(
           node, bookmark_model_, /*force_favicon_load=*/true);
-      data.non_unique_name = data.specifics.bookmark().title();
+      data->non_unique_name = data->specifics.bookmark().title();
     }
     auto request = std::make_unique<syncer::CommitRequestData>();
-    request->entity = data.PassToPtr();
+    request->entity = std::move(data);
     request->sequence_number = metadata->sequence_number();
     request->base_version = metadata->server_version();
     // Specifics hash has been computed in the tracker when this entity has been
diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc
index f5922ec..a4137db 100644
--- a/components/sync_bookmarks/bookmark_model_merger.cc
+++ b/components/sync_bookmarks/bookmark_model_merger.cc
@@ -98,7 +98,7 @@
 size_t FindMatchingChildFor(const UpdateResponseData* remote_node,
                             const bookmarks::BookmarkNode* local_parent,
                             size_t search_starting_child_index) {
-  const EntityData& remote_node_update_entity = remote_node->entity.value();
+  const EntityData& remote_node_update_entity = *remote_node->entity;
   for (int i = search_starting_child_index; i < local_parent->child_count();
        ++i) {
     const bookmarks::BookmarkNode* local_child = local_parent->GetChild(i);
@@ -112,9 +112,9 @@
 bool UniquePositionLessThan(const UpdateResponseData* a,
                             const UpdateResponseData* b) {
   const syncer::UniquePosition a_pos =
-      syncer::UniquePosition::FromProto(a->entity.value().unique_position);
+      syncer::UniquePosition::FromProto(a->entity->unique_position);
   const syncer::UniquePosition b_pos =
-      syncer::UniquePosition::FromProto(b->entity.value().unique_position);
+      syncer::UniquePosition::FromProto(b->entity->unique_position);
   return a_pos.LessThan(b_pos);
 }
 
@@ -139,7 +139,7 @@
   // model. Hence, we ignore tombstones.
   for (const std::unique_ptr<syncer::UpdateResponseData>& update : *updates) {
     DCHECK(update);
-    const EntityData& update_entity = update->entity.value();
+    const EntityData& update_entity = *update->entity;
     if (update_entity.is_deleted()) {
       continue;
     }
@@ -148,7 +148,7 @@
 
   for (const std::unique_ptr<UpdateResponseData>& update : *updates) {
     DCHECK(update);
-    const EntityData& update_entity = update->entity.value();
+    const EntityData& update_entity = *update->entity;
     if (update_entity.is_deleted()) {
       continue;
     }
@@ -220,7 +220,7 @@
   // Associate permanent folders.
   for (const std::unique_ptr<UpdateResponseData>& update : *updates_) {
     DCHECK(update);
-    const EntityData& update_entity = update->entity.value();
+    const EntityData& update_entity = *update->entity;
     const bookmarks::BookmarkNode* permanent_folder =
         GetPermanentFolder(update_entity);
     if (!permanent_folder) {
@@ -237,7 +237,7 @@
 void BookmarkModelMerger::MergeSubtree(
     const bookmarks::BookmarkNode* local_node,
     const UpdateResponseData* remote_update) {
-  const EntityData& remote_update_entity = remote_update->entity.value();
+  const EntityData& remote_update_entity = *remote_update->entity;
   bookmark_tracker_->Add(
       remote_update_entity.id, local_node, remote_update->response_version,
       remote_update_entity.creation_time, remote_update_entity.unique_position,
@@ -290,7 +290,7 @@
     const UpdateResponseData* remote_update,
     const bookmarks::BookmarkNode* local_parent,
     int index) {
-  const EntityData& remote_update_entity = remote_update->entity.value();
+  const EntityData& remote_update_entity = *remote_update->entity;
   const bookmarks::BookmarkNode* bookmark_node =
       CreateBookmarkNodeFromSpecifics(
           remote_update_entity.specifics.bookmark(), local_parent, index,
diff --git a/components/sync_bookmarks/bookmark_model_merger_unittest.cc b/components/sync_bookmarks/bookmark_model_merger_unittest.cc
index 4af9f09b..4fa2865 100644
--- a/components/sync_bookmarks/bookmark_model_merger_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_merger_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/strings/utf_string_conversions.h"
@@ -37,35 +38,35 @@
     const syncer::UniquePosition& unique_position,
     const std::string& icon_url = std::string(),
     const std::string& icon_data = std::string()) {
-  syncer::EntityData data;
-  data.id = server_id;
-  data.parent_id = parent_id;
-  data.unique_position = unique_position.ToProto();
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = server_id;
+  data->parent_id = parent_id;
+  data->unique_position = unique_position.ToProto();
 
   sync_pb::BookmarkSpecifics* bookmark_specifics =
-      data.specifics.mutable_bookmark();
+      data->specifics.mutable_bookmark();
   bookmark_specifics->set_title(title);
   bookmark_specifics->set_url(url);
   bookmark_specifics->set_icon_url(icon_url);
   bookmark_specifics->set_favicon(icon_data);
 
-  data.is_folder = is_folder;
+  data->is_folder = is_folder;
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
   return response_data;
 }
 
 std::unique_ptr<syncer::UpdateResponseData> CreateBookmarkBarNodeUpdateData() {
-  syncer::EntityData data;
-  data.id = kBookmarkBarId;
-  data.server_defined_unique_tag = kBookmarkBarTag;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = kBookmarkBarId;
+  data->server_defined_unique_tag = kBookmarkBarTag;
 
-  data.specifics.mutable_bookmark();
+  data->specifics.mutable_bookmark();
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
   return response_data;
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index 03bca3c..372daf8 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -11,6 +11,7 @@
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "base/trace_event/memory_usage_estimator.h"
 #include "base/trace_event/trace_event.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index 3f80973..76015ba 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -52,23 +52,23 @@
     const BookmarkInfo& bookmark_info,
     const syncer::UniquePosition& unique_position,
     int response_version) {
-  syncer::EntityData data;
-  data.id = bookmark_info.server_id;
-  data.parent_id = bookmark_info.parent_id;
-  data.server_defined_unique_tag = bookmark_info.server_tag;
-  data.unique_position = unique_position.ToProto();
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = bookmark_info.server_id;
+  data->parent_id = bookmark_info.parent_id;
+  data->server_defined_unique_tag = bookmark_info.server_tag;
+  data->unique_position = unique_position.ToProto();
 
   sync_pb::BookmarkSpecifics* bookmark_specifics =
-      data.specifics.mutable_bookmark();
+      data->specifics.mutable_bookmark();
   bookmark_specifics->set_title(bookmark_info.title);
   if (bookmark_info.url.empty()) {
-    data.is_folder = true;
+    data->is_folder = true;
   } else {
     bookmark_specifics->set_url(bookmark_info.url);
   }
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   response_data->response_version = response_version;
   return response_data;
 }
@@ -451,8 +451,9 @@
 
   // Push empty updates list to the processor together with the updated model
   // type state.
+  syncer::UpdateResponseDataList empty_updates_list;
   processor()->OnUpdateReceived(model_type_state,
-                                syncer::UpdateResponseDataList());
+                                std::move(empty_updates_list));
 
   // The model type state inside the tracker should have been updated, and
   // carries the new encryption key name.
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index 4968538..ff4500c6 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -76,7 +76,7 @@
     bookmarks::BookmarkModel* model,
     SyncedBookmarkTracker* tracker,
     favicon::FaviconService* favicon_service) {
-  const syncer::EntityData& update_entity = update.entity.value();
+  const syncer::EntityData& update_entity = *update.entity;
   DCHECK(!update_entity.is_deleted());
   DCHECK(tracked_entity);
   DCHECK(new_parent_tracked_entity);
@@ -140,7 +140,7 @@
   std::unordered_set<std::string> entities_with_up_to_date_encryption;
 
   for (const syncer::UpdateResponseData* update : ReorderUpdates(&updates)) {
-    const syncer::EntityData& update_entity = update->entity.value();
+    const syncer::EntityData& update_entity = *update->entity;
     // Only non deletions and non premanent node should have valid specifics and
     // unique positions.
     if (!update_entity.is_deleted() &&
@@ -302,7 +302,7 @@
   // Add only non-deletions to |id_to_updates|.
   for (const std::unique_ptr<syncer::UpdateResponseData>& update : *updates) {
     DCHECK(update);
-    const syncer::EntityData& update_entity = update->entity.value();
+    const syncer::EntityData& update_entity = *update->entity;
     // Ignore updates to root nodes.
     if (update_entity.parent_id == "0") {
       continue;
@@ -316,7 +316,7 @@
   // |parent_to_children|.
   for (const std::pair<base::StringPiece, const syncer::UpdateResponseData*>&
            pair : id_to_updates) {
-    const syncer::EntityData& update_entity = pair.second->entity.value();
+    const syncer::EntityData& update_entity = *pair.second->entity;
     parent_to_children[update_entity.parent_id].push_back(update_entity.id);
     // If this entity's parent has no pending update, add it to |roots|.
     if (id_to_updates.count(update_entity.parent_id) == 0) {
@@ -335,7 +335,7 @@
   // Add deletions.
   for (const std::unique_ptr<syncer::UpdateResponseData>& update : *updates) {
     DCHECK(update);
-    const syncer::EntityData& update_entity = update->entity.value();
+    const syncer::EntityData& update_entity = *update->entity;
     // Ignore updates to root nodes.
     if (update_entity.parent_id == "0") {
       root_node_updates_count++;
@@ -352,7 +352,7 @@
 
 bool BookmarkRemoteUpdatesHandler::ProcessCreate(
     const syncer::UpdateResponseData& update) {
-  const syncer::EntityData& update_entity = update.entity.value();
+  const syncer::EntityData& update_entity = *update.entity;
   DCHECK(!update_entity.is_deleted());
   if (!update_entity.server_defined_unique_tag.empty()) {
     DLOG(ERROR)
@@ -394,7 +394,7 @@
 void BookmarkRemoteUpdatesHandler::ProcessUpdate(
     const syncer::UpdateResponseData& update,
     const SyncedBookmarkTracker::Entity* tracked_entity) {
-  const syncer::EntityData& update_entity = update.entity.value();
+  const syncer::EntityData& update_entity = *update.entity;
   // Can only update existing nodes.
   DCHECK(tracked_entity);
   DCHECK_EQ(tracked_entity,
@@ -471,7 +471,7 @@
 void BookmarkRemoteUpdatesHandler::ProcessConflict(
     const syncer::UpdateResponseData& update,
     const SyncedBookmarkTracker::Entity* tracked_entity) {
-  const syncer::EntityData& update_entity = update.entity.value();
+  const syncer::EntityData& update_entity = *update.entity;
   // TODO(crbug.com/516866): Handle the case of conflict as a result of
   // re-encryption request.
 
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index abf7179..8352136 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -52,20 +52,20 @@
     bool is_deletion,
     int version,
     const syncer::UniquePosition& unique_position) {
-  syncer::EntityData data;
-  data.id = server_id;
-  data.parent_id = parent_id;
-  data.unique_position = unique_position.ToProto();
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = server_id;
+  data->parent_id = parent_id;
+  data->unique_position = unique_position.ToProto();
 
   // EntityData would be considered a deletion if its specifics hasn't been set.
   if (!is_deletion) {
     sync_pb::BookmarkSpecifics* bookmark_specifics =
-        data.specifics.mutable_bookmark();
+        data->specifics.mutable_bookmark();
     bookmark_specifics->set_title(title);
   }
-  data.is_folder = true;
+  data->is_folder = true;
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   response_data->response_version = version;
   return response_data;
 }
@@ -84,16 +84,16 @@
 }
 
 std::unique_ptr<syncer::UpdateResponseData> CreateBookmarkRootUpdateData() {
-  syncer::EntityData data;
-  data.id = syncer::ModelTypeToRootTag(syncer::BOOKMARKS);
-  data.parent_id = kRootParentId;
-  data.server_defined_unique_tag =
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = syncer::ModelTypeToRootTag(syncer::BOOKMARKS);
+  data->parent_id = kRootParentId;
+  data->server_defined_unique_tag =
       syncer::ModelTypeToRootTag(syncer::BOOKMARKS);
 
-  data.specifics.mutable_bookmark();
+  data->specifics.mutable_bookmark();
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
   return response_data;
@@ -102,15 +102,15 @@
 std::unique_ptr<syncer::UpdateResponseData> CreatePermanentFolderUpdateData(
     const std::string& id,
     const std::string& tag) {
-  syncer::EntityData data;
-  data.id = id;
-  data.parent_id = "root_id";
-  data.server_defined_unique_tag = tag;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = id;
+  data->parent_id = "root_id";
+  data->server_defined_unique_tag = tag;
 
-  data.specifics.mutable_bookmark();
+  data->specifics.mutable_bookmark();
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
   return response_data;
@@ -231,12 +231,12 @@
   // This is test is over verifying since the order requirements are
   // within subtrees only. (e.g it doesn't matter whether node1 comes before or
   // after node4). However, it's implemented this way for simplicity.
-  EXPECT_THAT(ordered_updates[0]->entity.value().id, Eq(ids[4]));
-  EXPECT_THAT(ordered_updates[1]->entity.value().id, Eq(ids[5]));
-  EXPECT_THAT(ordered_updates[2]->entity.value().id, Eq(ids[0]));
-  EXPECT_THAT(ordered_updates[3]->entity.value().id, Eq(ids[1]));
-  EXPECT_THAT(ordered_updates[4]->entity.value().id, Eq(ids[2]));
-  EXPECT_THAT(ordered_updates[5]->entity.value().id, Eq(ids[6]));
+  EXPECT_THAT(ordered_updates[0]->entity->id, Eq(ids[4]));
+  EXPECT_THAT(ordered_updates[1]->entity->id, Eq(ids[5]));
+  EXPECT_THAT(ordered_updates[2]->entity->id, Eq(ids[0]));
+  EXPECT_THAT(ordered_updates[3]->entity->id, Eq(ids[1]));
+  EXPECT_THAT(ordered_updates[4]->entity->id, Eq(ids[2]));
+  EXPECT_THAT(ordered_updates[5]->entity->id, Eq(ids[6]));
 }
 
 TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -583,22 +583,22 @@
   const GURL kIconUrl("http://www.icon-url.com");
 
   syncer::UpdateResponseDataList updates;
-  syncer::EntityData data;
-  data.id = "server_id";
-  data.parent_id = kBookmarkBarId;
-  data.unique_position = syncer::UniquePosition::InitialPosition(
-                             syncer::UniquePosition::RandomSuffix())
-                             .ToProto();
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = "server_id";
+  data->parent_id = kBookmarkBarId;
+  data->unique_position = syncer::UniquePosition::InitialPosition(
+                              syncer::UniquePosition::RandomSuffix())
+                              .ToProto();
   sync_pb::BookmarkSpecifics* bookmark_specifics =
-      data.specifics.mutable_bookmark();
+      data->specifics.mutable_bookmark();
   // Use the server id as the title for simplicity.
   bookmark_specifics->set_title(kTitle);
   bookmark_specifics->set_url(kUrl.spec());
   bookmark_specifics->set_icon_url(kIconUrl.spec());
   bookmark_specifics->set_favicon("PNG");
-  data.is_folder = false;
+  data->is_folder = false;
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
 
@@ -621,20 +621,20 @@
   const GURL kUrl("http://www.url.com");
 
   syncer::UpdateResponseDataList updates;
-  syncer::EntityData data;
-  data.id = "server_id";
-  data.parent_id = kBookmarkBarId;
-  data.unique_position = syncer::UniquePosition::InitialPosition(
-                             syncer::UniquePosition::RandomSuffix())
-                             .ToProto();
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = "server_id";
+  data->parent_id = kBookmarkBarId;
+  data->unique_position = syncer::UniquePosition::InitialPosition(
+                              syncer::UniquePosition::RandomSuffix())
+                              .ToProto();
   sync_pb::BookmarkSpecifics* bookmark_specifics =
-      data.specifics.mutable_bookmark();
+      data->specifics.mutable_bookmark();
   // Use the server id as the title for simplicity.
   bookmark_specifics->set_title(kTitle);
   bookmark_specifics->set_url(kUrl.spec());
-  data.is_folder = false;
+  data->is_folder = false;
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
 
@@ -693,19 +693,19 @@
 
   // Now receive an update with the actual server id.
   syncer::UpdateResponseDataList updates;
-  syncer::EntityData data;
-  data.id = kSyncId;
-  data.originator_cache_guid = kCacheGuid;
-  data.originator_client_item_id = kOriginatorClientItemId;
+  auto data = std::make_unique<syncer::EntityData>();
+  data->id = kSyncId;
+  data->originator_cache_guid = kCacheGuid;
+  data->originator_client_item_id = kOriginatorClientItemId;
   // Set the other required fields.
-  data.unique_position = syncer::UniquePosition::InitialPosition(
-                             syncer::UniquePosition::RandomSuffix())
-                             .ToProto();
-  data.specifics = specifics;
-  data.is_folder = true;
+  data->unique_position = syncer::UniquePosition::InitialPosition(
+                              syncer::UniquePosition::RandomSuffix())
+                              .ToProto();
+  data->specifics = specifics;
+  data->is_folder = true;
 
   auto response_data = std::make_unique<syncer::UpdateResponseData>();
-  response_data->entity = data.PassToPtr();
+  response_data->entity = std::move(data);
   // Similar to what's done in the loopback_server.
   response_data->response_version = 0;
   updates.push_back(std::move(response_data));
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index 0e621ad8..f62161d 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -51,6 +51,7 @@
   public_deps = [
     "//components/sessions",
     "//components/sync",
+    "//components/sync:device_info",
   ]
 
   deps = [
diff --git a/components/sync_sessions/session_sync_bridge_unittest.cc b/components/sync_sessions/session_sync_bridge_unittest.cc
index fe126fb..fed8de0c 100644
--- a/components/sync_sessions/session_sync_bridge_unittest.cc
+++ b/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -78,15 +78,15 @@
                                                    result_listener);
 }
 
-syncer::EntityDataPtr SpecificsToEntity(
+std::unique_ptr<syncer::EntityData> SpecificsToEntity(
     const sync_pb::SessionSpecifics& specifics,
     base::Time mtime = base::Time::Now()) {
-  syncer::EntityData data;
-  data.client_tag_hash = syncer::GenerateSyncableHash(
+  auto data = std::make_unique<syncer::EntityData>();
+  data->client_tag_hash = syncer::GenerateSyncableHash(
       syncer::SESSIONS, SessionStore::GetClientTag(specifics));
-  *data.specifics.mutable_session() = specifics;
-  data.modification_time = mtime;
-  return data.PassToPtr();
+  *data->specifics.mutable_session() = specifics;
+  data->modification_time = mtime;
+  return data;
 }
 
 std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse(
@@ -108,12 +108,13 @@
 
 std::unique_ptr<syncer::UpdateResponseData> CreateTombstone(
     const std::string& client_tag) {
-  EntityData tombstone;
-  tombstone.client_tag_hash =
+  auto tombstone = std::make_unique<syncer::EntityData>();
+
+  tombstone->client_tag_hash =
       syncer::GenerateSyncableHash(syncer::SESSIONS, client_tag);
 
   auto data = std::make_unique<syncer::UpdateResponseData>();
-  data->entity = tombstone.PassToPtr();
+  data->entity = std::move(tombstone);
   data->response_version = 2;
   return data;
 }
diff --git a/components/tracing/common/tracing_switches.cc b/components/tracing/common/tracing_switches.cc
index 26125bf..7a5eb2e 100644
--- a/components/tracing/common/tracing_switches.cc
+++ b/components/tracing/common/tracing_switches.cc
@@ -14,19 +14,6 @@
 // This flag will be ignored if --trace-startup or --trace-shutdown is provided.
 const char kTraceConfigFile[]               = "trace-config-file";
 
-// Causes TRACE_EVENT flags to be recorded beginning with shutdown. Optionally,
-// can specify the specific trace categories to include (e.g.
-// --trace-shutdown=base,net) otherwise, all events are recorded.
-// --trace-shutdown-file can be used to control where the trace log gets stored
-// to since there is otherwise no way to access the result.
-const char kTraceShutdown[]                 = "trace-shutdown";
-
-// If supplied, sets the file which shutdown tracing will be stored into, if
-// omitted the default will be used "chrometrace.log" in the current directory.
-// Has no effect unless --trace-shutdown is also supplied.
-// Example: --trace-shutdown --trace-shutdown-file=/tmp/trace_event.log
-const char kTraceShutdownFile[]             = "trace-shutdown-file";
-
 // Causes TRACE_EVENT flags to be recorded from startup. Optionally, can
 // specify the specific trace categories to include (e.g.
 // --trace-startup=base,net) otherwise, all events are recorded. Setting this
diff --git a/components/tracing/common/tracing_switches.h b/components/tracing/common/tracing_switches.h
index 4bc094be..4c5e6f1 100644
--- a/components/tracing/common/tracing_switches.h
+++ b/components/tracing/common/tracing_switches.h
@@ -11,8 +11,6 @@
 
 TRACING_EXPORT extern const char kEnableBackgroundTracing[];
 TRACING_EXPORT extern const char kTraceConfigFile[];
-TRACING_EXPORT extern const char kTraceShutdown[];
-TRACING_EXPORT extern const char kTraceShutdownFile[];
 TRACING_EXPORT extern const char kTraceStartup[];
 TRACING_EXPORT extern const char kTraceStartupDuration[];
 TRACING_EXPORT extern const char kTraceStartupFile[];
diff --git a/components/variations/field_trial_config/BUILD.gn b/components/variations/field_trial_config/BUILD.gn
index 7d29a57..02e518c4 100644
--- a/components/variations/field_trial_config/BUILD.gn
+++ b/components/variations/field_trial_config/BUILD.gn
@@ -57,9 +57,12 @@
     "//components/variations",
     "//components/variations/proto:proto",
     "//net",
+    "//ui/base",
   ]
 
-  public_deps = [ "//third_party/protobuf:protobuf_lite" ]
+  public_deps = [
+    "//third_party/protobuf:protobuf_lite",
+  ]
 }
 
 source_set("unit_tests") {
@@ -73,5 +76,6 @@
     "//base/test:test_support",
     "//components/variations",
     "//testing/gtest",
+    "//ui/base",
   ]
 }
diff --git a/components/variations/field_trial_config/DEPS b/components/variations/field_trial_config/DEPS
index 6a2f02e2..5875c613 100644
--- a/components/variations/field_trial_config/DEPS
+++ b/components/variations/field_trial_config/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+net/base",
+  "+ui/base",
 ]
diff --git a/components/variations/field_trial_config/field_trial_testing_config_schema.json b/components/variations/field_trial_config/field_trial_testing_config_schema.json
index 09e3a4b0..2d115d0 100644
--- a/components/variations/field_trial_config/field_trial_testing_config_schema.json
+++ b/components/variations/field_trial_config/field_trial_testing_config_schema.json
@@ -27,6 +27,11 @@
                 "contents": {"type": "enum", "ctype": "Study::Platform"}
               },
               {
+                "field": "form_factors",
+                "type": "array",
+                "contents": {"type": "enum", "ctype": "Study::FormFactor"}
+              },
+              {
                 "field": "is_low_end_device",
                 "type": "enum",
                 "ctype": "Study::OptionalBool",
diff --git a/components/variations/field_trial_config/field_trial_util.cc b/components/variations/field_trial_config/field_trial_util.cc
index cb2fd6a..ca28fb0 100644
--- a/components/variations/field_trial_config/field_trial_util.cc
+++ b/components/variations/field_trial_config/field_trial_util.cc
@@ -21,6 +21,7 @@
 #include "components/variations/field_trial_config/fieldtrial_testing_config.h"
 #include "components/variations/variations_associated_data.h"
 #include "net/base/escape.h"
+#include "ui/base/device_form_factor.h"
 
 namespace variations {
 namespace {
@@ -34,8 +35,8 @@
   return false;
 }
 
-// Returns true if the experiment config is has different value for
-// is_low_end_device than the current system value for this.
+// Returns true if the experiment config has a different value for
+// is_low_end_device than the current system value does.
 // If experiment has is_low_end_device missing, then it is False.
 bool HasDeviceLevelMismatch(const FieldTrialTestingExperiment& experiment) {
   if (experiment.is_low_end_device == Study::OPTIONAL_BOOL_MISSING) {
@@ -47,6 +48,29 @@
   return experiment.is_low_end_device == Study::OPTIONAL_BOOL_TRUE;
 }
 
+// Gets current form factor and converts it from enum DeviceFormFactor to enum
+// Study_FormFactor.
+Study::FormFactor _GetCurrentFormFactor() {
+  switch (ui::GetDeviceFormFactor()) {
+    case ui::DEVICE_FORM_FACTOR_PHONE:
+      return Study::PHONE;
+    case ui::DEVICE_FORM_FACTOR_TABLET:
+      return Study::TABLET;
+    case ui::DEVICE_FORM_FACTOR_DESKTOP:
+      return Study::DESKTOP;
+  }
+}
+
+// Returns true if the experiment config has a missing form_factors or it
+// contains the current system's form_factor. Otherwise, it is False.
+bool HasFormFactor(const FieldTrialTestingExperiment& experiment) {
+  for (size_t i = 0; i < experiment.form_factors_size; ++i) {
+    if (experiment.form_factors[i] == _GetCurrentFormFactor())
+      return true;
+  }
+  return experiment.form_factors_size == 0;
+}
+
 void AssociateParamsFromExperiment(
     const std::string& study_name,
     const FieldTrialTestingExperiment& experiment,
@@ -99,7 +123,9 @@
   for (size_t i = 0; i < study.experiments_size; ++i) {
     const FieldTrialTestingExperiment* experiment = study.experiments + i;
     if (HasPlatform(*experiment, platform)) {
-      if (!chosen_experiment && !HasDeviceLevelMismatch(*experiment))
+      if (!chosen_experiment &&
+          !HasDeviceLevelMismatch(*experiment) &&
+          HasFormFactor(*experiment))
         chosen_experiment = experiment;
 
       if (experiment->forcing_flag &&
diff --git a/components/variations/field_trial_config/field_trial_util_unittest.cc b/components/variations/field_trial_config/field_trial_util_unittest.cc
index 8cb2b9c..9e2372d6 100644
--- a/components/variations/field_trial_config/field_trial_util_unittest.cc
+++ b/components/variations/field_trial_config/field_trial_util_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/variations/field_trial_config/fieldtrial_testing_config.h"
 #include "components/variations/variations_associated_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/device_form_factor.h"
 
 namespace variations {
 namespace {
@@ -31,6 +32,19 @@
     testing::ClearAllVariationParams();
   }
 
+  // Gets current form factor and converts it from enum DeviceFormFactor to enum
+  // Study_FormFactor.
+  Study::FormFactor _GetCurrentFormFactor() {
+    switch (ui::GetDeviceFormFactor()) {
+      case ui::DEVICE_FORM_FACTOR_PHONE:
+        return Study::PHONE;
+      case ui::DEVICE_FORM_FACTOR_TABLET:
+        return Study::TABLET;
+      case ui::DEVICE_FORM_FACTOR_DESKTOP:
+        return Study::DESKTOP;
+    }
+  }
+
  private:
   base::FieldTrialList field_trial_list_;
 
@@ -68,15 +82,15 @@
   const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params_0[] =
       {{"x", "1"}, {"y", "2"}};
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = {
-      {"TestGroup1", &platform, 1, Study::OPTIONAL_BOOL_MISSING,
+      {"TestGroup1", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
        array_kFieldTrialConfig_params_0, 2, nullptr, 0, nullptr, 0, nullptr},
   };
   const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params_1[] =
       {{"x", "3"}, {"y", "4"}};
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_1[] = {
-      {"TestGroup2", &platform, 1, Study::OPTIONAL_BOOL_MISSING,
+      {"TestGroup2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
        array_kFieldTrialConfig_params_0, 2, nullptr, 0, nullptr, 0, nullptr},
-      {"TestGroup2-2", &platform, 1, Study::OPTIONAL_BOOL_MISSING,
+      {"TestGroup2-2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
        array_kFieldTrialConfig_params_1, 2, nullptr, 0, nullptr, 0, nullptr},
   };
   const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
@@ -126,7 +140,7 @@
   for (size_t i = 0; i < base::size(all_platforms); ++i) {
     const Study::Platform platform = all_platforms[i];
     const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments[] = {
-        {"TestGroup", &platform, 1, Study::OPTIONAL_BOOL_MISSING,
+        {"TestGroup", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
          array_kFieldTrialConfig_params, 2, nullptr, 0, nullptr, 0, nullptr},
     };
     const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
@@ -158,7 +172,7 @@
   const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params[] =
       {{"x", "1"}, {"y", "2"}};
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments[] = {
-      {"TestGroup", &platform, 1, Study::OPTIONAL_BOOL_MISSING,
+      {"TestGroup", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
        array_kFieldTrialConfig_params, 2, nullptr, 0, nullptr, 0, nullptr},
   };
   const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] =
@@ -187,7 +201,7 @@
   const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params[] =
       {{"x", "1"}, {"y", "2"}};
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments[] = {
-      {"TestGroup", platforms, 2, Study::OPTIONAL_BOOL_MISSING,
+      {"TestGroup", platforms, 2, {}, 0, Study::OPTIONAL_BOOL_MISSING,
        array_kFieldTrialConfig_params, 2, nullptr, 0, nullptr, 0, nullptr},
   };
   const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] =
@@ -212,6 +226,109 @@
   EXPECT_EQ("TestGroup", base::FieldTrialList::FindFullName("TestTrial"));
 }
 
+TEST_F(FieldTrialUtilTest,
+       AssociateParamsFromFieldTrialConfigWithAllFormFactors) {
+  const Study::Platform platform = Study::PLATFORM_WINDOWS;
+  const Study::FormFactor form_factors[] =
+      {Study::DESKTOP, Study::PHONE, Study::TABLET};
+  const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params[] =
+      {{"x", "1"}, {"y", "2"}};
+  const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments[] = {
+      {"TestGroup", &platform, 1, form_factors, 4, Study::OPTIONAL_BOOL_MISSING,
+       array_kFieldTrialConfig_params, 2, nullptr, 0, nullptr, 0, nullptr},
+  };
+  const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] =
+      {{"TestTrial", array_kFieldTrialConfig_experiments, 1}};
+  const FieldTrialTestingConfig kConfig =
+      {array_kFieldTrialConfig_studies, 1};
+
+  // One of the form_factors matches, so trial should be added.
+  base::FeatureList feature_list;
+  AssociateParamsFromFieldTrialConfig(kConfig, &feature_list, platform);
+
+  EXPECT_EQ("1", GetVariationParamValue("TestTrial", "x"));
+  EXPECT_EQ("2", GetVariationParamValue("TestTrial", "y"));
+
+  std::map<std::string, std::string> params;
+  EXPECT_TRUE(GetVariationParams("TestTrial", &params));
+  EXPECT_EQ(2U, params.size());
+  EXPECT_EQ("1", params["x"]);
+  EXPECT_EQ("2", params["y"]);
+
+  EXPECT_EQ("TestGroup", base::FieldTrialList::FindFullName("TestTrial"));
+}
+
+TEST_F(FieldTrialUtilTest,
+       AssociateParamsFromFieldTrialConfigWithSingleFormFactor) {
+  const Study::Platform platform = Study::PLATFORM_WINDOWS;
+  const Study::FormFactor form_factor = _GetCurrentFormFactor();
+  const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params[] =
+        {{"x", "1"}, {"y", "2"}};
+  const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments[] = {
+      {"TestGroup", &platform, 1, &form_factor, 1,
+       Study::OPTIONAL_BOOL_MISSING, array_kFieldTrialConfig_params, 2,
+       nullptr, 0, nullptr, 0, nullptr},
+  };
+  const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
+      {"TestTrial", array_kFieldTrialConfig_experiments, 1}
+  };
+  const FieldTrialTestingConfig kConfig = {
+      array_kFieldTrialConfig_studies, 1
+  };
+
+  // One of the form_factors matches, so trial should be added.
+  base::FeatureList feature_list;
+  AssociateParamsFromFieldTrialConfig(kConfig, &feature_list, platform);
+
+  EXPECT_EQ("1", GetVariationParamValue("TestTrial", "x"));
+  EXPECT_EQ("2", GetVariationParamValue("TestTrial", "y"));
+
+  std::map<std::string, std::string> params;
+  EXPECT_TRUE(GetVariationParams("TestTrial", &params));
+  EXPECT_EQ(2U, params.size());
+  EXPECT_EQ("1", params["x"]);
+  EXPECT_EQ("2", params["y"]);
+
+  EXPECT_EQ("TestGroup", base::FieldTrialList::FindFullName("TestTrial"));
+}
+
+TEST_F(FieldTrialUtilTest,
+       AssociateParamsFromFieldTrialConfigWithDifferentFormFactor) {
+  const Study::Platform platform = Study::PLATFORM_WINDOWS;
+  const Study::FormFactor current_form_factor = _GetCurrentFormFactor();
+  const Study::FormFactor all_form_factors[] =
+      {Study::DESKTOP, Study::PHONE, Study::TABLET};
+  for (size_t i = 0; i < base::size(all_form_factors); ++i) {
+    const Study::FormFactor form_factor = all_form_factors[i];
+    if (form_factor == current_form_factor)
+      continue;
+    const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params[] =
+        {{"x", "1"}, {"y", "2"}};
+    const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments[] = {
+        {"TestGroup", &platform, 1, &form_factor, 1,
+         Study::OPTIONAL_BOOL_MISSING, array_kFieldTrialConfig_params, 2,
+         nullptr, 0, nullptr, 0, nullptr},
+    };
+    const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] =
+        {{"TestTrial", array_kFieldTrialConfig_experiments, 1}};
+    const FieldTrialTestingConfig kConfig =
+        {array_kFieldTrialConfig_studies, 1};
+
+    // The form factor don't match, so trial shouldn't be added.
+    base::FeatureList feature_list;
+    AssociateParamsFromFieldTrialConfig(kConfig, &feature_list,
+                                        Study::PLATFORM_ANDROID_WEBVIEW);
+
+    EXPECT_EQ("", GetVariationParamValue("TestTrial", "x"));
+    EXPECT_EQ("", GetVariationParamValue("TestTrial", "y"));
+
+    std::map<std::string, std::string> params;
+    EXPECT_FALSE(GetVariationParams("TestTrial", &params));
+
+    EXPECT_EQ("", base::FieldTrialList::FindFullName("TestTrial"));
+  }
+}
+
 TEST_F(FieldTrialUtilTest, AssociateFeaturesFromFieldTrialConfig) {
   const base::Feature kFeatureA{"A", base::FEATURE_DISABLED_BY_DEFAULT};
   const base::Feature kFeatureB{"B", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -223,14 +340,14 @@
 
   const Study::Platform platform = Study::PLATFORM_LINUX;
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = {
-      {"TestGroup1", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       enable_features, 2, nullptr, 0, nullptr},
+      {"TestGroup1", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING, nullptr,
+       0, enable_features, 2, nullptr, 0, nullptr},
   };
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_1[] = {
-      {"TestGroup2", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, disable_features, 2, nullptr},
-      {"TestGroup2-2", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, nullptr},
+      {"TestGroup2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING, nullptr,
+       0, nullptr, 0, disable_features, 2, nullptr},
+      {"TestGroup2-2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
+       nullptr, 0, nullptr, 0, nullptr, 0, nullptr},
   };
 
   const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
@@ -263,21 +380,21 @@
 TEST_F(FieldTrialUtilTest, AssociateForcingFlagsFromFieldTrialConfig) {
   const Study::Platform platform = Study::PLATFORM_LINUX;
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = {
-      {"TestGroup1", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, nullptr}};
+      {"TestGroup1", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING, nullptr,
+       0, nullptr, 0, nullptr, 0, nullptr}};
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_1[] = {
-      {"TestGroup2", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, nullptr},
-      {"ForcedGroup2", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, "flag-2"},
+      {"TestGroup2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING, nullptr,
+       0, nullptr, 0, nullptr, 0, nullptr},
+      {"ForcedGroup2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
+       nullptr, 0, nullptr, 0, nullptr, 0, "flag-2"},
   };
   const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_2[] = {
-      {"TestGroup3", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, nullptr},
-      {"ForcedGroup3", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, "flag-3"},
-      {"ForcedGroup3-2", &platform, 1, Study::OPTIONAL_BOOL_MISSING, nullptr, 0,
-       nullptr, 0, nullptr, 0, "flag-3-2"},
+      {"TestGroup3", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING, nullptr,
+       0, nullptr, 0, nullptr, 0, nullptr},
+      {"ForcedGroup3", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
+       nullptr, 0, nullptr, 0, nullptr, 0, "flag-3"},
+      {"ForcedGroup3-2", &platform, 1, {}, 0, Study::OPTIONAL_BOOL_MISSING,
+       nullptr, 0, nullptr, 0, nullptr, 0, "flag-3-2"},
   };
   const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
       {"TestTrial1", array_kFieldTrialConfig_experiments_0, 1},
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 2dfcd0d..0e1baa3 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -353,6 +353,9 @@
   gfx::Transform content_device_transform;
   // The DrawQuad's visible_rect, possibly explicitly clipped by the scissor
   gfx::RectF visible_rect;
+  // Initialized to the visible_rect, relevant quad types should updated based
+  // on their specialized properties.
+  gfx::RectF vis_tex_coords;
   // SkCanvas::QuadAAFlags, already taking into account settings
   // (but not certain quad type's force_antialias_off bit)
   unsigned aa_flags;
@@ -391,6 +394,7 @@
                                              const gfx::QuadF* draw_region)
     : content_device_transform(cdt),
       visible_rect(visible_rect),
+      vis_tex_coords(visible_rect),
       aa_flags(aa_flags),
       blend_mode(blend_mode),
       opacity(opacity),
@@ -782,31 +786,31 @@
 
   switch (quad->material) {
     case DrawQuad::DEBUG_BORDER:
-      DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad), params);
+      DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::PICTURE_CONTENT:
-      DrawPictureQuad(PictureDrawQuad::MaterialCast(quad), params);
+      DrawPictureQuad(PictureDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::RENDER_PASS:
-      DrawRenderPassQuad(RenderPassDrawQuad::MaterialCast(quad), params);
+      DrawRenderPassQuad(RenderPassDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::SOLID_COLOR:
-      DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad), params);
+      DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::STREAM_VIDEO_CONTENT:
-      DrawStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad), params);
+      DrawStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::TEXTURE_CONTENT:
-      DrawTextureQuad(TextureDrawQuad::MaterialCast(quad), params);
+      DrawTextureQuad(TextureDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::TILED_CONTENT:
-      DrawTileDrawQuad(TileDrawQuad::MaterialCast(quad), params);
+      DrawTileDrawQuad(TileDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::YUV_VIDEO_CONTENT:
-      DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad), params);
+      DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad), &params);
       break;
     case DrawQuad::INVALID:
-      DrawUnsupportedQuad(quad, params);
+      DrawUnsupportedQuad(quad, &params);
       NOTREACHED();
       break;
     case DrawQuad::VIDEO_HOLE:
@@ -816,12 +820,12 @@
       // Quad and the quad would then reach here unexpectedly. Therefore
       // we should skip NOTREACHED() so an untrusted render is not capable
       // of causing a crash.
-      DrawUnsupportedQuad(quad, params);
+      DrawUnsupportedQuad(quad, &params);
       break;
     default:
       // If we've reached here, it's a new quad type that needs a
       // dedicated implementation
-      DrawUnsupportedQuad(quad, params);
+      DrawUnsupportedQuad(quad, &params);
       NOTREACHED();
       break;
   }
@@ -899,6 +903,7 @@
                              params.content_device_transform)) {
       ApplyExplicitScissor(quad, scissor_rect_, params.content_device_transform,
                            &params.aa_flags, &params.visible_rect);
+      params.vis_tex_coords = params.visible_rect;
     } else {
       params.scissor_rect = scissor_rect_;
     }
@@ -927,16 +932,13 @@
   return params;
 }
 
-SkCanvas::ImageSetEntry SkiaRenderer::MakeEntry(const DrawQuadParams& params,
-                                                const SkImage* image,
-                                                const gfx::RectF& src,
+SkCanvas::ImageSetEntry SkiaRenderer::MakeEntry(const SkImage* image,
                                                 int matrix_index,
-                                                bool use_opacity) {
+                                                const DrawQuadParams& params) {
   return SkCanvas::ImageSetEntry(
-      {sk_ref_sp(image), gfx::RectFToSkRect(src),
-       gfx::RectFToSkRect(params.visible_rect), matrix_index,
-       use_opacity ? params.opacity : 1.f, params.aa_flags,
-       params.draw_region.has_value()});
+      {sk_ref_sp(image), gfx::RectFToSkRect(params.vis_tex_coords),
+       gfx::RectFToSkRect(params.visible_rect), matrix_index, params.opacity,
+       params.aa_flags, params.draw_region.has_value()});
 }
 
 bool SkiaRenderer::MustFlushBatchedQuads(const DrawQuad* new_quad,
@@ -966,33 +968,32 @@
   return false;
 }
 
-void SkiaRenderer::AddQuadToBatch(const DrawQuadParams& params,
-                                  const SkImage* image,
-                                  const gfx::RectF& tex_coords) {
+void SkiaRenderer::AddQuadToBatch(const SkImage* image,
+                                  DrawQuadParams* params) {
   // Configure batch state if it's the first
   if (batched_quads_.empty()) {
-    batched_quad_state_.scissor_rect = params.scissor_rect;
-    batched_quad_state_.rounded_corner_bounds = params.rounded_corner_bounds;
-    batched_quad_state_.blend_mode = params.blend_mode;
-    batched_quad_state_.filter_quality = params.filter_quality;
+    batched_quad_state_.scissor_rect = params->scissor_rect;
+    batched_quad_state_.rounded_corner_bounds = params->rounded_corner_bounds;
+    batched_quad_state_.blend_mode = params->blend_mode;
+    batched_quad_state_.filter_quality = params->filter_quality;
   }
 
   // Add entry, with optional clip quad and shared transform
-  if (params.draw_region.has_value()) {
+  if (params->draw_region.has_value()) {
     for (int i = 0; i < 4; ++i) {
-      batched_draw_regions_.push_back(params.draw_region->points[i]);
+      batched_draw_regions_.push_back(params->draw_region->points[i]);
     }
   }
 
   SkMatrix m;
-  gfx::TransformToFlattenedSkMatrix(params.content_device_transform, &m);
+  gfx::TransformToFlattenedSkMatrix(params->content_device_transform, &m);
   std::vector<SkMatrix>& cdts = batched_cdt_matrices_;
   if (cdts.empty() || cdts[cdts.size() - 1] != m) {
     cdts.push_back(m);
   }
   int matrix_index = cdts.size() - 1;
 
-  batched_quads_.push_back(MakeEntry(params, image, tex_coords, matrix_index));
+  batched_quads_.push_back(MakeEntry(image, matrix_index, *params));
 }
 
 void SkiaRenderer::FlushBatchedQuads() {
@@ -1014,66 +1015,61 @@
   batched_cdt_matrices_.clear();
 }
 
-void SkiaRenderer::DrawColoredQuad(const DrawQuadParams& params,
-                                   SkColor color) {
+void SkiaRenderer::DrawColoredQuad(SkColor color, DrawQuadParams* params) {
   DCHECK(batched_quads_.empty());
   TRACE_EVENT0("viz", "SkiaRenderer::DrawColoredQuad");
 
   SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
-  PrepareCanvas(params.scissor_rect, params.rounded_corner_bounds,
-                &params.content_device_transform);
+  PrepareCanvas(params->scissor_rect, params->rounded_corner_bounds,
+                &params->content_device_transform);
 
-  color = SkColorSetA(color, params.opacity * SkColorGetA(color));
+  color = SkColorSetA(color, params->opacity * SkColorGetA(color));
   const SkPoint* draw_region =
-      params.draw_region.has_value() ? params.draw_region->points : nullptr;
+      params->draw_region.has_value() ? params->draw_region->points : nullptr;
   current_canvas_->experimental_DrawEdgeAAQuad(
-      gfx::RectFToSkRect(params.visible_rect), draw_region,
-      static_cast<SkCanvas::QuadAAFlags>(params.aa_flags), color,
-      params.blend_mode);
+      gfx::RectFToSkRect(params->visible_rect), draw_region,
+      static_cast<SkCanvas::QuadAAFlags>(params->aa_flags), color,
+      params->blend_mode);
 }
 
-void SkiaRenderer::DrawSingleImage(const DrawQuadParams& params,
-                                   const SkImage* image,
-                                   const gfx::RectF& src,
-                                   const SkPaint* paint) {
+void SkiaRenderer::DrawSingleImage(const SkImage* image,
+                                   const SkPaint& paint,
+                                   DrawQuadParams* params) {
   DCHECK(batched_quads_.empty());
   TRACE_EVENT0("viz", "SkiaRenderer::DrawSingleImage");
 
   SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
-  PrepareCanvas(params.scissor_rect, params.rounded_corner_bounds,
-                &params.content_device_transform);
+  PrepareCanvas(params->scissor_rect, params->rounded_corner_bounds,
+                &params->content_device_transform);
   // Use -1 for matrix index since the cdt is set on the canvas.
-  // Assume params.opacity has been somehow handled in the SkPaint
-  // (setAlphaf, color filter, image filter node, etc.).
-  SkCanvas::ImageSetEntry entry =
-      MakeEntry(params, image, src, -1, false /* use params.opacity */);
+  SkCanvas::ImageSetEntry entry = MakeEntry(image, -1, *params);
   const SkPoint* draw_region =
-      params.draw_region.has_value() ? params.draw_region->points : nullptr;
+      params->draw_region.has_value() ? params->draw_region->points : nullptr;
   current_canvas_->experimental_DrawEdgeAAImageSet(&entry, 1, draw_region,
-                                                   nullptr, paint);
+                                                   nullptr, &paint);
 }
 
 void SkiaRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad,
-                                       const DrawQuadParams& params) {
+                                       DrawQuadParams* params) {
   DCHECK(batched_quads_.empty());
 
   SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
   // We need to apply the matrix manually to have pixel-sized stroke width.
-  PrepareCanvas(params.scissor_rect, params.rounded_corner_bounds, nullptr);
+  PrepareCanvas(params->scissor_rect, params->rounded_corner_bounds, nullptr);
   SkMatrix cdt;
-  gfx::TransformToFlattenedSkMatrix(params.content_device_transform, &cdt);
+  gfx::TransformToFlattenedSkMatrix(params->content_device_transform, &cdt);
 
   SkPath path;
-  if (params.draw_region.has_value()) {
-    path.addPoly(params.draw_region->points, 4, true /* close */);
+  if (params->draw_region.has_value()) {
+    path.addPoly(params->draw_region->points, 4, true /* close */);
   } else {
-    path.addRect(gfx::RectFToSkRect(params.visible_rect));
+    path.addRect(gfx::RectFToSkRect(params->visible_rect));
   }
   path.transform(cdt);
 
-  SkPaint paint = params.paint();
+  SkPaint paint = params->paint();
   paint.setColor(quad->color);  // Must correct alpha afterwards
-  paint.setAlphaf(params.opacity * paint.getAlphaf());
+  paint.setAlphaf(params->opacity * paint.getAlphaf());
   paint.setStyle(SkPaint::kStroke_Style);
   paint.setStrokeJoin(SkPaint::kMiter_Join);
   paint.setStrokeWidth(quad->width);
@@ -1081,7 +1077,7 @@
 }
 
 void SkiaRenderer::DrawPictureQuad(const PictureDrawQuad* quad,
-                                   const DrawQuadParams& params) {
+                                   DrawQuadParams* params) {
   DCHECK(batched_quads_.empty());
   TRACE_EVENT0("viz", "SkiaRenderer::DrawPictureQuad");
 
@@ -1089,23 +1085,23 @@
   // must be used so that the display list is drawn into a transient image and
   // then blended as a single layer at the end.
   const bool needs_transparency =
-      params.opacity < 1.f || params.blend_mode != SkBlendMode::kSrcOver;
+      params->opacity < 1.f || params->blend_mode != SkBlendMode::kSrcOver;
   const bool disable_image_filtering =
       disable_picture_quad_image_filtering_ ||
-      params.filter_quality == kNone_SkFilterQuality;
+      params->filter_quality == kNone_SkFilterQuality;
 
   SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
-  PrepareCanvas(params.scissor_rect, params.rounded_corner_bounds,
-                &params.content_device_transform);
+  PrepareCanvas(params->scissor_rect, params->rounded_corner_bounds,
+                &params->content_device_transform);
 
   // Unlike other quads which draw visible_rect or draw_region as their geometry
   // these represent the valid windows of content to show for the display list,
   // so they need to be used as a clip in Skia.
-  SkRect visible_rect = gfx::RectFToSkRect(params.visible_rect);
-  SkPaint paint = params.paint();
-  if (params.draw_region.has_value()) {
+  SkRect visible_rect = gfx::RectFToSkRect(params->visible_rect);
+  SkPaint paint = params->paint();
+  if (params->draw_region.has_value()) {
     SkPath clip;
-    clip.addPoly(params.draw_region->points, 4, true /* close */);
+    clip.addPoly(params->draw_region->points, 4, true /* close */);
     current_canvas_->clipPath(clip, paint.isAntiAlias());
   } else {
     current_canvas_->clipRect(visible_rect, paint.isAntiAlias());
@@ -1143,13 +1139,13 @@
 }
 
 void SkiaRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
-                                      const DrawQuadParams& params) {
-  DrawColoredQuad(params, quad->color);
+                                      DrawQuadParams* params) {
+  DrawColoredQuad(quad->color, params);
 }
 
 void SkiaRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
-                                       const DrawQuadParams& params) {
-  DCHECK(!MustFlushBatchedQuads(quad, params));
+                                       DrawQuadParams* params) {
+  DCHECK(!MustFlushBatchedQuads(quad, *params));
   ScopedSkImageBuilder builder(this, quad->resource_id(),
                                kUnpremul_SkAlphaType);
   const SkImage* image = builder.sk_image();
@@ -1159,13 +1155,13 @@
   gfx::RectF uv_rect = gfx::ScaleRect(
       gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right),
       image->width(), image->height());
-  gfx::RectF visible_uv_rect = cc::MathUtil::ScaleRectProportional(
-      uv_rect, gfx::RectF(quad->rect), params.visible_rect);
-  AddQuadToBatch(params, image, visible_uv_rect);
+  params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
+      uv_rect, gfx::RectF(quad->rect), params->visible_rect);
+  AddQuadToBatch(image, params);
 }
 
 void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
-                                   const DrawQuadParams& params) {
+                                   DrawQuadParams* params) {
   ScopedSkImageBuilder builder(
       this, quad->resource_id(),
       quad->premultiplied_alpha ? kPremul_SkAlphaType : kUnpremul_SkAlphaType,
@@ -1176,8 +1172,8 @@
   gfx::RectF uv_rect = gfx::ScaleRect(
       gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right),
       image->width(), image->height());
-  gfx::RectF visible_uv_rect = cc::MathUtil::ScaleRectProportional(
-      uv_rect, gfx::RectF(quad->rect), params.visible_rect);
+  params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
+      uv_rect, gfx::RectF(quad->rect), params->visible_rect);
 
   // There are two scenarios where a texture quad cannot be put into a batch:
   // 1. It needs to be blended with a constant background color.
@@ -1190,8 +1186,8 @@
 
   if (!blend_background && !vertex_alpha) {
     // This is a simple texture draw and can go into the batching system
-    DCHECK(!MustFlushBatchedQuads(quad, params));
-    AddQuadToBatch(params, image, visible_uv_rect);
+    DCHECK(!MustFlushBatchedQuads(quad, *params));
+    AddQuadToBatch(image, params);
     return;
   }
   // This needs a color filter for background blending and/or a mask filter
@@ -1200,8 +1196,9 @@
   if (!batched_quads_.empty())
     FlushBatchedQuads();
 
-  SkPaint paint = params.paint();
-  float quad_alpha = params.opacity;
+  SkPaint paint = params->paint();
+  float quad_alpha = params->opacity;
+  params->opacity = 1.f;
   if (vertex_alpha) {
     // If they are all the same value, combine it with the overall opacity,
     // otherwise use a mask filter to emulate vertex opacity interpolation
@@ -1218,15 +1215,17 @@
       if (quad->vertex_opacity[0] == quad->vertex_opacity[1] &&
           quad->vertex_opacity[2] == quad->vertex_opacity[3]) {
         // Left to right gradient
-        float y = params.visible_rect.y() + 0.5f * params.visible_rect.height();
-        gradient_pts[0] = {params.visible_rect.x(), y};
-        gradient_pts[1] = {params.visible_rect.right(), y};
+        float y =
+            params->visible_rect.y() + 0.5f * params->visible_rect.height();
+        gradient_pts[0] = {params->visible_rect.x(), y};
+        gradient_pts[1] = {params->visible_rect.right(), y};
       } else if (quad->vertex_opacity[0] == quad->vertex_opacity[3] &&
                  quad->vertex_opacity[1] == quad->vertex_opacity[2]) {
         // Top to bottom gradient
-        float x = params.visible_rect.x() + 0.5f * params.visible_rect.width();
-        gradient_pts[0] = {x, params.visible_rect.y()};
-        gradient_pts[1] = {x, params.visible_rect.bottom()};
+        float x =
+            params->visible_rect.x() + 0.5f * params->visible_rect.width();
+        gradient_pts[0] = {x, params->visible_rect.y()};
+        gradient_pts[1] = {x, params->visible_rect.bottom()};
       } else {
         // Not sure how to emulate
         NOTIMPLEMENTED();
@@ -1265,12 +1264,12 @@
   // Override the default paint opacity since it may not be params.opacity
   paint.setAlphaf(quad_alpha);
 
-  DrawSingleImage(params, image, visible_uv_rect, &paint);
+  DrawSingleImage(image, paint, params);
 }
 
 void SkiaRenderer::DrawTileDrawQuad(const TileDrawQuad* quad,
-                                    const DrawQuadParams& params) {
-  DCHECK(!MustFlushBatchedQuads(quad, params));
+                                    DrawQuadParams* params) {
+  DCHECK(!MustFlushBatchedQuads(quad, *params));
 
   // |resource_provider_| can be NULL in resourceless software draws, which
   // should never produce tile quads in the first place.
@@ -1282,13 +1281,13 @@
   if (!image)
     return;
 
-  gfx::RectF vis_tex_coords = cc::MathUtil::ScaleRectProportional(
-      quad->tex_coord_rect, gfx::RectF(quad->rect), params.visible_rect);
-  AddQuadToBatch(params, image, vis_tex_coords);
+  params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
+      quad->tex_coord_rect, gfx::RectF(quad->rect), params->visible_rect);
+  AddQuadToBatch(image, params);
 }
 
 void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
-                                    const DrawQuadParams& params) {
+                                    DrawQuadParams* params) {
   // Since YUV quads always use a color filter, they require a complex skPaint
   // that precludes batching. If this changes, we could add YUV quads that don't
   // require a filter to the batch instead of drawing one at a time.
@@ -1315,22 +1314,22 @@
   if (!image)
     return;
 
-  gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional(
-      quad->ya_tex_coord_rect, gfx::RectF(quad->rect), params.visible_rect);
+  params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
+      quad->ya_tex_coord_rect, gfx::RectF(quad->rect), params->visible_rect);
 
-  SkPaint paint = params.paint();
+  SkPaint paint = params->paint();
   if (color_filter)
     paint.setColorFilter(color_filter);
 
-  DrawSingleImage(params, image, visible_tex_coord_rect, &paint);
+  DrawSingleImage(image, paint, params);
 }
 
 void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad,
-                                       const DrawQuadParams& params) {
+                                       DrawQuadParams* params) {
 #ifdef NDEBUG
-  DrawColoredQuad(params, SK_ColorWHITE);
+  DrawColoredQuad(SK_ColorWHITE, params);
 #else
-  DrawColoredQuad(params, SK_ColorMAGENTA);
+  DrawColoredQuad(SK_ColorMAGENTA, params);
 #endif
 }
 
@@ -1383,8 +1382,8 @@
 SkiaRenderer::DrawRPDQParams SkiaRenderer::CalculateRPDQParams(
     const SkImage* content,
     const RenderPassDrawQuad* quad,
-    const DrawQuadParams& params) {
-  DrawRPDQParams rpdq_params(params.visible_rect);
+    DrawQuadParams* params) {
+  DrawRPDQParams rpdq_params(params->visible_rect);
 
   // Prepare mask.
   ScopedSkImageBuilder mask_image_builder(this, quad->mask_resource_id());
@@ -1425,11 +1424,12 @@
     auto sk_filter = paint_filter ? paint_filter->cached_sk_filter_ : nullptr;
 
     if (sk_filter) {
-      if (params.opacity != 1.f) {
+      if (params->opacity != 1.f) {
         // Apply opacity as the last step of image filter so it is uniform
         // across any overlapping content produced by the image filters.
-        sk_sp<SkColorFilter> cf = MakeOpacityFilter(params.opacity, nullptr);
+        sk_sp<SkColorFilter> cf = MakeOpacityFilter(params->opacity, nullptr);
         sk_filter = SkColorFilterImageFilter::Make(std::move(cf), sk_filter);
+        params->opacity = 1.f;
       }
 
       // Update the filter bounds based to account for how the image filters
@@ -1463,18 +1463,18 @@
   // Convert CC image filters for the backdrop into a SkImageFilter root node
   if (backdrop_filters) {
     DCHECK(!backdrop_filters->IsEmpty());
-    auto paint_filter = cc::RenderSurfaceFilters::BuildImageFilter(
+    auto bg_paint_filter = cc::RenderSurfaceFilters::BuildImageFilter(
         *backdrop_filters, filter_size);
-    auto sk_backdrop_filter =
-        paint_filter ? paint_filter->cached_sk_filter_ : nullptr;
+    auto sk_bg_filter =
+        bg_paint_filter ? bg_paint_filter->cached_sk_filter_ : nullptr;
 
-    if (sk_backdrop_filter) {
+    if (sk_bg_filter) {
       SkMatrix content_to_dest = SkMatrix::MakeRectToRect(
           gfx::RectFToSkRect(quad->tex_coord_rect),
           gfx::RectToSkRect(quad->rect), SkMatrix::kFill_ScaleToFit);
       content_to_dest.preConcat(local_matrix);
       rpdq_params.backdrop_filter =
-          sk_backdrop_filter->makeWithLocalMatrix(content_to_dest);
+          sk_bg_filter->makeWithLocalMatrix(content_to_dest);
     }
   }
 
@@ -1514,7 +1514,7 @@
 }
 
 void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad,
-                                      const DrawQuadParams& params) {
+                                      DrawQuadParams* params) {
   auto bypass = render_pass_bypass_quads_.find(quad->render_pass_id);
   // When Render Pass has a single quad inside we would draw that directly.
   if (bypass != render_pass_bypass_quads_.end()) {
@@ -1523,8 +1523,7 @@
                                  tile_quad->is_premultiplied
                                      ? kPremul_SkAlphaType
                                      : kUnpremul_SkAlphaType);
-    DrawRenderPassQuadInternal(quad, params, builder.sk_image(),
-                               false /* mipmap */);
+    DrawRenderPassQuadInternal(quad, builder.sk_image(), params);
   } else {
     auto iter = render_pass_backings_.find(quad->render_pass_id);
     DCHECK(render_pass_backings_.end() != iter);
@@ -1550,27 +1549,31 @@
       }
     }
 
-    DrawRenderPassQuadInternal(quad, params, content_image.get(),
-                               backing.generate_mipmap);
+    // Currently the only trigger for generate_mipmap for render pass is
+    // trilinear filtering. It only affects GPU backed implementations and thus
+    // requires medium filter quality level.
+    if (backing.generate_mipmap)
+      params->filter_quality = kMedium_SkFilterQuality;
+    DrawRenderPassQuadInternal(quad, content_image.get(), params);
   }
 }
 
 void SkiaRenderer::DrawRenderPassQuadInternal(const RenderPassDrawQuad* quad,
-                                              const DrawQuadParams& params,
                                               const SkImage* content_image,
-                                              bool needs_mipmap) {
+                                              DrawQuadParams* params) {
   DrawRPDQParams rpdq_params = CalculateRPDQParams(content_image, quad, params);
   if (rpdq_params.filter_bounds.IsEmpty())
     return;
 
-  gfx::RectF vis_tex_coords = cc::MathUtil::ScaleRectProportional(
-      quad->tex_coord_rect, gfx::RectF(quad->rect), params.visible_rect);
-  if (!needs_mipmap && !rpdq_params.image_filter &&
-      !rpdq_params.backdrop_filter && !rpdq_params.mask_image) {
+  params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
+      quad->tex_coord_rect, gfx::RectF(quad->rect), params->visible_rect);
+  if (params->filter_quality < kMedium_SkFilterQuality &&
+      !rpdq_params.image_filter && !rpdq_params.backdrop_filter &&
+      !rpdq_params.mask_image) {
     // We've checked enough to know that this is a plain textured draw that
     // is compatible with any batched images, so preserve that
-    DCHECK(!MustFlushBatchedQuads(quad, params));
-    AddQuadToBatch(params, content_image, vis_tex_coords);
+    DCHECK(!MustFlushBatchedQuads(quad, *params));
+    AddQuadToBatch(content_image, params);
     return;
   }
 
@@ -1579,14 +1582,7 @@
   if (!batched_quads_.empty())
     FlushBatchedQuads();
 
-  SkPaint paint = params.paint();
-
-  // Currently the only trigger for generate_mipmap for render pass is
-  // trilinear filtering. It only affects GPU backed implementations and thus
-  // requires medium filter quality level.
-  if (needs_mipmap)
-    paint.setFilterQuality(kMedium_SkFilterQuality);
-
+  SkPaint paint = params->paint();
   if (!rpdq_params.image_filter && !rpdq_params.backdrop_filter) {
     // When there are no filters, there is no need to save a layer, but we do
     // have to incorporate the mask directly into the paint then.
@@ -1596,7 +1592,7 @@
               &rpdq_params.mask_to_quad_matrix)));
       DCHECK(paint.getMaskFilter());
     }
-    DrawSingleImage(params, content_image, vis_tex_coords, &paint);
+    DrawSingleImage(content_image, paint, params);
     return;
   }
 
@@ -1614,8 +1610,8 @@
 
   // Make sure everything is provided in the quad space coordinate system.
   SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
-  PrepareCanvas(params.scissor_rect, params.rounded_corner_bounds,
-                &params.content_device_transform);
+  PrepareCanvas(params->scissor_rect, params->rounded_corner_bounds,
+                &params->content_device_transform);
 
   // saveLayer automatically respects the clip when it is restored, and
   // automatically reads beyond the clip for its backdrop filtered content.
@@ -1628,9 +1624,6 @@
   // Add the image filter to the restoration paint.
   if (rpdq_params.image_filter) {
     paint.setImageFilter(rpdq_params.image_filter);
-    // Reset paint to opaque. Render Pass should apply their opacity as last
-    // step, so the opacity is built into the image filter.
-    paint.setAlphaf(1.f);
   }
 
   // Save the layer with the restoration paint (which holds the final image
@@ -1663,11 +1656,9 @@
   SkPaint content_paint;
   content_paint.setFilterQuality(paint.getFilterQuality());
 
-  SkCanvas::ImageSetEntry entry =
-      MakeEntry(params, content_image, vis_tex_coords, -1,
-                false /* use params.opacity */);
+  SkCanvas::ImageSetEntry entry = MakeEntry(content_image, -1, *params);
   const SkPoint* draw_region =
-      params.draw_region.has_value() ? params.draw_region->points : nullptr;
+      params->draw_region.has_value() ? params->draw_region->points : nullptr;
   current_canvas_->experimental_DrawEdgeAAImageSet(&entry, 1, draw_region,
                                                    nullptr, &content_paint);
 
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index f189d38..9510665 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -104,58 +104,51 @@
                      const base::Optional<gfx::RRectF>& rounded_corner_bounds,
                      const gfx::Transform* cdt);
 
+  // The returned DrawQuadParams can be modified by the DrawX calls that accept
+  // params so that they can apply explicit data transforms before sending to
+  // Skia in a consistent manner.
   DrawQuadParams CalculateDrawQuadParams(const DrawQuad* quad,
                                          const gfx::QuadF* draw_region);
   DrawRPDQParams CalculateRPDQParams(const SkImage* src_image,
                                      const RenderPassDrawQuad* quad,
-                                     const DrawQuadParams& params);
+                                     DrawQuadParams* params);
 
-  SkCanvas::ImageSetEntry MakeEntry(const DrawQuadParams& params,
-                                    const SkImage* image,
-                                    const gfx::RectF& src,
+  SkCanvas::ImageSetEntry MakeEntry(const SkImage* image,
                                     int matrix_index,
-                                    bool use_opacity = true);
+                                    const DrawQuadParams& params);
 
   bool MustFlushBatchedQuads(const DrawQuad* new_quad,
                              const DrawQuadParams& params);
-  void AddQuadToBatch(const DrawQuadParams& params,
-                      const SkImage* image,
-                      const gfx::RectF& tex_coords);
+  void AddQuadToBatch(const SkImage* image, DrawQuadParams* params);
   void FlushBatchedQuads();
 
   // Utility to draw a single quad as a filled color
-  void DrawColoredQuad(const DrawQuadParams& params, SkColor color);
+  void DrawColoredQuad(SkColor color, DrawQuadParams* params);
   // Utility to make a single ImageSetEntry and draw it with the complex paint.
-  // Assumes the paint applies the param's opacity.
-  void DrawSingleImage(const DrawQuadParams& params,
-                       const SkImage* image,
-                       const gfx::RectF& src,
-                       const SkPaint* paint);
+  void DrawSingleImage(const SkImage* image,
+                       const SkPaint& paint,
+                       DrawQuadParams* params);
 
   // DebugBorder, Picture, RPDQ, and SolidColor quads cannot be batched. They
   // either are not textures (debug, picture, solid color), or it's very likely
   // the texture will have advanced paint effects (rpdq)
   void DrawDebugBorderQuad(const DebugBorderDrawQuad* quad,
-                           const DrawQuadParams& params);
-  void DrawPictureQuad(const PictureDrawQuad* quad,
-                       const DrawQuadParams& params);
+                           DrawQuadParams* params);
+  void DrawPictureQuad(const PictureDrawQuad* quad, DrawQuadParams* params);
   void DrawRenderPassQuad(const RenderPassDrawQuad* quad,
-                          const DrawQuadParams& params);
+                          DrawQuadParams* params);
   void DrawRenderPassQuadInternal(const RenderPassDrawQuad* quad,
-                                  const DrawQuadParams& params,
                                   const SkImage* content_image,
-                                  bool needs_mipmap);
+                                  DrawQuadParams* params);
   void DrawSolidColorQuad(const SolidColorDrawQuad* quad,
-                          const DrawQuadParams& state);
+                          DrawQuadParams* params);
 
   void DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
-                           const DrawQuadParams& params);
-  void DrawTextureQuad(const TextureDrawQuad* quad,
-                       const DrawQuadParams& params);
-  void DrawTileDrawQuad(const TileDrawQuad* quad, const DrawQuadParams& params);
-  void DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
-                        const DrawQuadParams& params);
-  void DrawUnsupportedQuad(const DrawQuad* quad, const DrawQuadParams& params);
+                           DrawQuadParams* params);
+  void DrawTextureQuad(const TextureDrawQuad* quad, DrawQuadParams* params);
+  void DrawTileDrawQuad(const TileDrawQuad* quad, DrawQuadParams* params);
+  void DrawYUVVideoQuad(const YUVVideoDrawQuad* quad, DrawQuadParams* params);
+  void DrawUnsupportedQuad(const DrawQuad* quad, DrawQuadParams* params);
 
   const TileDrawQuad* CanPassBeDrawnDirectly(const RenderPass* pass) override;
 
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index 6dbf7a0..19aec32 100644
--- a/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -92,6 +92,7 @@
     LOG(FATAL) << "Failed to initialize vulkan surface.";
   }
   vulkan_surface_ = std::move(vulkan_surface);
+  sk_surfaces_.resize(vulkan_surface_->GetSwapChain()->num_images());
 }
 
 void SkiaOutputDeviceVulkan::UpdateDrawSurface() {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 141dd45d..762a38f5 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -548,8 +548,6 @@
     "browser_plugin/browser_plugin_popup_menu_helper_mac.mm",
     "browser_process_sub_thread.cc",
     "browser_process_sub_thread.h",
-    "browser_shutdown_profile_dumper.cc",
-    "browser_shutdown_profile_dumper.h",
     "browser_thread_impl.cc",
     "browser_thread_impl.h",
     "browser_url_handler_impl.cc",
diff --git a/content/browser/browser_main_runner_impl.cc b/content/browser/browser_main_runner_impl.cc
index db743ae..fcb137d 100644
--- a/content/browser/browser_main_runner_impl.cc
+++ b/content/browser/browser_main_runner_impl.cc
@@ -23,7 +23,6 @@
 #include "components/tracing/common/trace_startup_config.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "content/browser/browser_main_loop.h"
-#include "content/browser/browser_shutdown_profile_dumper.h"
 #include "content/browser/notification_service_impl.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/common/content_switches_internal.h"
@@ -182,19 +181,7 @@
   main_loop_->PreShutdown();
 
   // Finalize the startup tracing session if it is still active.
-  std::unique_ptr<BrowserShutdownProfileDumper> startup_profiler =
-      TracingControllerImpl::GetInstance()->FinalizeStartupTracingIfNeeded();
-
-  // The shutdown tracing got enabled in AttemptUserExit earlier, but someone
-  // needs to write the result to disc. For that a dumper needs to get created
-  // which will dump the traces to disc when it gets destroyed.
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  std::unique_ptr<BrowserShutdownProfileDumper> shutdown_profiler;
-  if (command_line.HasSwitch(switches::kTraceShutdown)) {
-    shutdown_profiler.reset(new BrowserShutdownProfileDumper(
-        BrowserShutdownProfileDumper::GetShutdownProfileFileName()));
-  }
+  TracingControllerImpl::GetInstance()->FinalizeStartupTracingIfNeeded();
 
   {
     // The trace event has to stay between profiler creation and destruction.
diff --git a/content/browser/browser_shutdown_profile_dumper.cc b/content/browser/browser_shutdown_profile_dumper.cc
deleted file mode 100644
index 22f5760..0000000
--- a/content/browser/browser_shutdown_profile_dumper.cc
+++ /dev/null
@@ -1,148 +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 "content/browser/browser_shutdown_profile_dumper.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "components/tracing/common/tracing_switches.h"
-
-namespace content {
-
-BrowserShutdownProfileDumper::BrowserShutdownProfileDumper(
-    const base::FilePath& dump_file_name)
-    : dump_file_name_(dump_file_name), blocks_(0), dump_file_(nullptr) {}
-
-BrowserShutdownProfileDumper::~BrowserShutdownProfileDumper() {
-  WriteTracesToDisc();
-}
-
-static float GetTraceBufferPercentFull() {
-  base::trace_event::TraceLogStatus status =
-      base::trace_event::TraceLog::GetInstance()->GetStatus();
-  return 100 * static_cast<float>(static_cast<double>(status.event_count) /
-                                  status.event_capacity);
-}
-
-void BrowserShutdownProfileDumper::WriteTracesToDisc() {
-  // Note: I have seen a usage of 0.000xx% when dumping - which fits easily.
-  // Since the tracer stops when the trace buffer is filled, we'd rather save
-  // what we have than nothing since we might see from the amount of events
-  // that caused the problem.
-  DVLOG(1) << "Flushing shutdown traces to disc. The buffer is "
-           << GetTraceBufferPercentFull() << "% full.";
-  DCHECK(!dump_file_);
-  dump_file_ = base::OpenFile(dump_file_name_, "w+");
-  if (!IsFileValid()) {
-    LOG(ERROR) << "Failed to open performance trace file: "
-               << dump_file_name_.value();
-    return;
-  }
-  WriteString("{\"traceEvents\":");
-  WriteString("[");
-
-  // TraceLog::Flush() requires the calling thread to have a message loop.
-  // As the message loop of the current thread may have quit, start another
-  // thread for flushing the trace.
-  base::WaitableEvent flush_complete_event(
-      base::WaitableEvent::ResetPolicy::AUTOMATIC,
-      base::WaitableEvent::InitialState::NOT_SIGNALED);
-  base::Thread flush_thread("browser_shutdown_trace_event_flush");
-  flush_thread.Start();
-  flush_thread.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&BrowserShutdownProfileDumper::EndTraceAndFlush,
-                                base::Unretained(this),
-                                base::Unretained(&flush_complete_event)));
-
-  bool original_wait_allowed = base::ThreadRestrictions::SetWaitAllowed(true);
-  flush_complete_event.Wait();
-  base::ThreadRestrictions::SetWaitAllowed(original_wait_allowed);
-}
-
-void BrowserShutdownProfileDumper::EndTraceAndFlush(
-    base::WaitableEvent* flush_complete_event) {
-  base::trace_event::TraceLog::GetInstance()->SetDisabled();
-  base::trace_event::TraceLog::GetInstance()->Flush(
-      base::Bind(&BrowserShutdownProfileDumper::WriteTraceDataCollected,
-                 base::Unretained(this),
-                 base::Unretained(flush_complete_event)));
-}
-
-// static
-base::FilePath BrowserShutdownProfileDumper::GetShutdownProfileFileName() {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  base::FilePath trace_file =
-      command_line.GetSwitchValuePath(switches::kTraceShutdownFile);
-
-  if (!trace_file.empty())
-    return trace_file;
-
-  // Default to saving the startup trace into the current dir.
-  return base::FilePath().AppendASCII("chrometrace.log");
-}
-
-void BrowserShutdownProfileDumper::WriteTraceDataCollected(
-    base::WaitableEvent* flush_complete_event,
-    const scoped_refptr<base::RefCountedString>& events_str,
-    bool has_more_events) {
-  if (!IsFileValid()) {
-    flush_complete_event->Signal();
-    return;
-  }
-  if (blocks_) {
-    // Blocks are not comma separated. Beginning with the second block we
-    // start therefore to add one in front of the previous block.
-    WriteString(",");
-  }
-  ++blocks_;
-  WriteString(events_str->data());
-
-  if (!has_more_events) {
-    WriteString("]");
-    WriteString("}");
-    CloseFile();
-    flush_complete_event->Signal();
-  }
-}
-
-bool BrowserShutdownProfileDumper::IsFileValid() {
-  return dump_file_ && (ferror(dump_file_) == 0);
-}
-
-void BrowserShutdownProfileDumper::WriteString(const std::string& string) {
-  WriteChars(string.data(), string.size());
-}
-
-void BrowserShutdownProfileDumper::WriteChars(const char* chars, size_t size) {
-  if (!IsFileValid())
-    return;
-
-  size_t written = fwrite(chars, 1, size, dump_file_);
-  if (written != size) {
-    LOG(ERROR) << "Error " << ferror(dump_file_)
-               << " in fwrite() to trace file '" << dump_file_name_.value()
-               << "'";
-    CloseFile();
-  }
-}
-
-void BrowserShutdownProfileDumper::CloseFile() {
-  if (!dump_file_)
-    return;
-  base::CloseFile(dump_file_);
-  dump_file_ = nullptr;
-}
-
-}  // namespace content
diff --git a/content/browser/browser_shutdown_profile_dumper.h b/content/browser/browser_shutdown_profile_dumper.h
deleted file mode 100644
index 859811a6..0000000
--- a/content/browser/browser_shutdown_profile_dumper.h
+++ /dev/null
@@ -1,80 +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 CONTENT_BROWSER_BROWSER_SHUTDOWN_PROFILE_DUMPER_H_
-#define CONTENT_BROWSER_BROWSER_SHUTDOWN_PROFILE_DUMPER_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/ref_counted_memory.h"
-#include "content/common/content_export.h"
-
-namespace base {
-class FilePath;
-class WaitableEvent;
-}
-
-namespace content {
-
-// This class is intended to dump the tracing results of the shutdown process
-// to a file before the browser process exits.
-// It will save the file either into the command line passed
-// "--trace-shutdown-file=<name>" parameter - or - to "chrometrace.log" in the
-// current directory.
-// Use the class with a scoped_ptr to get files written in the destructor.
-// Note that we cannot use the asynchronous file writer since the
-// |SequencedWorkerPool| will get killed in the shutdown process.
-class BrowserShutdownProfileDumper {
- public:
-  explicit BrowserShutdownProfileDumper(const base::FilePath& dump_file_name);
-
-  ~BrowserShutdownProfileDumper();
-
-  // Returns the file name where we should save the shutdown trace dump to.
-  static base::FilePath GetShutdownProfileFileName();
-
- private:
-  // Writes all traces which happened to disk.
-  void WriteTracesToDisc();
-
-  void EndTraceAndFlush(base::WaitableEvent* flush_complete_event);
-
-  // The callback for the |TraceLog::Flush| function. It saves all traces to
-  // disc.
-  void WriteTraceDataCollected(
-      base::WaitableEvent* flush_complete_event,
-      const scoped_refptr<base::RefCountedString>& events_str,
-      bool has_more_events);
-
-  // Returns true if the dump file is valid.
-  bool IsFileValid();
-
-  // Writes a string to the dump file.
-  void WriteString(const std::string& string);
-
-  // Write a buffer to the dump file.
-  void WriteChars(const char* chars, size_t size);
-
-  // Closes the dump file.
-  void CloseFile();
-
-  // The name of the dump file.
-  const base::FilePath dump_file_name_;
-
-  // The number of blocks we have already written.
-  int blocks_;
-  // For dumping the content to disc.
-  FILE* dump_file_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserShutdownProfileDumper);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_BROWSER_SHUTDOWN_PROFILE_DUMPER_H_
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index 0197747..664d2c2 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -366,9 +366,8 @@
     int32_t widget_routing_id,
     bool swapped_out,
     bool hidden) {
-  auto iter = render_view_host_map_.find(site_instance->GetId());
-  if (iter != render_view_host_map_.end())
-    return iter->second;
+  if (RenderViewHostImpl* existing_rvh = GetRenderViewHost(site_instance))
+    return existing_rvh;
 
   RenderViewHostImpl* rvh =
       static_cast<RenderViewHostImpl*>(RenderViewHostFactory::Create(
@@ -376,43 +375,37 @@
           routing_id, main_frame_routing_id, widget_routing_id, swapped_out,
           hidden));
 
-  render_view_host_map_[site_instance->GetId()] = rvh;
+  render_view_host_map_[site_instance->GetId()] = base::WrapUnique(rvh);
   return rvh;
 }
 
 RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
-  auto iter = render_view_host_map_.find(site_instance->GetId());
-  if (iter != render_view_host_map_.end())
-    return iter->second;
+  auto it = render_view_host_map_.find(site_instance->GetId());
+  if (it == render_view_host_map_.end())
+    return nullptr;
 
-  return nullptr;
+  return it->second.get();
 }
 
-void FrameTree::AddRenderViewHostRef(RenderViewHostImpl* render_view_host) {
-  SiteInstance* site_instance = render_view_host->GetSiteInstance();
-  auto iter = render_view_host_map_.find(site_instance->GetId());
-  CHECK(iter != render_view_host_map_.end());
-  CHECK(iter->second == render_view_host);
+void FrameTree::AddRenderViewHostRef(RenderViewHostImpl* rvh) {
+  auto it = render_view_host_map_.find(rvh->GetSiteInstance()->GetId());
+  CHECK(it != render_view_host_map_.end());
+  CHECK_EQ(it->second.get(), rvh);
 
-  iter->second->increment_ref_count();
+  rvh->increment_ref_count();
 }
 
-void FrameTree::ReleaseRenderViewHostRef(RenderViewHostImpl* render_view_host) {
-  SiteInstance* site_instance = render_view_host->GetSiteInstance();
-  int32_t site_instance_id = site_instance->GetId();
-  auto iter = render_view_host_map_.find(site_instance_id);
+void FrameTree::ReleaseRenderViewHostRef(RenderViewHostImpl* rvh) {
+  auto it = render_view_host_map_.find(rvh->GetSiteInstance()->GetId());
+  CHECK(it != render_view_host_map_.end());
+  CHECK_EQ(it->second.get(), rvh);
 
-  CHECK(iter != render_view_host_map_.end());
-  CHECK_EQ(iter->second, render_view_host);
-
-  // Decrement the refcount and shutdown the RenderViewHost if no one else is
+  // Decrement the refcount and delete the RenderViewHost if no one else is
   // using it.
-  CHECK_GT(iter->second->ref_count(), 0);
-  iter->second->decrement_ref_count();
-  if (iter->second->ref_count() == 0) {
-    iter->second->ShutdownAndDestroy();
-    render_view_host_map_.erase(iter);
-  }
+  CHECK_GT(rvh->ref_count(), 0);
+  rvh->decrement_ref_count();
+  if (rvh->ref_count() == 0)
+    render_view_host_map_.erase(it);
 }
 
 void FrameTree::FrameRemoved(FrameTreeNode* frame) {
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index 1a768cf8..ccccd552 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -252,7 +252,9 @@
  private:
   friend class FrameTreeTest;
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, RemoveFocusedFrame);
-  typedef std::unordered_map<int, RenderViewHostImpl*> RenderViewHostMap;
+  using RenderViewHostMap =
+      std::unordered_map<int /* SiteInstance ID */,
+                         std::unique_ptr<RenderViewHostImpl>>;
 
   // Returns a range to iterate over all FrameTreeNodes in the frame tree in
   // breadth-first traversal order, skipping the subtree rooted at
@@ -266,13 +268,12 @@
   RenderWidgetHostDelegate* render_widget_delegate_;
   RenderFrameHostManager::Delegate* manager_delegate_;
 
-  // Map of SiteInstance ID to a RenderViewHost.  This allows us to look up the
+  // Map of SiteInstance ID to RenderViewHost. This allows us to look up the
   // RenderViewHost for a given SiteInstance when creating RenderFrameHosts.
-  // Combined with the refcount on RenderViewHost, this allows us to call
-  // Shutdown on the RenderViewHost and remove it from the map when no more
-  // RenderFrameHosts are using it.
+  // Each RenderViewHost maintains a refcount and is deleted when there are no
+  // more RenderFrameHosts using it.
   //
-  // Must be declared before |root_| so that it is deleted afterward.  Otherwise
+  // Must be declared before |root_| so that it is deleted afterward. Otherwise
   // the map will be cleared before we delete the RenderFrameHosts in the tree.
   RenderViewHostMap render_view_host_map_;
 
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 0104f604..f28f9e6 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -582,8 +582,8 @@
   // redirects.
   // Note: |common_params_| and |begin_params_| are not const as they can be
   // modified during redirects.
-  // Note: |commit_params_| is not const because service_worker_provider_id
-  // and should_create_service_worker will be set in OnResponseStarted.
+  // Note: |commit_params_| is not const because was_discarded will
+  // be set in CreatedNavigationRequest.
   CommonNavigationParams common_params_;
   mojom::BeginNavigationParamsPtr begin_params_;
   CommitNavigationParams commit_params_;
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index ee15d67..5c17f54 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -272,6 +272,16 @@
 }
 
 RenderViewHostImpl::~RenderViewHostImpl() {
+  // We can't release the SessionStorageNamespace until our peer
+  // in the renderer has wound down.
+  if (GetProcess()->IsInitializedAndNotDead()) {
+    RenderProcessHostImpl::ReleaseOnCloseACK(
+        GetProcess(), delegate_->GetSessionStorageNamespaceMap(),
+        GetWidget()->GetRoutingID());
+  }
+
+  GetWidget()->ShutdownAndDestroyWidget(false);
+
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::IO},
@@ -854,19 +864,6 @@
   ClosePageIgnoringUnloadEvents();
 }
 
-void RenderViewHostImpl::ShutdownAndDestroy() {
-  // We can't release the SessionStorageNamespace until our peer
-  // in the renderer has wound down.
-  if (GetProcess()->IsInitializedAndNotDead()) {
-    RenderProcessHostImpl::ReleaseOnCloseACK(
-        GetProcess(), delegate_->GetSessionStorageNamespaceMap(),
-        GetWidget()->GetRoutingID());
-  }
-
-  GetWidget()->ShutdownAndDestroyWidget(false);
-  delete this;
-}
-
 void RenderViewHostImpl::CreateNewWidget(int32_t widget_route_id,
                                          mojom::WidgetPtr widget) {
   delegate_->CreateNewWidget(GetProcess()->GetID(), widget_route_id,
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 0f1443e..fcece6a 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -80,13 +80,8 @@
                      int32_t main_frame_routing_id,
                      bool swapped_out,
                      bool has_initialized_audio_host);
-  // TODO(ajwong): Make destructor private. Deletion of this object should only
-  // be done via ShutdownAndDestroy(). https://crbug.com/545684
   ~RenderViewHostImpl() override;
 
-  // Shuts down this RenderViewHost and deletes it.
-  void ShutdownAndDestroy();
-
   // RenderViewHost implementation.
   bool Send(IPC::Message* msg) override;
   RenderWidgetHostImpl* GetWidget() override;
diff --git a/content/browser/resources/media/OWNERS b/content/browser/resources/media/OWNERS
index f4f6a04..00c172f 100644
--- a/content/browser/resources/media/OWNERS
+++ b/content/browser/resources/media/OWNERS
@@ -1,4 +1,6 @@
 file://media/OWNERS
 tommi@chromium.org
+# For chrome://webrtc-internals related.
+hbos@chromium.org
 
 # COMPONENT: Internals>Media
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index a47da70..d7ea5af 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -774,8 +774,6 @@
   inflight_start_task_->set_start_worker_sent_time(base::TimeTicks::Now());
 
   // The host must be alive as long as |params->provider_info| is alive.
-  DCHECK_EQ(params->provider_info->provider_id,
-            owner_version_->provider_host()->provider_id());
   owner_version_->provider_host()->CompleteStartWorkerPreparation(
       process_id(), MakeRequest(&params->provider_info->interface_provider));
   client_->StartWorker(std::move(params));
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index e7d4110..a4e5f3c 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -180,7 +180,6 @@
       std::move(client_ptr_info), context));
   host->web_contents_getter_ = std::move(web_contents_getter);
 
-  (*out_provider_info)->provider_id = host->provider_id();
   auto weak_ptr = host->AsWeakPtr();
   RegisterToContextCore(context, std::move(host));
   return weak_ptr;
@@ -202,7 +201,6 @@
       std::move(client_ptr_info), context));
   host->running_hosted_version_ = std::move(version);
 
-  (*out_provider_info)->provider_id = host->provider_id();
   auto weak_ptr = host->AsWeakPtr();
   RegisterToContextCore(context, std::move(host));
   return weak_ptr;
@@ -223,7 +221,6 @@
       std::move(client_ptr_info), context));
   host->SetRenderProcessId(process_id);
 
-  (*out_provider_info)->provider_id = host->provider_id();
   auto weak_ptr = host->AsWeakPtr();
   RegisterToContextCore(context, std::move(host));
   return weak_ptr;
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 862bb76..d01657de 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -23,7 +23,6 @@
 #include "components/tracing/common/trace_startup_config.h"
 #include "components/tracing/common/trace_to_console.h"
 #include "components/tracing/common/tracing_switches.h"
-#include "content/browser/browser_shutdown_profile_dumper.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/tracing/file_tracing_provider_impl.h"
 #include "content/browser/tracing/perfetto_file_tracer.h"
@@ -450,8 +449,7 @@
       base::BindRepeating(OnStoppedStartupTracing, startup_trace_file_)));
 }
 
-std::unique_ptr<BrowserShutdownProfileDumper>
-TracingControllerImpl::FinalizeStartupTracingIfNeeded() {
+void TracingControllerImpl::FinalizeStartupTracingIfNeeded() {
   // There are two cases:
   // 1. Startup duration is not reached.
   // 2. Or if the trace should be saved to file for --trace-config-file flag.
@@ -466,14 +464,11 @@
     startup_trace_file = GetStartupTraceFileName();
   }
   if (!startup_trace_file)
-    return nullptr;
-  if (!tracing::TracingUsesPerfettoBackend()) {
-    return std::make_unique<BrowserShutdownProfileDumper>(
-        startup_trace_file.value());
-  }
-  // Perfetto doesn't support shutdown profiling due to complications
-  // around service shutdown timings.
-  // TODO(eseckler): Do something about it.
+    return;
+  // Perfetto currently doesn't support tracing during shutdown as the trace
+  // buffer is lost when the service is shut down, so we wait until the trace is
+  // complete. See also crbug.com/944107.
+  // TODO(eseckler): Avoid the nestedRunLoop here somehow.
   base::RunLoop run_loop;
   StopTracing(CreateFileEndpoint(
       startup_trace_file.value(),
@@ -484,7 +479,6 @@
           },
           startup_trace_file.value(), run_loop.QuitClosure())));
   run_loop.Run();
-  return nullptr;
 }
 
 bool TracingControllerImpl::StopTracing(
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h
index acbad2f..a3acd0b9 100644
--- a/content/browser/tracing/tracing_controller_impl.h
+++ b/content/browser/tracing/tracing_controller_impl.h
@@ -81,11 +81,8 @@
 
   // Should be called before browser main loop shutdown. If startup tracing is
   // tracing to a file and is still active, this stops the duration timer if it
-  // exists and returns a BrowserShutdownProfileDumper that will finalize the
-  // trace file upon its destruction (i.e. startup tracing becomes a version of
-  // shutdown tracing).
-  std::unique_ptr<BrowserShutdownProfileDumper>
-  FinalizeStartupTracingIfNeeded();
+  // exists.
+  void FinalizeStartupTracingIfNeeded();
 
  private:
   friend std::default_delete<TracingControllerImpl>;
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc
index a2bddd60..47f990f9 100644
--- a/content/browser/webauth/authenticator_common.cc
+++ b/content/browser/webauth/authenticator_common.cc
@@ -479,7 +479,7 @@
     response->appid_extension = *echo_appid_extension;
   }
   response_data.user_entity()
-      ? response->user_handle.emplace(response_data.user_entity()->user_id())
+      ? response->user_handle.emplace(response_data.user_entity()->id)
       : response->user_handle.emplace();
   return response;
 }
@@ -569,7 +569,7 @@
     // unreasonably specific assumptions about the clientData JSON. This is
     // done in the fashion of
     // https://tools.ietf.org/html/draft-davidben-tls-grease-01
-    client_data.SetKey("new_keys_may_be_added_here",
+    client_data.SetKey("extra_keys_may_be_added_here",
                        base::Value("do not compare clientDataJSON against a "
                                    "template. See https://goo.gl/yabPex"));
   }
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 788e95b..eaa523ff 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -258,7 +258,7 @@
   std::vector<uint8_t> id(32, 0x0A);
   entity->id = id;
   entity->name = "username@example.com";
-  entity->icon = GURL("fakeurl2.png");
+  entity->icon = GURL("https://gstatic.com/fakeurl2.png");
   return entity;
 }
 
@@ -3244,7 +3244,7 @@
     std::sort(responses.begin(), responses.end(),
               [](const device::AuthenticatorGetAssertionResponse& a,
                  const device::AuthenticatorGetAssertionResponse& b) {
-                return a.user_entity()->user_id() < b.user_entity()->user_id();
+                return a.user_entity()->id < b.user_entity()->id;
               });
 
     std::vector<std::string> string_reps;
@@ -3253,9 +3253,8 @@
         [](const device::AuthenticatorGetAssertionResponse& response) {
           const device::PublicKeyCredentialUserEntity& user =
               response.user_entity().value();
-          return base::HexEncode(user.user_id().data(), user.user_id().size()) +
-                 ":" + user.user_name().value_or("") + ":" +
-                 user.user_display_name().value_or("");
+          return base::HexEncode(user.id.data(), user.id.size()) + ":" +
+                 user.name.value_or("") + ":" + user.display_name.value_or("");
         });
 
     EXPECT_EQ(expected_accounts_, base::JoinString(string_reps, "/"));
@@ -3263,7 +3262,7 @@
     const auto selected = std::find_if(
         responses.begin(), responses.end(),
         [this](const device::AuthenticatorGetAssertionResponse& response) {
-          return response.user_entity()->user_id() == selected_user_id_;
+          return response.user_entity()->id == selected_user_id_;
         });
     ASSERT_TRUE(selected != responses.end());
 
@@ -3377,11 +3376,10 @@
     EXPECT_TRUE(registration.is_resident);
     ASSERT_TRUE(registration.user.has_value());
     const auto options = make_credential_options();
-    EXPECT_EQ(options->user->name, registration.user->user_name());
-    EXPECT_EQ(options->user->display_name,
-              registration.user->user_display_name());
-    EXPECT_EQ(options->user->id, registration.user->user_id());
-    EXPECT_EQ(options->user->icon, registration.user->user_icon_url());
+    EXPECT_EQ(options->user->name, registration.user->name);
+    EXPECT_EQ(options->user->display_name, registration.user->display_name);
+    EXPECT_EQ(options->user->id, registration.user->id);
+    EXPECT_EQ(options->user->icon, registration.user->icon_url);
   }
 }
 
diff --git a/content/browser/webauth/authenticator_type_converters.cc b/content/browser/webauth/authenticator_type_converters.cc
index c032346..c6c8337 100644
--- a/content/browser/webauth/authenticator_type_converters.cc
+++ b/content/browser/webauth/authenticator_type_converters.cc
@@ -181,9 +181,10 @@
               PublicKeyCredentialUserEntityPtr>::
     Convert(const PublicKeyCredentialUserEntityPtr& input) {
   device::PublicKeyCredentialUserEntity user_entity(input->id);
-  user_entity.SetUserName(input->name).SetDisplayName(input->display_name);
+  user_entity.name = input->name;
+  user_entity.display_name = input->display_name;
   if (input->icon)
-    user_entity.SetIconUrl(*input->icon);
+    user_entity.icon_url = *input->icon;
 
   return user_entity;
 }
diff --git a/content/browser/webrtc/webrtc_content_browsertest_base.cc b/content/browser/webrtc/webrtc_content_browsertest_base.cc
index d13dc9b..d4a106b 100644
--- a/content/browser/webrtc/webrtc_content_browsertest_base.cc
+++ b/content/browser/webrtc/webrtc_content_browsertest_base.cc
@@ -47,6 +47,8 @@
 void WebRtcContentBrowserTestBase::SetUp() {
   // We need pixel output when we dig pixels out of video tags for verification.
   EnablePixelOutput();
+  // Some tests capture the audio played out.
+  EnableAudioOutput();
 #if defined(OS_CHROMEOS)
   chromeos::CrasAudioClient::InitializeFake();
   chromeos::CrasAudioHandler::InitializeForTesting();
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index 7a9177d..818311f 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -756,7 +756,9 @@
 }
 
 // Flaky on Win, see https://crbug.com/915135
-#if defined(OS_WIN)
+// Flaky on tsan and asan with accelerated canvases,
+// see https://crbug.com/952381
+#if defined(OS_WIN) || defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
 #define MAYBE_ApplyConstraintsNonDevice DISABLED_ApplyConstraintsNonDevice
 #else
 #define MAYBE_ApplyConstraintsNonDevice ApplyConstraintsNonDevice
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index f8aa1f1..df34e0a 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -387,7 +387,7 @@
           "restrict-lazy-load-frames-to-data-saver-only", false));
   WebRuntimeFeatures::EnableRestrictLazyImageLoadingToDataSaver(
       base::GetFieldTrialParamByFeatureAsBool(
-          features::kLazyFrameLoading,
+          features::kLazyImageLoading,
           "restrict-lazy-load-images-to-data-saver-only", false));
 
   WebRuntimeFeatures::EnablePictureInPicture(
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 55da306a..81efafa 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -45,6 +45,7 @@
 #include "content/public/test/test_utils.h"
 #include "content/test/content_browser_sanity_checker.h"
 #include "gpu/config/gpu_switches.h"
+#include "media/base/media_switches.h"
 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -141,6 +142,7 @@
     : field_trial_list_(std::make_unique<base::FieldTrialList>(nullptr)),
       expected_exit_code_(0),
       enable_pixel_output_(false),
+      enable_audio_output_(false),
       use_software_compositing_(false),
       set_up_called_(false) {
   ui::test::EnableTestConfigForPlatformWindows();
@@ -262,6 +264,11 @@
   if (use_software_gl && !use_software_compositing_)
     command_line->AppendSwitch(switches::kOverrideUseSoftwareGLForTests);
 
+  // Disable audio output to avoid unnecessary error log output from platform
+  // audio layers, unless audio has been specifically requested.
+  if (!enable_audio_output_)
+    command_line->AppendSwitch(switches::kDisableAudioOutput);
+
   // Use an sRGB color profile to ensure that the machine's color profile does
   // not affect the results.
   command_line->AppendSwitchASCII(switches::kForceDisplayColorProfile, "srgb");
@@ -484,6 +491,11 @@
 
 void BrowserTestBase::EnablePixelOutput() { enable_pixel_output_ = true; }
 
+void BrowserTestBase::EnableAudioOutput() {
+  DCHECK(!set_up_called_);
+  enable_audio_output_ = true;
+}
+
 void BrowserTestBase::UseSoftwareCompositing() {
   use_software_compositing_ = true;
 }
diff --git a/content/public/test/browser_test_base.h b/content/public/test/browser_test_base.h
index b7bc20a..0b3eb39 100644
--- a/content/public/test/browser_test_base.h
+++ b/content/public/test/browser_test_base.h
@@ -138,6 +138,10 @@
   // Call this before SetUp() to cause the test to generate pixel output.
   void EnablePixelOutput();
 
+  // Call this before SetUp() to cause audio to be sent to platform audio
+  // devices.
+  void EnableAudioOutput();
+
   // Call this before SetUp() to not use GL, but use software compositing
   // instead.
   void UseSoftwareCompositing();
@@ -178,6 +182,9 @@
   // for pixel tests.
   bool enable_pixel_output_;
 
+  // When true, audio is sent to a real audio device.
+  bool enable_audio_output_;
+
   // When true, do compositing with the software backend instead of using GL.
   bool use_software_compositing_;
 
diff --git a/content/renderer/loader/request_extra_data.cc b/content/renderer/loader/request_extra_data.cc
index 8d6e5002..9f5a39a 100644
--- a/content/renderer/loader/request_extra_data.cc
+++ b/content/renderer/loader/request_extra_data.cc
@@ -22,7 +22,6 @@
 
   request->allow_download = allow_download_;
   request->transition_type = transition_type_;
-  request->service_worker_provider_id = service_worker_provider_id_;
   request->originated_from_service_worker = originated_from_service_worker_;
 
   request->initiated_in_secure_context = initiated_in_secure_context_;
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.cc b/content/renderer/loader/web_worker_fetch_context_impl.cc
index 594454d..231a29b 100644
--- a/content/renderer/loader/web_worker_fetch_context_impl.cc
+++ b/content/renderer/loader/web_worker_fetch_context_impl.cc
@@ -191,14 +191,10 @@
           ChildThreadImpl::current()->thread_safe_sender(),
           ChildThreadImpl::current()->GetConnector()->Clone()));
   if (provider_context) {
-    worker_fetch_context->set_service_worker_provider_id(
-        provider_context->provider_id());
     worker_fetch_context->set_is_controlled_by_service_worker(
         provider_context->IsControlledByServiceWorker());
     worker_fetch_context->set_client_id(provider_context->client_id());
   } else {
-    worker_fetch_context->set_service_worker_provider_id(
-        blink::kInvalidServiceWorkerProviderId);
     worker_fetch_context->set_is_controlled_by_service_worker(
         blink::mojom::ControllerServiceWorkerMode::kNoController);
   }
@@ -281,7 +277,6 @@
                 std::move(task_runner))
           : nullptr,
       thread_safe_sender_.get(), service_manager_connection_->Clone()));
-  new_context->service_worker_provider_id_ = service_worker_provider_id_;
   new_context->is_controlled_by_service_worker_ =
       is_controlled_by_service_worker_;
   new_context->is_on_sub_frame_ = is_on_sub_frame_;
@@ -368,7 +363,6 @@
   }
 
   auto extra_data = std::make_unique<RequestExtraData>();
-  extra_data->set_service_worker_provider_id(service_worker_provider_id_);
   extra_data->set_render_frame_id(ancestor_frame_id_);
   extra_data->set_frame_request_blocker(frame_request_blocker_);
   extra_data->set_initiated_in_secure_context(is_secure_context_);
@@ -460,10 +454,6 @@
       ancestor_frame_id_, std::move(task_runner));
 }
 
-void WebWorkerFetchContextImpl::set_service_worker_provider_id(int id) {
-  service_worker_provider_id_ = id;
-}
-
 void WebWorkerFetchContextImpl::set_is_controlled_by_service_worker(
     blink::mojom::ControllerServiceWorkerMode mode) {
   is_controlled_by_service_worker_ = mode;
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.h b/content/renderer/loader/web_worker_fetch_context_impl.h
index e7561d9..ee7efa1e 100644
--- a/content/renderer/loader/web_worker_fetch_context_impl.h
+++ b/content/renderer/loader/web_worker_fetch_context_impl.h
@@ -114,7 +114,6 @@
   // it's copied from the ancestor frame (directly for non-nested workers, or
   // indirectly via its parent worker for nested workers). For shared workers,
   // it's copied from the shadow page.
-  void set_service_worker_provider_id(int id);
   void set_is_controlled_by_service_worker(
       blink::mojom::ControllerServiceWorkerMode mode);
   void set_ancestor_frame_id(int id);
@@ -199,7 +198,6 @@
   // Consumed on the worker thread to create |fallback_factory_|.
   std::unique_ptr<network::SharedURLLoaderFactoryInfo> fallback_factory_info_;
 
-  int service_worker_provider_id_ = blink::kInvalidServiceWorkerProviderId;
   blink::mojom::ControllerServiceWorkerMode is_controlled_by_service_worker_ =
       blink::mojom::ControllerServiceWorkerMode::kNoController;
 
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index c2b72a6..2a7e6da 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -1018,7 +1018,6 @@
 ServiceWorkerContextClient::CreateServiceWorkerNetworkProviderOnMainThread() {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   return std::make_unique<ServiceWorkerNetworkProviderForServiceWorker>(
-      service_worker_provider_info_->provider_id,
       std::move(service_worker_provider_info_->script_loader_factory_ptr_info));
 }
 
@@ -1051,7 +1050,6 @@
   return base::MakeRefCounted<ServiceWorkerFetchContextImpl>(
       *renderer_preferences_, script_url_, url_loader_factory_bundle->Clone(),
       std::move(script_loader_factory_info),
-      service_worker_provider_info_->provider_id,
       GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
           URLLoaderThrottleProviderType::kWorker),
       GetContentClient()
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index dab84b7..1beabf8 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -280,14 +280,6 @@
     feature_list_.InitAndEnableFeature(network::features::kNetworkService);
   }
 
-  // Creates an empty struct to initialize ServiceWorkerProviderContext.
-  blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr
-  CreateProviderInfo() {
-    auto info = blink::mojom::ServiceWorkerProviderInfoForStartWorker::New();
-    info->provider_id = 10;  // dummy
-    return info;
-  }
-
   // Creates an ContextClient, whose pipes are connected to |out_pipes|, then
   // simulates that the service worker thread has started with |proxy|.
   //
@@ -313,7 +305,8 @@
         false /* is_script_streaming */,
         blink::mojom::RendererPreferences::New(),
         std::move(service_worker_request), std::move(controller_request),
-        embedded_worker_host_ptr.PassInterface(), CreateProviderInfo(),
+        embedded_worker_host_ptr.PassInterface(),
+        blink::mojom::ServiceWorkerProviderInfoForStartWorker::New(),
         embedded_worker_instance_client,
         blink::mojom::EmbeddedWorkerStartTiming::New(),
         nullptr /* preference_watcher_request */,
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index 7ea9dd31..56ff4781 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -26,7 +26,6 @@
         url_loader_factory_info,
     std::unique_ptr<network::SharedURLLoaderFactoryInfo>
         script_loader_factory_info,
-    int service_worker_provider_id,
     std::unique_ptr<URLLoaderThrottleProvider> throttle_provider,
     std::unique_ptr<WebSocketHandshakeThrottleProvider>
         websocket_handshake_throttle_provider,
@@ -35,7 +34,6 @@
       worker_script_url_(worker_script_url),
       url_loader_factory_info_(std::move(url_loader_factory_info)),
       script_loader_factory_info_(std::move(script_loader_factory_info)),
-      service_worker_provider_id_(service_worker_provider_id),
       throttle_provider_(std::move(throttle_provider)),
       websocket_handshake_throttle_provider_(
           std::move(websocket_handshake_throttle_provider)),
@@ -101,7 +99,6 @@
                                "1");
   }
   auto extra_data = std::make_unique<RequestExtraData>();
-  extra_data->set_service_worker_provider_id(service_worker_provider_id_);
   extra_data->set_originated_from_service_worker(true);
   extra_data->set_initiated_in_secure_context(true);
   if (throttle_provider_) {
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index 03efdaf..f1734529 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -35,7 +35,6 @@
           url_loader_factory_info,
       std::unique_ptr<network::SharedURLLoaderFactoryInfo>
           script_loader_factory_info,
-      int service_worker_provider_id,
       std::unique_ptr<URLLoaderThrottleProvider> throttle_provider,
       std::unique_ptr<WebSocketHandshakeThrottleProvider>
           websocket_handshake_throttle_provider,
@@ -73,7 +72,6 @@
   // Consumed on the worker thread to create |web_script_loader_factory_|.
   std::unique_ptr<network::SharedURLLoaderFactoryInfo>
       script_loader_factory_info_;
-  const int service_worker_provider_id_;
 
   // Initialized on the worker thread when InitializeOnWorkerThread() is called.
   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
index f8909fa..caaf9b2a 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
+++ b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
@@ -9,7 +9,7 @@
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/origin_util.h"
 #include "content/public/renderer/render_frame_observer.h"
-#include "content/renderer/loader/request_extra_data.h"
+#include "content/renderer/loader/web_url_loader_impl.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
@@ -66,7 +66,6 @@
   auto provider =
       base::WrapUnique(new ServiceWorkerNetworkProviderForFrame(frame));
   provider->context_ = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      provider_info->provider_id,
       blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(provider_info->client_request),
       std::move(provider_info->host_ptr_info), std::move(controller_info),
@@ -94,11 +93,6 @@
 
 void ServiceWorkerNetworkProviderForFrame::WillSendRequest(
     blink::WebURLRequest& request) {
-  if (!request.GetExtraData())
-    request.SetExtraData(std::make_unique<RequestExtraData>());
-  auto* extra_data = static_cast<RequestExtraData*>(request.GetExtraData());
-  extra_data->set_service_worker_provider_id(provider_id());
-
   // Inject this frame's fetch window id into the request.
   if (context())
     request.SetFetchWindowId(context()->fetch_request_window_id());
@@ -162,12 +156,6 @@
   context()->DispatchNetworkQuiet();
 }
 
-int ServiceWorkerNetworkProviderForFrame::provider_id() const {
-  if (!context_)
-    return blink::kInvalidServiceWorkerProviderId;
-  return context_->provider_id();
-}
-
 void ServiceWorkerNetworkProviderForFrame::NotifyExecutionReady() {
   if (context())
     context()->NotifyExecutionReady();
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_frame.h b/content/renderer/service_worker/service_worker_network_provider_for_frame.h
index c70b045..c3cba01 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_frame.h
+++ b/content/renderer/service_worker/service_worker_network_provider_for_frame.h
@@ -53,7 +53,6 @@
   int64_t ControllerServiceWorkerID() override;
   void DispatchNetworkQuiet() override;
 
-  int provider_id() const;
   ServiceWorkerProviderContext* context() { return context_.get(); }
 
  private:
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_service_worker.cc b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.cc
index 0bae4f8..6fc87a0 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_service_worker.cc
+++ b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.cc
@@ -22,11 +22,9 @@
 
 ServiceWorkerNetworkProviderForServiceWorker::
     ServiceWorkerNetworkProviderForServiceWorker(
-        int provider_id,
         network::mojom::URLLoaderFactoryAssociatedPtrInfo
             script_loader_factory_info)
-    : provider_id_(provider_id),
-      script_loader_factory_(std::move(script_loader_factory_info)) {}
+    : script_loader_factory_(std::move(script_loader_factory_info)) {}
 
 ServiceWorkerNetworkProviderForServiceWorker::
     ~ServiceWorkerNetworkProviderForServiceWorker() = default;
@@ -34,7 +32,6 @@
 void ServiceWorkerNetworkProviderForServiceWorker::WillSendRequest(
     blink::WebURLRequest& request) {
   auto extra_data = std::make_unique<RequestExtraData>();
-  extra_data->set_service_worker_provider_id(provider_id_);
   extra_data->set_originated_from_service_worker(true);
   // Service workers are only available in secure contexts, so all requests
   // are initiated in a secure context.
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h
index 6841e3c..9f54c3ea 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h
+++ b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h
@@ -21,8 +21,7 @@
 class ServiceWorkerNetworkProviderForServiceWorker final
     : public blink::WebServiceWorkerNetworkProvider {
  public:
-  ServiceWorkerNetworkProviderForServiceWorker(
-      int provider_id,
+  explicit ServiceWorkerNetworkProviderForServiceWorker(
       network::mojom::URLLoaderFactoryAssociatedPtrInfo
           script_loader_factory_info);
   ~ServiceWorkerNetworkProviderForServiceWorker() override;
@@ -43,7 +42,6 @@
   }
 
  private:
-  const int provider_id_;
   // The URL loader factory for loading the service worker's scripts.
   network::mojom::URLLoaderFactoryAssociatedPtr script_loader_factory_;
 };
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index 71d593e..866096a 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -56,14 +56,12 @@
 
 // For service worker clients.
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(
-    int provider_id,
     blink::mojom::ServiceWorkerProviderType provider_type,
     blink::mojom::ServiceWorkerContainerAssociatedRequest request,
     blink::mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info,
     blink::mojom::ControllerServiceWorkerInfoPtr controller_info,
     scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory)
     : provider_type_(provider_type),
-      provider_id_(provider_id),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       binding_(this, std::move(request)),
       weak_factory_(this) {
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h
index c58cfc0..a0d0803 100644
--- a/content/renderer/service_worker/service_worker_provider_context.h
+++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -64,9 +64,8 @@
       public blink::mojom::ServiceWorkerContainer,
       public blink::mojom::ServiceWorkerWorkerClientRegistry {
  public:
-  // |provider_id| is used to identify this provider in IPC messages to the
-  // browser process. |request| is an endpoint which is connected to
-  // the content::ServiceWorkerProviderHost that notifies of changes to the
+  // |request| is an endpoint which is connected to the
+  // content::ServiceWorkerProviderHost that notifies of changes to the
   // registration's and workers' status. |request| is bound with |binding_|.
   //
   // |controller_info| contains the endpoint and object info that is needed to
@@ -77,7 +76,6 @@
   // This is non-null only if the provider is created for controllees, and if
   // the loading context, e.g. a frame, provides it.
   ServiceWorkerProviderContext(
-      int provider_id,
       blink::mojom::ServiceWorkerProviderType provider_type,
       blink::mojom::ServiceWorkerContainerAssociatedRequest request,
       blink::mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info,
@@ -88,8 +86,6 @@
     return provider_type_;
   }
 
-  int provider_id() const { return provider_id_; }
-
   // Returns version id of the controller service worker object
   // (ServiceWorkerContainer#controller).
   int64_t GetControllerVersionId() const;
@@ -195,7 +191,6 @@
   bool CanCreateSubresourceLoaderFactory() const;
 
   const blink::mojom::ServiceWorkerProviderType provider_type_;
-  const int provider_id_;
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
 
   // Mojo binding for the |request| passed to the constructor. This keeps the
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index cf3722e..263e08c 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -302,8 +302,6 @@
 };
 
 TEST_F(ServiceWorkerProviderContextTest, SetController) {
-  const int kProviderId = 10;
-
   {
     auto mock_service_worker_object_host =
         std::make_unique<MockServiceWorkerObjectHost>(200 /* version_id */);
@@ -323,7 +321,7 @@
     blink::mojom::ServiceWorkerContainerAssociatedRequest container_request =
         mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
     auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-        kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+        blink::mojom::ServiceWorkerProviderType::kForWindow,
         std::move(container_request), host_ptr.PassInterface(),
         nullptr /* controller_info */, nullptr /* loader_factory*/);
 
@@ -362,7 +360,7 @@
     blink::mojom::ServiceWorkerContainerAssociatedRequest container_request =
         mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
     auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-        kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+        blink::mojom::ServiceWorkerProviderType::kForWindow,
         std::move(container_request), host_ptr.PassInterface(),
         nullptr /* controller_info */, nullptr /* loader_factory*/);
     auto provider_impl =
@@ -386,8 +384,6 @@
 // Test that clearing the controller by sending a nullptr object info results in
 // the provider context having a null controller.
 TEST_F(ServiceWorkerProviderContextTest, SetController_Null) {
-  const int kProviderId = 10;
-
   blink::mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr;
   blink::mojom::ServiceWorkerContainerHostAssociatedRequest host_request =
       mojo::MakeRequestAssociatedWithDedicatedPipe(&host_ptr);
@@ -396,7 +392,7 @@
   blink::mojom::ServiceWorkerContainerAssociatedRequest container_request =
       mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+      blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), host_ptr.PassInterface(),
       nullptr /* controller_info */, nullptr /* loader_factory*/);
   auto provider_impl =
@@ -416,7 +412,6 @@
 // worker for clients.
 TEST_F(ServiceWorkerProviderContextTest, SetControllerServiceWorker) {
   EnableNetworkService();
-  const int kProviderId = 10;
 
   // Make the ServiceWorkerContainerHost implementation and
   // ServiceWorkerContainer request.
@@ -450,7 +445,7 @@
   // Make the ServiceWorkerProviderContext, pasing it the controller, container,
   // and container host.
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+      blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), host_ptr.PassInterface(),
       std::move(controller_info1), loader_factory_);
 
@@ -607,7 +602,6 @@
 
 TEST_F(ServiceWorkerProviderContextTest, ControllerWithoutFetchHandler) {
   EnableNetworkService();
-  const int kProviderId = 10;
   auto object_host =
       std::make_unique<MockServiceWorkerObjectHost>(200 /* version_id */);
 
@@ -624,7 +618,7 @@
   blink::mojom::ServiceWorkerContainerAssociatedRequest container_request =
       mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+      blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), nullptr /* host_ptr_info */,
       std::move(controller_info), loader_factory_);
   base::RunLoop().RunUntilIdle();
@@ -634,8 +628,6 @@
 }
 
 TEST_F(ServiceWorkerProviderContextTest, PostMessageToClient) {
-  const int kProviderId = 10;
-
   auto mock_service_worker_object_host =
       std::make_unique<MockServiceWorkerObjectHost>(200 /* version_id */);
   ASSERT_EQ(0, mock_service_worker_object_host->GetBindingCount());
@@ -651,7 +643,7 @@
   blink::mojom::ServiceWorkerContainerAssociatedRequest container_request =
       mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+      blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), host_ptr.PassInterface(),
       nullptr /* controller_info */, nullptr /* loader_factory*/);
   auto provider_impl =
@@ -671,8 +663,6 @@
 }
 
 TEST_F(ServiceWorkerProviderContextTest, CountFeature) {
-  const int kProviderId = 10;
-
   blink::mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr;
   blink::mojom::ServiceWorkerContainerHostAssociatedRequest host_request =
       mojo::MakeRequestAssociatedWithDedicatedPipe(&host_ptr);
@@ -681,7 +671,7 @@
   blink::mojom::ServiceWorkerContainerAssociatedRequest container_request =
       mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
+      blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), host_ptr.PassInterface(),
       nullptr /* controller_info */, nullptr /* loader_factory*/);
   auto provider_impl =
@@ -732,7 +722,7 @@
 
   // Make the provider context.
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      11 /* provider_id */, blink::mojom::ServiceWorkerProviderType::kForWindow,
+      blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), host_ptr.PassInterface(),
       std::move(controller_info), loader_factory_);
 
diff --git a/content/renderer/worker/dedicated_worker_host_factory_client.cc b/content/renderer/worker/dedicated_worker_host_factory_client.cc
index 6cf5bb11..308587b6 100644
--- a/content/renderer/worker/dedicated_worker_host_factory_client.cc
+++ b/content/renderer/worker/dedicated_worker_host_factory_client.cc
@@ -97,7 +97,6 @@
   DCHECK(!service_worker_provider_context_);
   service_worker_provider_context_ =
       base::MakeRefCounted<ServiceWorkerProviderContext>(
-          service_worker_provider_info->provider_id,
           blink::mojom::ServiceWorkerProviderType::kForSharedWorker,
           std::move(service_worker_provider_info->client_request),
           std::move(service_worker_provider_info->host_ptr_info),
diff --git a/content/renderer/worker/service_worker_network_provider_for_worker.cc b/content/renderer/worker/service_worker_network_provider_for_worker.cc
index d3baa45..631983f 100644
--- a/content/renderer/worker/service_worker_network_provider_for_worker.cc
+++ b/content/renderer/worker/service_worker_network_provider_for_worker.cc
@@ -34,7 +34,6 @@
   auto provider = base::WrapUnique(new ServiceWorkerNetworkProviderForWorker(
       is_secure_context, std::move(response_override)));
   provider->context_ = base::MakeRefCounted<ServiceWorkerProviderContext>(
-      info->provider_id,
       blink::mojom::ServiceWorkerProviderType::kForSharedWorker,
       std::move(info->client_request), std::move(info->host_ptr_info),
       std::move(controller_info), std::move(fallback_loader_factory));
@@ -54,7 +53,6 @@
 void ServiceWorkerNetworkProviderForWorker::WillSendRequest(
     blink::WebURLRequest& request) {
   auto extra_data = std::make_unique<RequestExtraData>();
-  extra_data->set_service_worker_provider_id(provider_id());
   extra_data->set_initiated_in_secure_context(is_secure_context_);
   if (response_override_) {
     DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
@@ -113,12 +111,6 @@
 
 void ServiceWorkerNetworkProviderForWorker::DispatchNetworkQuiet() {}
 
-int ServiceWorkerNetworkProviderForWorker::provider_id() const {
-  if (!context_)
-    return blink::kInvalidServiceWorkerProviderId;
-  return context_->provider_id();
-}
-
 ServiceWorkerNetworkProviderForWorker::ServiceWorkerNetworkProviderForWorker(
     bool is_secure_context,
     std::unique_ptr<NavigationResponseOverrideParameters> response_override)
diff --git a/content/renderer/worker/service_worker_network_provider_for_worker.h b/content/renderer/worker/service_worker_network_provider_for_worker.h
index 4b194e3c..72cf038 100644
--- a/content/renderer/worker/service_worker_network_provider_for_worker.h
+++ b/content/renderer/worker/service_worker_network_provider_for_worker.h
@@ -61,7 +61,6 @@
   int64_t ControllerServiceWorkerID() override;
   void DispatchNetworkQuiet() override;
 
-  int provider_id() const;
   ServiceWorkerProviderContext* context() { return context_.get(); }
 
  private:
diff --git a/content/shell/browser/web_test/web_test_browser_main.cc b/content/shell/browser/web_test/web_test_browser_main.cc
index 24603f7..3ec1a58 100644
--- a/content/shell/browser/web_test/web_test_browser_main.cc
+++ b/content/shell/browser/web_test/web_test_browser_main.cc
@@ -31,6 +31,7 @@
 #include "content/shell/common/web_test/web_test_switches.h"
 #include "content/shell/renderer/web_test/blink_test_helpers.h"
 #include "gpu/config/gpu_switches.h"
+#include "media/base/media_switches.h"
 #include "net/base/filename_util.h"
 
 #if defined(OS_ANDROID)
@@ -136,6 +137,13 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisableGpuProcessForDX12VulkanInfoCollection);
 
+  // Disable audio output to avoid unnecessary log output from platform audio
+  // layers. Seems to cause flakiness on Mac.
+#if !defined(OS_MACOSX)
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kDisableAudioOutput);
+#endif
+
 #if defined(OS_ANDROID)
   content::ScopedAndroidConfiguration android_configuration;
 #endif
diff --git a/device/fido/authenticator_get_assertion_response.cc b/device/fido/authenticator_get_assertion_response.cc
index 2ec556d..72c3458 100644
--- a/device/fido/authenticator_get_assertion_response.cc
+++ b/device/fido/authenticator_get_assertion_response.cc
@@ -108,7 +108,8 @@
   response_map.emplace(3, response.signature());
 
   if (response.user_entity()) {
-    response_map.emplace(4, response.user_entity()->ConvertToCBOR());
+    response_map.emplace(4, PublicKeyCredentialUserEntity::ConvertToCBOR(
+                                *response.user_entity()));
   }
   if (response.num_credentials()) {
     response_map.emplace(5, response.num_credentials().value());
diff --git a/device/fido/ctap_make_credential_request.cc b/device/fido/ctap_make_credential_request.cc
index 549a2b8..f6bac1d 100644
--- a/device/fido/ctap_make_credential_request.cc
+++ b/device/fido/ctap_make_credential_request.cc
@@ -46,7 +46,8 @@
   cbor::Value::MapValue cbor_map;
   cbor_map[cbor::Value(1)] = cbor::Value(client_data_hash_);
   cbor_map[cbor::Value(2)] = rp_.ConvertToCBOR();
-  cbor_map[cbor::Value(3)] = user_.ConvertToCBOR();
+  cbor_map[cbor::Value(3)] =
+      PublicKeyCredentialUserEntity::ConvertToCBOR(user_);
   cbor_map[cbor::Value(4)] = public_key_credential_params_.ConvertToCBOR();
   if (exclude_list_) {
     cbor::Value::ArrayValue exclude_list_array;
diff --git a/device/fido/ctap_request_unittest.cc b/device/fido/ctap_request_unittest.cc
index 31cc2b2..79564184 100644
--- a/device/fido/ctap_request_unittest.cc
+++ b/device/fido/ctap_request_unittest.cc
@@ -23,9 +23,9 @@
 
   PublicKeyCredentialUserEntity user(
       fido_parsing_utils::Materialize(test_data::kUserId));
-  user.SetUserName("johnpsmith@example.com")
-      .SetDisplayName("John P. Smith")
-      .SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
+  user.name = "johnpsmith@example.com";
+  user.display_name = "John P. Smith";
+  user.icon_url = GURL("https://pics.acme.com/00/p/aBjjjpqPb.png");
 
   CtapMakeCredentialRequest make_credential_param(
       test_data::kClientDataJson, std::move(rp), std::move(user),
@@ -94,15 +94,15 @@
               ::testing::ElementsAreArray(test_data::kClientDataHash));
   EXPECT_EQ(test_data::kRelyingPartyId, request.rp().rp_id());
   EXPECT_EQ("Acme", request.rp().rp_name());
-  EXPECT_THAT(request.user().user_id(),
+  EXPECT_THAT(request.user().id,
               ::testing::ElementsAreArray(test_data::kUserId));
-  ASSERT_TRUE(request.user().user_name());
-  EXPECT_EQ("johnpsmith@example.com", *request.user().user_name());
-  ASSERT_TRUE(request.user().user_display_name());
-  EXPECT_EQ("John P. Smith", *request.user().user_display_name());
-  ASSERT_TRUE(request.user().user_icon_url());
+  ASSERT_TRUE(request.user().name);
+  EXPECT_EQ("johnpsmith@example.com", *request.user().name);
+  ASSERT_TRUE(request.user().display_name);
+  EXPECT_EQ("John P. Smith", *request.user().display_name);
+  ASSERT_TRUE(request.user().icon_url);
   EXPECT_EQ("https://pics.acme.com/00/p/aBjjjpqPb.png",
-            request.user().user_icon_url()->spec());
+            request.user().icon_url->spec());
   ASSERT_EQ(2u, request.public_key_credential_params()
                     .public_key_credential_params()
                     .size());
diff --git a/device/fido/ctap_response_unittest.cc b/device/fido/ctap_response_unittest.cc
index 87edc93..f57121f1 100644
--- a/device/fido/ctap_response_unittest.cc
+++ b/device/fido/ctap_response_unittest.cc
@@ -742,9 +742,9 @@
   response.SetCredential({CredentialType::kPublicKey,
                           fido_parsing_utils::Materialize(kCredentialId)});
   PublicKeyCredentialUserEntity user(fido_parsing_utils::Materialize(kUserId));
-  user.SetDisplayName("John P. Smith");
-  user.SetUserName("johnpsmith@example.com");
-  user.SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
+  user.display_name = "John P. Smith";
+  user.name = "johnpsmith@example.com";
+  user.icon_url = GURL("https://pics.acme.com/00/p/aBjjjpqPb.png");
   response.SetUserEntity(std::move(user));
   response.SetNumCredentials(1);
 
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc
index c3e700e..fa516c3 100644
--- a/device/fido/get_assertion_request_handler.cc
+++ b/device/fido/get_assertion_request_handler.cc
@@ -44,8 +44,8 @@
   // published.
   const auto& user_entity = response.user_entity();
   const bool has_user_identifying_info =
-      user_entity && (user_entity->user_display_name() ||
-                      user_entity->user_name() || user_entity->user_icon_url());
+      user_entity &&
+      (user_entity->display_name || user_entity->name || user_entity->icon_url);
   if (!response.auth_data().obtained_user_verification() &&
       has_user_identifying_info) {
     return false;
diff --git a/device/fido/mac/credential_metadata.cc b/device/fido/mac/credential_metadata.cc
index 54c69ed..2dcd6c05 100644
--- a/device/fido/mac/credential_metadata.cc
+++ b/device/fido/mac/credential_metadata.cc
@@ -41,19 +41,18 @@
 CredentialMetadata::UserEntity
 CredentialMetadata::UserEntity::FromPublicKeyCredentialUserEntity(
     const PublicKeyCredentialUserEntity& user) {
-  return CredentialMetadata::UserEntity(user.user_id(),
-                                        user.user_name().value_or(""),
-                                        user.user_display_name().value_or(""));
+  return CredentialMetadata::UserEntity(user.id, user.name.value_or(""),
+                                        user.display_name.value_or(""));
 }
 
 PublicKeyCredentialUserEntity
 CredentialMetadata::UserEntity::ToPublicKeyCredentialUserEntity() {
   auto user_entity = PublicKeyCredentialUserEntity(id);
   if (!name.empty()) {
-    user_entity.SetUserName(name);
+    user_entity.name = name;
   }
   if (!display_name.empty()) {
-    user_entity.SetDisplayName(display_name);
+    user_entity.display_name = display_name;
   }
   return user_entity;
 }
diff --git a/device/fido/mac/credential_metadata_unittest.cc b/device/fido/mac/credential_metadata_unittest.cc
index 48bf13ad..6d47530 100644
--- a/device/fido/mac/credential_metadata_unittest.cc
+++ b/device/fido/mac/credential_metadata_unittest.cc
@@ -127,9 +127,9 @@
 TEST(CredentialMetadata, FromPublicKeyCredentialUserEntity) {
   std::vector<uint8_t> user_id = {{1, 2, 3}};
   PublicKeyCredentialUserEntity in(user_id);
-  in.SetUserName("username");
-  in.SetDisplayName("display name");
-  in.SetIconUrl(GURL("http://rp.foo/user.png"));
+  in.name = "username";
+  in.display_name = "display name";
+  in.icon_url = GURL("http://rp.foo/user.png");
   CredentialMetadata::UserEntity out =
       CredentialMetadata::UserEntity::FromPublicKeyCredentialUserEntity(
           std::move(in));
@@ -142,10 +142,10 @@
   std::vector<uint8_t> user_id = {{1, 2, 3}};
   CredentialMetadata::UserEntity in(user_id, "username", "display name");
   PublicKeyCredentialUserEntity out = in.ToPublicKeyCredentialUserEntity();
-  EXPECT_EQ(user_id, out.user_id());
-  EXPECT_EQ("username", out.user_name().value());
-  EXPECT_EQ("display name", out.user_display_name().value());
-  EXPECT_FALSE(out.user_icon_url().has_value());
+  EXPECT_EQ(user_id, out.id);
+  EXPECT_EQ("username", out.name.value());
+  EXPECT_EQ("display name", out.display_name.value());
+  EXPECT_FALSE(out.icon_url.has_value());
 }
 
 }  // namespace
diff --git a/device/fido/mac/make_credential_operation.mm b/device/fido/mac/make_credential_operation.mm
index 17ab1b8..927b8b1b 100644
--- a/device/fido/mac/make_credential_operation.mm
+++ b/device/fido/mac/make_credential_operation.mm
@@ -115,7 +115,7 @@
   // Delete the key pair for this RP + user handle if one already exists.
   base::Optional<std::string> encoded_rp_id_user_id =
       CredentialMetadata::EncodeRpIdAndUserId(metadata_secret(), RpId(),
-                                              request().user().user_id());
+                                              request().user().id);
   if (!encoded_rp_id_user_id) {
     // Internal error.
     std::move(callback())
diff --git a/device/fido/make_credential_task.cc b/device/fido/make_credential_task.cc
index cc9bbe77..7a75949 100644
--- a/device/fido/make_credential_task.cc
+++ b/device/fido/make_credential_task.cc
@@ -68,7 +68,7 @@
   // created. This does assume that the device supports ECDSA P-256, however.
   PublicKeyCredentialUserEntity user({1} /* user ID */);
   // The user name is incorrectly marked as optional in the CTAP2 spec.
-  user.SetUserName("dummy");
+  user.name = "dummy";
   CtapMakeCredentialRequest req(
       "" /* client_data_json */, PublicKeyCredentialRpEntity(".dummy"),
       std::move(user),
diff --git a/device/fido/public_key_credential_user_entity.cc b/device/fido/public_key_credential_user_entity.cc
index 7db7cb8..990bc5d4 100644
--- a/device/fido/public_key_credential_user_entity.cc
+++ b/device/fido/public_key_credential_user_entity.cc
@@ -18,34 +18,59 @@
 
   const cbor::Value::MapValue& cbor_map = cbor.GetMap();
 
-  auto user_id = cbor_map.find(cbor::Value(kEntityIdMapKey));
-  if (user_id == cbor_map.end() || !user_id->second.is_bytestring())
+  auto id_it = cbor_map.find(cbor::Value(kEntityIdMapKey));
+  if (id_it == cbor_map.end() || !id_it->second.is_bytestring())
     return base::nullopt;
 
-  PublicKeyCredentialUserEntity user(user_id->second.GetBytestring());
+  PublicKeyCredentialUserEntity user(id_it->second.GetBytestring());
 
-  auto user_name = cbor_map.find(cbor::Value(kEntityNameMapKey));
-  if (user_name != cbor_map.end() && user_name->second.is_string()) {
-    user.SetUserName(user_name->second.GetString());
+  auto name_it = cbor_map.find(cbor::Value(kEntityNameMapKey));
+  if (name_it != cbor_map.end()) {
+    if (!name_it->second.is_string()) {
+      return base::nullopt;
+    }
+    user.name = name_it->second.GetString();
   }
 
-  auto user_display_name = cbor_map.find(cbor::Value(kDisplayNameMapKey));
-  if (user_display_name != cbor_map.end() &&
-      user_display_name->second.is_string()) {
-    user.SetDisplayName(user_display_name->second.GetString());
+  auto display_name_it = cbor_map.find(cbor::Value(kDisplayNameMapKey));
+  if (display_name_it != cbor_map.end()) {
+    if (!display_name_it->second.is_string()) {
+      return base::nullopt;
+    }
+    user.display_name = display_name_it->second.GetString();
   }
 
-  auto user_icon_url = cbor_map.find(cbor::Value(kIconUrlMapKey));
-  if (user_icon_url != cbor_map.end() && user_icon_url->second.is_string()) {
-    user.SetIconUrl(GURL(user_icon_url->second.GetString()));
+  auto icon_it = cbor_map.find(cbor::Value(kIconUrlMapKey));
+  if (icon_it != cbor_map.end()) {
+    if (!icon_it->second.is_string()) {
+      return base::nullopt;
+    }
+    user.icon_url = GURL(icon_it->second.GetString());
+    if (!user.icon_url->is_valid()) {
+      return base::nullopt;
+    }
   }
 
   return user;
 }
 
+// static
+cbor::Value PublicKeyCredentialUserEntity::ConvertToCBOR(
+    const PublicKeyCredentialUserEntity& user) {
+  cbor::Value::MapValue user_map;
+  user_map.emplace(kEntityIdMapKey, user.id);
+  if (user.name)
+    user_map.emplace(kEntityNameMapKey, *user.name);
+  if (user.icon_url)
+    user_map.emplace(kIconUrlMapKey, user.icon_url->spec());
+  if (user.display_name)
+    user_map.emplace(kDisplayNameMapKey, *user.display_name);
+  return cbor::Value(std::move(user_map));
+}
+
 PublicKeyCredentialUserEntity::PublicKeyCredentialUserEntity(
-    std::vector<uint8_t> user_id)
-    : user_id_(std::move(user_id)) {}
+    std::vector<uint8_t> in_id)
+    : id(std::move(in_id)) {}
 
 PublicKeyCredentialUserEntity::PublicKeyCredentialUserEntity(
     const PublicKeyCredentialUserEntity& other) = default;
@@ -61,35 +86,6 @@
 
 PublicKeyCredentialUserEntity::~PublicKeyCredentialUserEntity() = default;
 
-cbor::Value PublicKeyCredentialUserEntity::ConvertToCBOR() const {
-  cbor::Value::MapValue user_map;
-  user_map.emplace(kEntityIdMapKey, user_id_);
-  if (user_name_)
-    user_map.emplace(kEntityNameMapKey, *user_name_);
-  if (user_icon_url_)
-    user_map.emplace(kIconUrlMapKey, user_icon_url_->spec());
-  if (user_display_name_) {
-    user_map.emplace(kDisplayNameMapKey, *user_display_name_);
-  }
-  return cbor::Value(std::move(user_map));
-}
 
-PublicKeyCredentialUserEntity& PublicKeyCredentialUserEntity::SetUserName(
-    std::string user_name) {
-  user_name_ = std::move(user_name);
-  return *this;
-}
-
-PublicKeyCredentialUserEntity& PublicKeyCredentialUserEntity::SetDisplayName(
-    std::string user_display_name) {
-  user_display_name_ = std::move(user_display_name);
-  return *this;
-}
-
-PublicKeyCredentialUserEntity& PublicKeyCredentialUserEntity::SetIconUrl(
-    GURL icon_url) {
-  user_icon_url_ = std::move(icon_url);
-  return *this;
-}
 
 }  // namespace device
diff --git a/device/fido/public_key_credential_user_entity.h b/device/fido/public_key_credential_user_entity.h
index fcd77eb9..58ccf068 100644
--- a/device/fido/public_key_credential_user_entity.h
+++ b/device/fido/public_key_credential_user_entity.h
@@ -24,8 +24,9 @@
  public:
   static base::Optional<PublicKeyCredentialUserEntity> CreateFromCBORValue(
       const cbor::Value& cbor);
+  static cbor::Value ConvertToCBOR(const PublicKeyCredentialUserEntity& user);
 
-  explicit PublicKeyCredentialUserEntity(std::vector<uint8_t> user_id);
+  explicit PublicKeyCredentialUserEntity(std::vector<uint8_t> id);
   PublicKeyCredentialUserEntity(const PublicKeyCredentialUserEntity& other);
   PublicKeyCredentialUserEntity(PublicKeyCredentialUserEntity&& other);
   PublicKeyCredentialUserEntity& operator=(
@@ -34,23 +35,10 @@
       PublicKeyCredentialUserEntity&& other);
   ~PublicKeyCredentialUserEntity();
 
-  cbor::Value ConvertToCBOR() const;
-  PublicKeyCredentialUserEntity& SetUserName(std::string user_name);
-  PublicKeyCredentialUserEntity& SetDisplayName(std::string display_name);
-  PublicKeyCredentialUserEntity& SetIconUrl(GURL icon_url);
-
-  const std::vector<uint8_t>& user_id() const { return user_id_; }
-  const base::Optional<std::string>& user_name() const { return user_name_; }
-  const base::Optional<std::string>& user_display_name() const {
-    return user_display_name_;
-  }
-  const base::Optional<GURL>& user_icon_url() const { return user_icon_url_; }
-
- private:
-  std::vector<uint8_t> user_id_;
-  base::Optional<std::string> user_name_;
-  base::Optional<std::string> user_display_name_;
-  base::Optional<GURL> user_icon_url_;
+  std::vector<uint8_t> id;
+  base::Optional<std::string> name;
+  base::Optional<std::string> display_name;
+  base::Optional<GURL> icon_url;
 };
 
 }  // namespace device
diff --git a/device/fido/u2f_command_constructor_unittest.cc b/device/fido/u2f_command_constructor_unittest.cc
index de3003a..deadbc8 100644
--- a/device/fido/u2f_command_constructor_unittest.cc
+++ b/device/fido/u2f_command_constructor_unittest.cc
@@ -24,9 +24,9 @@
 
   PublicKeyCredentialUserEntity user(
       fido_parsing_utils::Materialize(test_data::kUserId));
-  user.SetUserName("johnpsmith@example.com")
-      .SetDisplayName("John P. Smith")
-      .SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
+  user.name = "johnpsmith@example.com";
+  user.display_name = "John P. Smith";
+  user.icon_url = GURL("https://pics.acme.com/00/p/aBjjjpqPb.png");
 
   return CtapMakeCredentialRequest(
       test_data::kClientDataJson, std::move(rp), std::move(user),
@@ -77,9 +77,9 @@
 
   PublicKeyCredentialUserEntity user(
       fido_parsing_utils::Materialize(test_data::kUserId));
-  user.SetUserName("johnpsmith@example.com")
-      .SetDisplayName("John P. Smith")
-      .SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
+  user.name = "johnpsmith@example.com";
+  user.display_name = "John P. Smith";
+  user.icon_url = GURL("https://pics.acme.com/00/p/aBjjjpqPb.png");
 
   CtapMakeCredentialRequest make_credential_param(
       test_data::kClientDataJson, std::move(rp), std::move(user),
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index 9a1971c1..4b89567 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -644,7 +644,7 @@
     for (const auto& registration : mutable_state()->registrations) {
       if (registration.second.is_resident &&
           rp_id_hash == registration.second.application_parameter &&
-          registration.second.user->user_id() == request.user().user_id()) {
+          registration.second.user->id == request.user().id) {
         mutable_state()->registrations.erase(registration.first);
         break;
       }
diff --git a/device/fido/virtual_fido_device.cc b/device/fido/virtual_fido_device.cc
index e0e07bb..d40f9c2 100644
--- a/device/fido/virtual_fido_device.cc
+++ b/device/fido/virtual_fido_device.cc
@@ -93,7 +93,7 @@
   for (const auto& registration : registrations) {
     if (registration.second.is_resident &&
         application_parameter == registration.second.application_parameter &&
-        user_id == registration.second.user->user_id()) {
+        user_id == registration.second.user->id) {
       return false;
     }
   }
@@ -105,9 +105,10 @@
                                 std::move(application_parameter),
                                 0 /* signature counter */);
   registration.is_resident = true;
-  registration.user = device::PublicKeyCredentialUserEntity(user_id);
-  registration.user->SetUserName(name);
-  registration.user->SetDisplayName(display_name);
+  PublicKeyCredentialUserEntity user(user_id);
+  user.name = name;
+  user.display_name = display_name;
+  registration.user = std::move(user);
 
   bool was_inserted;
   std::tie(std::ignore, was_inserted) =
diff --git a/device/fido/win/webauthn_api.cc b/device/fido/win/webauthn_api.cc
index e653ffb..1436800 100644
--- a/device/fido/win/webauthn_api.cc
+++ b/device/fido/win/webauthn_api.cc
@@ -204,12 +204,11 @@
       rp_name.c_str(), rp_icon_url.c_str()};
 
   base::string16 user_name =
-      base::UTF8ToUTF16(request.user().user_name().value_or(""));
-  base::string16 user_icon_url =
-      OptionalGURLToUTF16(request.user().user_icon_url());
+      base::UTF8ToUTF16(request.user().name.value_or(""));
+  base::string16 user_icon_url = OptionalGURLToUTF16(request.user().icon_url);
   base::string16 user_display_name =
-      base::UTF8ToUTF16(request.user().user_display_name().value_or(""));
-  std::vector<uint8_t> user_id = request.user().user_id();
+      base::UTF8ToUTF16(request.user().display_name.value_or(""));
+  std::vector<uint8_t> user_id = request.user().id;
   WEBAUTHN_USER_ENTITY_INFORMATION user_info{
       WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION,
       user_id.size(),
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 748c0d1..c696f079 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -4031,7 +4031,6 @@
     # Linux
 
     builders { mixins: "linux"  name: "WebRTC Chromium Linux Builder" }
-    builders { mixins: "linux"  name: "WebRTC Chromium Linux Builder (RBE)" }
     builders { mixins: "linux"  name: "WebRTC Chromium Linux Tester" }
 
     # Mac
@@ -4093,9 +4092,7 @@
     # Linux
 
     builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (RBE)" }
     builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (dbg)" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)" }
     builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Tester" }
 
     # Mac
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 66ff7341..5e3c975 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3595,11 +3595,6 @@
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.webrtc/WebRTC Chromium Linux Builder (RBE)"
-    category: "linux"
-    short_name: "rbe"
-  }
-  builders {
     name: "buildbucket/luci.chromium.webrtc/WebRTC Chromium Linux Tester"
     category: "linux"
     short_name: "tst"
@@ -3674,21 +3669,11 @@
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
-    category: "linux|debug"
-    short_name: "rbe"
-  }
-  builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Builder"
     category: "linux|release"
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Builder (RBE)"
-    category: "linux|release"
-    short_name: "rbe"
-  }
-  builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Tester"
     category: "linux|release"
     short_name: "tst"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index 1df4b78..e0bb21b1 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -376,7 +376,6 @@
   triggers: "mac-rel"
   triggers: "WebRTC Chromium Android Builder"
   triggers: "WebRTC Chromium Linux Builder"
-  triggers: "WebRTC Chromium Linux Builder (RBE)"
   triggers: "WebRTC Chromium Mac Builder"
   triggers: "WebRTC Chromium Win Builder"
   triggers: "win-annotator-rel"
@@ -407,9 +406,7 @@
   triggers: "WebRTC Chromium FYI ios-simulator"
 
   triggers: "WebRTC Chromium FYI Linux Builder"
-  triggers: "WebRTC Chromium FYI Linux Builder (RBE)"
   triggers: "WebRTC Chromium FYI Linux Builder (dbg)"
-  triggers: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
 
   triggers: "WebRTC Chromium FYI Mac Builder"
   triggers: "WebRTC Chromium FYI Mac Builder (dbg)"
@@ -1983,17 +1980,6 @@
 }
 
 job {
-  id: "WebRTC Chromium Linux Builder (RBE)"
-  acl_sets: "default"
-  acl_sets: "webrtc"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.webrtc"
-    builder: "WebRTC Chromium Linux Builder (RBE)"
-  }
-}
-
-job {
   id: "WebRTC Chromium Linux Tester"
   acl_sets: "triggered-by-parent-builders"
   acl_sets: "webrtc"
@@ -5595,17 +5581,6 @@
 }
 
 job {
-  id: "WebRTC Chromium FYI Linux Builder (RBE)"
-  acl_sets: "default"
-  acl_sets: "webrtc"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.webrtc.fyi"
-    builder: "WebRTC Chromium FYI Linux Builder (RBE)"
-  }
-}
-
-job {
   id: "WebRTC Chromium FYI Linux Tester"
   acl_sets: "triggered-by-parent-builders"
   acl_sets: "webrtc"
@@ -5628,17 +5603,6 @@
 }
 
 job {
-  id: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
-  acl_sets: "default"
-  acl_sets: "webrtc"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.webrtc.fyi"
-    builder: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
-  }
-}
-
-job {
   id: "WebRTC Chromium FYI Mac Builder"
   acl_sets: "default"
   acl_sets: "webrtc"
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn
index 70223b1..c50555d 100644
--- a/ios/chrome/browser/metrics/BUILD.gn
+++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -62,6 +62,7 @@
     "//components/rappor",
     "//components/signin/core/browser",
     "//components/sync",
+    "//components/sync:device_info",
     "//components/ukm",
     "//components/ukm:observers",
     "//components/variations",
diff --git a/ios/chrome/browser/metrics/ukm_egtest.mm b/ios/chrome/browser/metrics/ukm_egtest.mm
index 3a8229f..5a5e5ae 100644
--- a/ios/chrome/browser/metrics/ukm_egtest.mm
+++ b/ios/chrome/browser/metrics/ukm_egtest.mm
@@ -40,7 +40,7 @@
 using chrome_test_util::AccountsSyncButton;
 using chrome_test_util::ButtonWithAccessibilityLabel;
 using chrome_test_util::ButtonWithAccessibilityLabelId;
-using chrome_test_util::ClearBrowsingDataCollectionView;
+using chrome_test_util::ClearBrowsingDataView;
 using chrome_test_util::GetIncognitoTabCount;
 using chrome_test_util::IsIncognitoMode;
 using chrome_test_util::IsSyncInitialized;
@@ -136,7 +136,7 @@
 
   // Before returning, make sure that the top of the Clear Browsing Data
   // settings screen is visible to match the state at the start of the method.
-  [[EarlGrey selectElementWithMatcher:ClearBrowsingDataCollectionView()]
+  [[EarlGrey selectElementWithMatcher:ClearBrowsingDataView()]
       performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)];
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
diff --git a/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm b/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm
index 2177e8f..9875f9a 100644
--- a/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm
+++ b/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm
@@ -21,7 +21,7 @@
 #endif
 
 using chrome_test_util::ClearBrowsingDataCell;
-using chrome_test_util::ClearBrowsingDataCollectionView;
+using chrome_test_util::ClearBrowsingDataView;
 using chrome_test_util::ClearBrowsingDataButton;
 using chrome_test_util::ConfirmClearBrowsingDataButton;
 using chrome_test_util::SettingsDoneButton;
@@ -134,7 +134,7 @@
 
   // Before returning, make sure that the top of the Clear Browsing Data
   // settings screen is visible to match the state at the start of the method.
-  [[EarlGrey selectElementWithMatcher:ClearBrowsingDataCollectionView()]
+  [[EarlGrey selectElementWithMatcher:ClearBrowsingDataView()]
       performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)];
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_driver.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_driver.mm
index 3c4c7c8..eca00ff 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_driver.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_driver.mm
@@ -7,6 +7,7 @@
 #include "base/strings/string16.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/password_manager/core/browser/password_generation_frame_helper.h"
 #include "components/password_manager/core/browser/password_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -36,7 +37,10 @@
 
 void IOSChromePasswordManagerDriver::FormEligibleForGenerationFound(
     const autofill::NewPasswordFormGenerationData& form) {
-  [delegate_ formEligibleForGenerationFound:form];
+  if (GetPasswordGenerationHelper()->IsGenerationEnabled(
+          /*log_debug_data*/ true)) {
+    [delegate_ formEligibleForGenerationFound:form];
+  }
 }
 
 void IOSChromePasswordManagerDriver::GeneratedPasswordAccepted(
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm
index 368072f..66f197a 100644
--- a/ios/chrome/browser/passwords/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -15,6 +15,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/values.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
@@ -32,6 +33,7 @@
 #import "ios/chrome/browser/autofill/form_suggestion_controller.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/passwords/password_form_filler.h"
+#include "ios/chrome/browser/passwords/password_manager_features.h"
 #import "ios/chrome/browser/ui/autofill/form_input_accessory_mediator.h"
 #include "ios/chrome/browser/web/chrome_web_client.h"
 #import "ios/chrome/browser/web/chrome_web_test.h"
@@ -61,6 +63,7 @@
 using test_helpers::SetPasswordFormFillData;
 using testing::NiceMock;
 using testing::Return;
+using base::ASCIIToUTF16;
 using base::test::ios::kWaitForActionTimeout;
 using base::test::ios::kWaitForJSCompletionTimeout;
 using base::test::ios::WaitUntilConditionOrTimeout;
@@ -85,6 +88,8 @@
   ~MockPasswordManagerClient() override = default;
 
   MOCK_CONST_METHOD0(GetLogManager, password_manager::LogManager*(void));
+  MOCK_CONST_METHOD0(GetPasswordSyncState, password_manager::SyncState());
+  MOCK_CONST_METHOD0(IsIncognito, bool());
 
   PrefService* GetPrefs() const override { return prefs_.get(); }
 
@@ -129,8 +134,8 @@
   form.scheme = PasswordForm::SCHEME_HTML;
   form.origin = GURL(origin_url);
   form.signon_realm = origin_url;
-  form.username_value = base::ASCIIToUTF16(username_value);
-  form.password_value = base::ASCIIToUTF16(password_value);
+  form.username_value = ASCIIToUTF16(username_value);
+  form.password_value = ASCIIToUTF16(password_value);
   return form;
 }
 
@@ -409,9 +414,9 @@
         }));
     if (data.expected_form_found) {
       ASSERT_EQ(1U, forms.size());
-      EXPECT_EQ(base::ASCIIToUTF16(data.expected_username_element),
+      EXPECT_EQ(ASCIIToUTF16(data.expected_username_element),
                 forms[0].username_element);
-      EXPECT_EQ(base::ASCIIToUTF16(data.expected_password_element),
+      EXPECT_EQ(ASCIIToUTF16(data.expected_password_element),
                 forms[0].password_element);
     } else {
       ASSERT_TRUE(forms.empty());
@@ -495,7 +500,7 @@
       block_was_called = YES;
       ASSERT_EQ(data.expected_form_found, found);
       if (data.expected_form_found) {
-        EXPECT_EQ(base::ASCIIToUTF16(data.expected_username_element),
+        EXPECT_EQ(ASCIIToUTF16(data.expected_username_element),
                   form.username_element);
       }
     };
@@ -877,6 +882,14 @@
      "<input id='pw' type='password' name=\"p'\">"
      "</form>";
 
+static NSString* kHtmlWithNewPasswordForm =
+    @"<form>"
+     "<input id='un' type='text' name=\"u'\" autocomplete=\"username\""
+     "  onkeyup='window.onKeyUpCalled_=true'"
+     "  onchange='window.onChangeCalled_=true'>"
+     "<input id='pw' type='password' name=\"p'\" autocomplete=\"new-password\">"
+     "</form>";
+
 // An HTML page containing two password forms.
 static NSString* kHtmlWithTwoPasswordForms =
     @"<form id='f1'>"
@@ -955,7 +968,7 @@
   PasswordFormFillData form_data;
   SetPasswordFormFillData(base_url, base_url, "un", "user0", "pw", "password0",
                           "abc", "def", true, &form_data);
-  form_data.name = base::ASCIIToUTF16(FormName(0));
+  form_data.name = ASCIIToUTF16(FormName(0));
 
   __block BOOL block_was_called = NO;
   [passwordController_ fillPasswordForm:form_data
@@ -1053,7 +1066,7 @@
     SetPasswordFormFillData(base_url, base_url, test_data.username_element,
                             "user0", test_data.password_element, "password0",
                             "abc", "def", true, &form_data);
-    form_data.name = base::ASCIIToUTF16(test_data.form_name);
+    form_data.name = ASCIIToUTF16(test_data.form_name);
 
     __block BOOL block_was_called = NO;
     [passwordController_ fillPasswordForm:form_data
@@ -1428,3 +1441,124 @@
 
   EXPECT_FALSE(completion_handler_success);
 }
+
+// Tests password generation suggestion is shown properly.
+TEST_F(PasswordControllerTest, CheckPasswordGenerationSuggestion) {
+  TearDown();
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(features::kPasswordGeneration);
+  SetUp();
+  EXPECT_CALL(*store_, GetLogins(_, _))
+      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+  EXPECT_CALL(*weak_client_, GetPasswordSyncState())
+      .WillRepeatedly(
+          Return(password_manager::SyncState::SYNCING_NORMAL_ENCRYPTION));
+
+  LoadHtml(kHtmlWithNewPasswordForm);
+  const std::string base_url = BaseUrl();
+  ExecuteJavaScript(
+      [NSString stringWithFormat:kUsernameAndPasswordTestPreparationScript,
+                                 @"un", @"pw"]);
+
+  // Initialize |form_data| with test data and an indicator that autofill
+  // should not be performed while the user is entering the username so that
+  // we can test with an initially-empty username field. Testing with a
+  // username field that contains input is performed by a specific test below.
+  PasswordFormFillData form_data;
+  SetPasswordFormFillData(base_url, base_url, "un", "user0", "pw", "password0",
+                          "abc", "def", true, &form_data);
+  form_data.name = ASCIIToUTF16(FormName(0));
+
+  __block BOOL block_was_called = NO;
+  [passwordController_ fillPasswordForm:form_data
+                      completionHandler:^(BOOL success) {
+                        block_was_called = YES;
+                        // Verify that the fill reports failed.
+                        EXPECT_FALSE(success);
+                      }];
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool() {
+    return block_was_called;
+  }));
+
+  // Verify that the form has not been autofilled.
+  EXPECT_NSEQ(@"[]=, onkeyup=false, onchange=false",
+              ExecuteJavaScript(kUsernamePasswordVerificationScript));
+
+  NSString* showAll = @"Show All\u2026";
+  // clang-format off
+  SuggestionTestData test_data[] = {
+    {
+      "Should not show suggest password when focusing username field",
+      @[(@"var evt = document.createEvent('Events');"
+         "username_.focus();"),
+        @""],
+      @[@"user0 ••••••••", @"abc ••••••••", showAll],
+      @"[]=, onkeyup=false, onchange=false"
+    },
+    {
+      "Should show suggest password when focusing password field",
+      @[(@"var evt = document.createEvent('Events');"
+         "password_.focus();"),
+        @""],
+      @[@"user0 ••••••••", @"abc ••••••••", @"Suggest  Password\u2026", showAll],
+      @"[]=, onkeyup=false, onchange=false"
+    },
+  };
+  // clang-format on
+
+  for (const SuggestionTestData& data : test_data) {
+    SCOPED_TRACE(testing::Message()
+                 << "for description=" << data.description
+                 << " and eval_scripts=" << data.eval_scripts);
+    // Prepare the test.
+    ExecuteJavaScript(
+        [NSString stringWithFormat:kUsernameAndPasswordTestPreparationScript,
+                                   @"un", @"pw"]);
+
+    for (NSString* script in data.eval_scripts) {
+      // Trigger events.
+      ExecuteJavaScript(script);
+
+      // Pump the run loop so that the host can respond.
+      WaitForBackgroundTasks();
+    }
+    // Wait until suggestions are received.
+    EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+      return [GetSuggestionValues() count] > 0;
+    }));
+
+    EXPECT_NSEQ(data.expected_suggestions, GetSuggestionValues());
+    EXPECT_NSEQ(data.expected_result,
+                ExecuteJavaScript(kUsernamePasswordVerificationScript));
+    // Clear all suggestions.
+    [suggestionController_ setSuggestions:nil];
+  }
+}
+
+
+// Check that if the PasswordController is told (by the PasswordManagerClient)
+// that this is Incognito, it won't enable password generation.
+TEST_F(PasswordControllerTest, IncognitoPasswordGenerationDisabled) {
+    TearDown();
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndEnableFeature(features::kPasswordGeneration);
+    ChromeWebTest::SetUp();
+    
+    password_manager::NewPasswordFormManager::
+    set_wait_for_server_predictions_for_filling(false);
+    
+    auto client =
+    std::make_unique<NiceMock<MockPasswordManagerClient>>(store_.get());
+    weak_client_ = client.get();
+    
+    EXPECT_CALL(*weak_client_, GetPasswordSyncState())
+    .WillRepeatedly(
+                    Return(password_manager::SyncState::SYNCING_NORMAL_ENCRYPTION));
+    EXPECT_CALL(*weak_client_, IsIncognito()).WillRepeatedly(Return(true));
+    
+    passwordController_ =
+    [[PasswordController alloc] initWithWebState:web_state()
+                                          client:std::move(client)];
+    
+    EXPECT_FALSE([passwordController_ passwordGenerationHelper]);
+}
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn
index 806e43b..03d3fd0 100644
--- a/ios/chrome/browser/sync/BUILD.gn
+++ b/ios/chrome/browser/sync/BUILD.gn
@@ -54,6 +54,7 @@
     "//components/sessions",
     "//components/signin/core/browser",
     "//components/sync",
+    "//components/sync:device_info",
     "//components/sync:user_events",
     "//components/sync_preferences",
     "//components/sync_sessions",
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index 81f0e75f..9da551c7 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -45,6 +45,7 @@
 #include "ios/chrome/browser/sync/session_sync_service_factory.h"
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
+#include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/web_task_traits.h"
 #include "ios/web/public/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -170,6 +171,7 @@
   init_params.url_loader_factory = browser_state->GetSharedURLLoaderFactory();
   init_params.network_connection_tracker =
       GetApplicationContext()->GetNetworkConnectionTracker();
+  init_params.channel = ::GetChannel();
   init_params.debug_identifier = browser_state->GetDebugName();
   init_params.autofill_enable_account_wallet_storage =
       base::FeatureList::IsEnabled(
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
index b5bd7aa..3a37d25 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -29,7 +29,7 @@
 #error "This file requires ARC support."
 #endif
 
-@interface OmniboxCoordinator ()
+@interface OmniboxCoordinator () <OmniboxViewControllerDelegate>
 // Object taking care of adding the accessory views to the keyboard.
 @property(nonatomic, strong)
     ToolbarAssistiveKeyboardDelegateImpl* keyboardDelegate;
@@ -68,6 +68,7 @@
   self.viewController.dispatcher =
       static_cast<id<BrowserCommands, LoadQueryCommands, OmniboxFocuser>>(
           self.dispatcher);
+  self.viewController.delegate = self;
   self.mediator = [[OmniboxMediator alloc] init];
   self.mediator.templateURLService =
       ios::TemplateURLServiceFactory::GetForBrowserState(self.browserState);
@@ -97,6 +98,8 @@
   self.editController = nil;
   self.viewController = nil;
   self.mediator = nil;
+
+  [NSNotificationCenter.defaultCenter removeObserver:self];
 }
 
 - (void)updateOmniboxState {
@@ -164,6 +167,13 @@
   return self.viewController;
 }
 
+#pragma mark - OmniboxViewControllerDelegate
+
+- (void)omniboxViewControllerTextInputModeDidChange:
+    (OmniboxViewController*)omniboxViewController {
+  _editView->UpdatePopupAppearance();
+}
+
 #pragma mark - private
 
 // Convenience accessor.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
index eada570..010707d8 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
@@ -15,6 +15,16 @@
 @protocol BrowserCommands;
 @protocol LoadQueryCommands;
 @protocol OmniboxFocuser;
+@class OmniboxViewController;
+
+@protocol OmniboxViewControllerDelegate
+
+// Called after the text input mode changes in the OmniboxViewController. This
+// means that the active keyboard has changed.
+- (void)omniboxViewControllerTextInputModeDidChange:
+    (OmniboxViewController*)omniboxViewController;
+
+@end
 
 // The view controller managing the omnibox textfield and its container view.
 @interface OmniboxViewController : UIViewController<EditViewAnimatee,
@@ -34,16 +44,18 @@
 // The current semantic content attribute for the views this view controller
 // manages
 @property(nonatomic, assign)
-    UISemanticContentAttribute* semanticContentAttribute;
-
-// Designated initializer.
-- (instancetype)initWithIncognito:(BOOL)isIncognito;
+    UISemanticContentAttribute semanticContentAttribute;
 
 // The dispatcher for the paste and go action.
 @property(nonatomic, weak)
     id<BrowserCommands, LoadQueryCommands, OmniboxFocuser>
         dispatcher;
 
+// The delegate for this object.
+@property(nonatomic, weak) id<OmniboxViewControllerDelegate> delegate;
+
+// Designated initializer.
+- (instancetype)initWithIncognito:(BOOL)isIncognito;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index 32776616..48335e8a 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -106,18 +106,18 @@
   self.textField.placeholder = l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT);
   [self setupClearButton];
 
+  [NSNotificationCenter.defaultCenter
+      addObserver:self
+         selector:@selector(textInputModeDidChange)
+             name:UITextInputCurrentInputModeDidChangeNotification
+           object:nil];
+
   // TODO(crbug.com/866446): Use UITextFieldDelegate instead.
   [[NSNotificationCenter defaultCenter]
       addObserver:self
          selector:@selector(textFieldDidBeginEditing)
              name:UITextFieldTextDidBeginEditingNotification
            object:self.textField];
-
-  [NSNotificationCenter.defaultCenter
-      addObserver:self
-         selector:@selector(textInputModeDidChange)
-             name:UITextInputCurrentInputModeDidChangeNotification
-           object:nil];
 }
 
 - (void)viewDidAppear:(BOOL)animated {
@@ -138,15 +138,6 @@
   [self updateLeadingImageVisibility];
 }
 
-- (void)textInputModeDidChange {
-  if (!self.textField.isFirstResponder) {
-    return;
-  }
-
-  [self.textField updateTextDirection];
-  [self updateSemanticContentAttribute];
-}
-
 #pragma mark - public methods
 
 - (OmniboxTextFieldIOS*)textField {
@@ -205,7 +196,20 @@
                                  ? self.defaultLeadingImage
                                  : self.emptyTextLeadingImage];
 
-  [self updateSemanticContentAttribute];
+  self.semanticContentAttribute = [self.textField bestSemanticContentAttribute];
+}
+
+// Called on UITextInputCurrentInputModeDidChangeNotification for self.textField
+- (void)textInputModeDidChange {
+  // Only respond to language changes when the omnibox is first responder.
+  if (![self.textField isFirstResponder]) {
+    return;
+  }
+
+  [self.textField updateTextDirection];
+  self.semanticContentAttribute = [self.textField bestSemanticContentAttribute];
+
+  [self.delegate omniboxViewControllerTextInputModeDidChange:self];
 }
 
 #pragma mark clear button
@@ -267,7 +271,7 @@
   }
 
   [self updateClearButtonVisibility];
-  [self updateSemanticContentAttribute];
+  self.semanticContentAttribute = [self.textField bestSemanticContentAttribute];
 }
 
 // Hides the clear button if the textfield is empty; shows it otherwise.
@@ -277,15 +281,18 @@
                                            : UITextFieldViewModeNever];
 }
 
-// Updates the semantic content attribute based on the textField's current text.
-- (void)updateSemanticContentAttribute {
+// Handle the updates to semanticContentAttribute by passing the changes along
+// to the necessary views.
+- (void)setSemanticContentAttribute:
+    (UISemanticContentAttribute)semanticContentAttribute {
+  _semanticContentAttribute = semanticContentAttribute;
+
   if (!base::FeatureList::IsEnabled(kNewOmniboxPopupLayout)) {
     return;
   }
-  UISemanticContentAttribute bestAttribute =
-      [self.textField bestSemanticContentAttribute];
-  self.view.semanticContentAttribute = bestAttribute;
-  self.textField.semanticContentAttribute = bestAttribute;
+
+  self.view.semanticContentAttribute = self.semanticContentAttribute;
+  self.textField.semanticContentAttribute = self.semanticContentAttribute;
 }
 
 #pragma mark - UIMenuItem
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
index fe8d9a5..e689dfe 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
@@ -121,6 +121,9 @@
   // Updates this edit view to show the proper text, highlight and images.
   void UpdateAppearance();
 
+  // Updates the appearance of popup to have proper text alignment.
+  void UpdatePopupAppearance();
+
   // Clears the text from the omnibox.
   void ClearText();
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index c43c6a3d..c574a7d0 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -270,6 +270,11 @@
   if (model())
     model()->StartAutocomplete(current_selection_.length != 0,
                                prevent_inline_autocomplete);
+
+  UpdatePopupAppearance();
+}
+
+void OmniboxViewIOS::UpdatePopupAppearance() {
   DCHECK(popup_provider_);
   popup_provider_->SetTextAlignment([field_ bestTextAlignment]);
   popup_provider_->SetSemanticContentAttribute(
@@ -374,6 +379,10 @@
   [field_ setText:[field_ text]];
   OnBeforePossibleChange();
 
+  // Make sure the omnibox popup's semantic content attribute is set correctly.
+  popup_provider_->SetSemanticContentAttribute(
+      [field_ bestSemanticContentAttribute]);
+
   if (model()) {
     // In the case where the user taps the fakebox on the Google landing page,
     // or from the secondary toolbar search button, the focus source is already
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
index 9e9fbfa..319a177 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -28,6 +28,23 @@
          forCellReuseIdentifier:OmniboxPopupRowCellReuseIdentifier];
 }
 
+- (void)setSemanticContentAttribute:
+    (UISemanticContentAttribute)semanticContentAttribute {
+  [super setSemanticContentAttribute:semanticContentAttribute];
+
+  // If there are any visible cells, update them right away.
+  for (UITableViewCell* cell in self.tableView.visibleCells) {
+    if ([cell isKindOfClass:[OmniboxPopupRowCell class]]) {
+      OmniboxPopupRowCell* rowCell =
+          base::mac::ObjCCastStrict<OmniboxPopupRowCell>(cell);
+      // This has to be set here because the cell's content view has its
+      // semantic content attribute reset before the cell is displayed (and
+      // before this method is called).
+      rowCell.omniboxSemanticContentAttribute = self.semanticContentAttribute;
+    }
+  }
+}
+
 #pragma mark - UIScrollViewDelegate
 
 - (void)scrollViewDidScroll:(UIScrollView*)scrollView {
diff --git a/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h b/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h
index 7940960..01678ba4 100644
--- a/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h
+++ b/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h
@@ -7,10 +7,10 @@
 
 #import <Foundation/Foundation.h>
 
-// The accessibility identifier of the privacy settings collection view.
-extern NSString* const kClearBrowsingDataCollectionViewAccessibilityIdentifier;
+// The accessibility identifier of the clear browsing data view.
+extern NSString* const kClearBrowsingDataViewAccessibilityIdentifier;
 
-// The accessibility identifiers of the cells in the collection view.
+// The accessibility identifiers of the cells in the clear browsing data view.
 extern NSString* const kClearBrowsingHistoryCellAccessibilityIdentifier;
 extern NSString* const kClearCookiesCellAccessibilityIdentifier;
 extern NSString* const kClearCacheCellAccessibilityIdentifier;
diff --git a/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.mm b/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.mm
index 4f1ad2c..efd46db 100644
--- a/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.mm
+++ b/ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.mm
@@ -8,10 +8,9 @@
 #error "This file requires ARC support."
 #endif
 
-// The accessibility identifier of the privacy settings collection view.
-NSString* const kClearBrowsingDataCollectionViewAccessibilityIdentifier =
-    @"kClearBrowsingDataCollectionViewAccessibilityIdentifier";
-// The accessibility identifiers of the cells in the collection view.
+NSString* const kClearBrowsingDataViewAccessibilityIdentifier =
+    @"kClearBrowsingDataViewAccessibilityIdentifier";
+
 NSString* const kClearBrowsingHistoryCellAccessibilityIdentifier =
     @"kClearBrowsingHistoryCellAccessibilityIdentifier";
 NSString* const kClearCookiesCellAccessibilityIdentifier =
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm
index a1aa63e..ba45c3c0 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm
@@ -89,7 +89,7 @@
 
     self.title = l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE);
     self.collectionViewAccessibilityIdentifier =
-        kClearBrowsingDataCollectionViewAccessibilityIdentifier;
+        kClearBrowsingDataViewAccessibilityIdentifier;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
index 1c721cb9..3b7905d 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
@@ -16,9 +16,11 @@
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/elements/chrome_activity_overlay_coordinator.h"
+#include "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h"
 #import "ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h"
 #include "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_local_commands.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.h"
+#import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_constants.h"
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h"
@@ -107,6 +109,8 @@
                 style:UIBarButtonItemStylePlain
                target:self
                action:@selector(showClearBrowsingDataAlertController:)];
+    _clearBrowsingDataBarButton.accessibilityIdentifier =
+        kClearBrowsingDataButtonIdentifier;
     _clearBrowsingDataBarButton.tintColor = [UIColor redColor];
   }
   return _clearBrowsingDataBarButton;
@@ -126,6 +130,8 @@
 - (void)viewDidLoad {
   [super viewDidLoad];
   self.styler.tableViewBackgroundColor = UIColor.whiteColor;
+  self.tableView.accessibilityIdentifier =
+      kClearBrowsingDataViewAccessibilityIdentifier;
   self.tableView.backgroundColor = self.styler.tableViewBackgroundColor;
   // TableView configuration
   self.tableView.estimatedRowHeight = 56;
diff --git a/ios/chrome/browser/ui/settings/settings_egtest.mm b/ios/chrome/browser/ui/settings/settings_egtest.mm
index 7ed6a20..dcd18be0 100644
--- a/ios/chrome/browser/ui/settings/settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/settings_egtest.mm
@@ -50,7 +50,8 @@
 #endif
 
 using chrome_test_util::ButtonWithAccessibilityLabelId;
-using chrome_test_util::ClearBrowsingDataCollectionView;
+using chrome_test_util::ClearBrowsingDataButton;
+using chrome_test_util::ClearBrowsingDataView;
 using chrome_test_util::ClearBrowsingHistoryButton;
 using chrome_test_util::ClearCacheButton;
 using chrome_test_util::ClearCookiesButton;
@@ -77,10 +78,6 @@
   kBreakpadFirstLaunch,
 };
 
-// Matcher for the clear browsing data button on the clear browsing data panel.
-id<GREYMatcher> ClearBrowsingDataButton() {
-  return ButtonWithAccessibilityLabelId(IDS_IOS_CLEAR_BUTTON);
-}
 // Matcher for the Send Usage Data cell on the Privacy screen.
 id<GREYMatcher> SendUsageDataButton() {
   return ButtonWithAccessibilityLabelId(IDS_IOS_OPTIONS_SEND_USAGE_DATA);
@@ -182,7 +179,7 @@
 
   // Before returning, make sure that the top of the Clear Browsing Data
   // settings screen is visible to match the state at the start of the method.
-  [[EarlGrey selectElementWithMatcher:ClearBrowsingDataCollectionView()]
+  [[EarlGrey selectElementWithMatcher:ClearBrowsingDataView()]
       performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)];
 }
 
@@ -587,7 +584,7 @@
 - (void)testAccessibilityOnPrivacyClearBrowsingHistoryPage {
   [ChromeEarlGreyUI openSettingsMenu];
   [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
-  [ChromeEarlGreyUI tapPrivacyMenuButton:ClearBrowsingDataButton()];
+  [ChromeEarlGreyUI tapPrivacyMenuButton:ClearBrowsingDataCell()];
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
   [self closeSubSettingsMenu];
 }
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn
index 66636205..0e70d94b 100644
--- a/ios/chrome/test/app/BUILD.gn
+++ b/ios/chrome/test/app/BUILD.gn
@@ -45,6 +45,7 @@
     "//components/metrics",
     "//components/prefs",
     "//components/signin/core/browser",
+    "//components/sync:device_info",
     "//components/sync:test_support_fake_server",
     "//google_apis",
     "//ios/chrome/app:app_internal",
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index a3718969..82ef421 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -39,6 +39,7 @@
     "//ios/chrome/browser/ntp_tiles:eg_tests",
     "//ios/chrome/browser/passwords:eg_tests",
     "//ios/chrome/browser/prerender:eg_tests",
+    "//ios/chrome/browser/ui/payments:eg_tests",
   ]
 }
 
@@ -105,7 +106,6 @@
     "//ios/chrome/browser/ui/omnibox/popup:eg_tests",
     "//ios/chrome/browser/ui/omnibox/popup/shortcuts:eg_tests",
     "//ios/chrome/browser/ui/page_info:eg_tests",
-    "//ios/chrome/browser/ui/payments:eg_tests",
     "//ios/chrome/browser/ui/popup_menu:eg_tests",
     "//ios/chrome/browser/ui/print:eg_tests",
     "//ios/chrome/browser/ui/qr_scanner:eg_tests",
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
index 7ebaa94..3c16bea8 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
@@ -29,7 +29,7 @@
 #error "This file requires ARC support."
 #endif
 
-using chrome_test_util::ClearBrowsingDataCollectionView;
+using chrome_test_util::ClearBrowsingDataView;
 using chrome_test_util::SettingsMenuButton;
 using chrome_test_util::ToolsMenuView;
 using base::test::ios::WaitUntilConditionOrTimeout;
@@ -90,8 +90,7 @@
       grey_allOf(buttonMatcher, grey_interactable(), nil);
   [[[EarlGrey selectElementWithMatcher:interactableButtonMatcher]
          usingSearchAction:ScrollDown()
-      onElementWithMatcher:ClearBrowsingDataCollectionView()]
-      performAction:grey_tap()];
+      onElementWithMatcher:ClearBrowsingDataView()] performAction:grey_tap()];
 }
 
 + (void)openAndClearBrowsingDataFromHistory {
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index ba879f7c..6651c54 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -144,8 +144,8 @@
 // panel.
 + (id<GREYMatcher>)clearBrowsingDataButton;
 
-// Returns matcher for the clear browsing data collection view.
-+ (id<GREYMatcher>)clearBrowsingDataCollectionView;
+// Returns matcher for the clear browsing data view.
++ (id<GREYMatcher>)clearBrowsingDataView;
 
 // Matcher for the clear browsing data action sheet item.
 + (id<GREYMatcher>)confirmClearBrowsingDataButton;
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index 3d3fd77..1be10ea 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -364,19 +364,19 @@
 }
 
 + (id<GREYMatcher>)clearBrowsingDataButton {
-  return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_IOS_CLEAR_BUTTON)];
+  return grey_accessibilityID(kClearBrowsingDataButtonIdentifier);
 }
 
-+ (id<GREYMatcher>)clearBrowsingDataCollectionView {
-  return grey_accessibilityID(
-      kClearBrowsingDataCollectionViewAccessibilityIdentifier);
++ (id<GREYMatcher>)clearBrowsingDataView {
+  return grey_accessibilityID(kClearBrowsingDataViewAccessibilityIdentifier);
 }
 
 + (id<GREYMatcher>)confirmClearBrowsingDataButton {
   return grey_allOf(
       grey_accessibilityLabel(l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)),
       grey_accessibilityTrait(UIAccessibilityTraitButton),
-      grey_not(grey_accessibilityID(kClearBrowsingDataButtonIdentifier)), nil);
+      grey_not(grey_accessibilityID(kClearBrowsingDataButtonIdentifier)),
+      grey_userInteractionEnabled(), nil);
 }
 
 + (id<GREYMatcher>)settingsMenuButton {
@@ -484,7 +484,9 @@
 }
 
 + (id<GREYMatcher>)clearBrowsingHistoryButton {
-  return grey_accessibilityID(kClearBrowsingHistoryCellAccessibilityIdentifier);
+  return grey_allOf(
+      grey_accessibilityID(kClearBrowsingHistoryCellAccessibilityIdentifier),
+      grey_sufficientlyVisible(), nil);
 }
 
 + (id<GREYMatcher>)clearCookiesButton {
@@ -492,7 +494,9 @@
 }
 
 + (id<GREYMatcher>)clearCacheButton {
-  return grey_accessibilityID(kClearCacheCellAccessibilityIdentifier);
+  return grey_allOf(
+      grey_accessibilityID(kClearCacheCellAccessibilityIdentifier),
+      grey_sufficientlyVisible(), nil);
 }
 
 + (id<GREYMatcher>)clearSavedPasswordsButton {
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h b/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h
index eeb40eb3..1cf9dde 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h
@@ -141,8 +141,8 @@
 // panel.
 id<GREYMatcher> ClearBrowsingDataButton();
 
-// Returns matcher for the clear browsing data collection view.
-id<GREYMatcher> ClearBrowsingDataCollectionView();
+// Returns matcher for the clear browsing data view.
+id<GREYMatcher> ClearBrowsingDataView();
 
 // Matcher for the clear browsing data action sheet item.
 id<GREYMatcher> ConfirmClearBrowsingDataButton();
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm b/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm
index 7f89aad03..07bcfbfa 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm
@@ -175,8 +175,8 @@
   return [ChromeMatchers clearBrowsingDataButton];
 }
 
-id<GREYMatcher> ClearBrowsingDataCollectionView() {
-  return [ChromeMatchers clearBrowsingDataCollectionView];
+id<GREYMatcher> ClearBrowsingDataView() {
+  return [ChromeMatchers clearBrowsingDataView];
 }
 
 id<GREYMatcher> ConfirmClearBrowsingDataButton() {
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index de14a3ee..12c3df65 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -292,6 +292,7 @@
   "//components/signin/ios/browser:active_state_manager",
   "//components/strings:components_strings_grit",
   "//components/sync",
+  "//components/sync:device_info",
   "//components/sync:user_events",
   "//components/language/ios/browser",
   "//components/sync_sessions",
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
index 95bbf3f2..74404d6 100644
--- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
@@ -14,7 +14,6 @@
 #include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/sync/base/model_type.h"
-#include "components/sync/device_info/local_device_info_provider_impl.h"
 #include "components/sync/driver/profile_sync_service.h"
 #include "components/sync/driver/startup_controller.h"
 #include "components/sync/driver/sync_service.h"
@@ -93,6 +92,7 @@
   init_params.network_time_update_callback = base::DoNothing();
   init_params.network_connection_tracker =
       ApplicationContext::GetInstance()->GetNetworkConnectionTracker();
+  init_params.channel = version_info::Channel::STABLE;
   init_params.invalidations_identity_providers.push_back(
       WebViewProfileInvalidationProviderFactory::GetForBrowserState(
           browser_state)
diff --git a/net/http/http_stream_factory_job.cc b/net/http/http_stream_factory_job.cc
index 8f1b27a..58c3c9b 100644
--- a/net/http/http_stream_factory_job.cc
+++ b/net/http/http_stream_factory_job.cc
@@ -435,21 +435,6 @@
   // |this| may be deleted after this call.
 }
 
-void HttpStreamFactory::Job::OnNewSpdySessionReadyCallback() {
-  DCHECK(stream_.get() || bidirectional_stream_impl_.get());
-  DCHECK_NE(job_type_, PRECONNECT);
-  DCHECK(using_spdy_);
-  // Note: an event loop iteration has passed, so |new_spdy_session_| may be
-  // NULL at this point if the SpdySession closed immediately after creation.
-  base::WeakPtr<SpdySession> spdy_session = new_spdy_session_;
-  new_spdy_session_.reset();
-
-  MaybeCopyConnectionAttemptsFromSocketOrHandle();
-
-  delegate_->OnNewSpdySessionReady(this, spdy_session);
-  // |this| may be deleted after this call.
-}
-
 void HttpStreamFactory::Job::OnStreamFailedCallback(int result) {
   DCHECK_NE(job_type_, PRECONNECT);
 
@@ -511,8 +496,6 @@
 }
 
 void HttpStreamFactory::Job::OnPreconnectsComplete() {
-  DCHECK(!new_spdy_session_);
-
   delegate_->OnPreconnectsComplete(this);
   // |this| may be deleted after this call.
 }
@@ -550,15 +533,6 @@
   // while doing anything other than waiting to establish a connection.
   spdy_session_request_.reset();
 
-  if (!using_quic_) {
-    // Resume all throttled Jobs with the same SpdySessionKey if there are any,
-    // now that this job is done.
-    //
-    // TODO(mmenke): The |spdy_session_request_| call above already does this,
-    // except for preconnects. Make it resume preconnects, too.
-    session_->spdy_session_pool()->ResumePendingRequests(spdy_session_key_);
-  }
-
   if (job_type_ == PRECONNECT) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
@@ -617,11 +591,7 @@
 
     case OK:
       next_state_ = STATE_DONE;
-      if (new_spdy_session_.get()) {
-        base::ThreadTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE, base::BindOnce(&Job::OnNewSpdySessionReadyCallback,
-                                      ptr_factory_.GetWeakPtr()));
-      } else if (is_websocket_) {
+      if (is_websocket_) {
         DCHECK(websocket_stream_);
         base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE,
@@ -672,10 +642,6 @@
       case STATE_WAIT_COMPLETE:
         rv = DoWaitComplete(rv);
         break;
-      case STATE_EVALUATE_THROTTLE:
-        DCHECK_EQ(OK, rv);
-        rv = DoEvaluateThrottle();
-        break;
       case STATE_INIT_CONNECTION:
         DCHECK_EQ(OK, rv);
         rv = DoInitConnection();
@@ -751,50 +717,8 @@
 int HttpStreamFactory::Job::DoWaitComplete(int result) {
   net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_WAITING);
   DCHECK_EQ(OK, result);
-  next_state_ = STATE_EVALUATE_THROTTLE;
-  return OK;
-}
-
-int HttpStreamFactory::Job::DoEvaluateThrottle() {
   next_state_ = STATE_INIT_CONNECTION;
-  if (!using_ssl_)
-    return OK;
-  if (using_quic_)
-    return OK;
-
-  DCHECK(!spdy_session_request_);
-  if (job_type_ != PRECONNECT) {
-    // Start watching for an available H2 connection. Note that this does not
-    // mean that HTTP/2 is necessarily supported for this SpdySessionKey, since
-    // we may need to wait for ALPN to complete before knowing if HTTP/2 is
-    // available.
-    spdy_session_request_ =
-        session_->spdy_session_pool()->CreateRequestForSpdySession(
-            spdy_session_key_, this);
-  }
-
-  // Throttle connect to an HTTP/2 supported server, if there are pending
-  // requests with the same SpdySessionKey.
-  if (session_->http_server_properties()->RequiresHTTP11(
-          spdy_session_key_.host_port_pair())) {
-    return OK;
-  }
-  url::SchemeHostPort scheme_host_port(
-      using_ssl_ ? url::kHttpsScheme : url::kHttpScheme,
-      spdy_session_key_.host_port_pair().host(),
-      spdy_session_key_.host_port_pair().port());
-  if (!session_->http_server_properties()->GetSupportsSpdy(scheme_host_port))
-    return OK;
-  base::Closure callback = base::Bind(
-      &HttpStreamFactory::Job::ResumeInitConnection, ptr_factory_.GetWeakPtr());
-  if (session_->spdy_session_pool()->StartRequest(spdy_session_key_,
-                                                  callback)) {
-    return OK;
-  }
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, callback, base::TimeDelta::FromMilliseconds(kHTTP2ThrottleMs));
-  net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_THROTTLED);
-  return ERR_IO_PENDING;
+  return OK;
 }
 
 void HttpStreamFactory::Job::ResumeInitConnection() {
@@ -901,10 +825,44 @@
           &existing_spdy_session_, &pushed_stream_id_);
     }
     if (!existing_spdy_session_) {
-      existing_spdy_session_ =
-          session_->spdy_session_pool()->FindAvailableSession(
-              spdy_session_key_, enable_ip_based_pooling_,
-              try_websocket_over_http2_, net_log_);
+      if (!spdy_session_request_) {
+        // If not currently watching for an H2 session, use
+        // SpdySessionPool::RequestSession() to check for a session, and start
+        // watching for one.
+        bool should_throttle_connect = ShouldThrottleConnectForSpdy();
+        base::RepeatingClosure resume_callback =
+            should_throttle_connect
+                ? base::BindRepeating(
+                      &HttpStreamFactory::Job::ResumeInitConnection,
+                      ptr_factory_.GetWeakPtr())
+                : base::RepeatingClosure();
+
+        bool is_first_request_for_session;
+        existing_spdy_session_ = session_->spdy_session_pool()->RequestSession(
+            spdy_session_key_, enable_ip_based_pooling_,
+            try_websocket_over_http2_, net_log_, resume_callback, this,
+            &spdy_session_request_, &is_first_request_for_session);
+        if (!existing_spdy_session_ && should_throttle_connect &&
+            !is_first_request_for_session) {
+          net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_THROTTLED);
+          next_state_ = STATE_INIT_CONNECTION;
+          base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+              FROM_HERE, resume_callback,
+              base::TimeDelta::FromMilliseconds(kHTTP2ThrottleMs));
+          return ERR_IO_PENDING;
+        }
+      } else if (enable_ip_based_pooling_) {
+        // If already watching for an H2 session, still need to check for an
+        // existing connection that can be reused through IP pooling, as those
+        // don't post session available notifications.
+        //
+        // TODO(mmenke):  Make sessions created through IP pooling invoke the
+        // callback.
+        existing_spdy_session_ =
+            session_->spdy_session_pool()->FindAvailableSession(
+                spdy_session_key_, enable_ip_based_pooling_,
+                try_websocket_over_http2_, net_log_);
+      }
     }
     if (existing_spdy_session_) {
       // Stop watching for SpdySessions.
@@ -1245,7 +1203,6 @@
     return ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY;
   }
 
-  new_spdy_session_ = spdy_session;
   url::SchemeHostPort scheme_host_port(
       using_ssl_ ? url::kHttpsScheme : url::kHttpScheme,
       spdy_session_key_.host_port_pair().host(),
@@ -1257,11 +1214,8 @@
     http_server_properties->SetSupportsSpdy(scheme_host_port, true);
 
   // Create a SpdyHttpStream or a BidirectionalStreamImpl attached to the
-  // session; OnNewSpdySessionReadyCallback is not called until an event loop
-  // iteration later, so if the SpdySession is closed between then, allow
-  // reuse state from the underlying socket, sampled by SpdyHttpStream,
-  // bubble up to the request.
-  return SetSpdyHttpStreamOrBidirectionalStreamImpl(new_spdy_session_);
+  // session.
+  return SetSpdyHttpStreamOrBidirectionalStreamImpl(spdy_session);
 }
 
 int HttpStreamFactory::Job::DoCreateStreamComplete(int result) {
@@ -1297,6 +1251,12 @@
   // SpdySessionPool.
   init_connection_already_resumed_ = true;
 
+  // If this is a preconnect, nothing left do to.
+  if (job_type_ == PRECONNECT) {
+    OnPreconnectsComplete();
+    return;
+  }
+
   using_spdy_ = true;
   existing_spdy_session_ = spdy_session;
   next_state_ = STATE_CREATE_STREAM;
@@ -1477,4 +1437,20 @@
       is_websocket, enable_ip_based_pooling, net_log);
 }
 
+bool HttpStreamFactory::Job::ShouldThrottleConnectForSpdy() const {
+  DCHECK(!using_quic_);
+  DCHECK(!spdy_session_request_);
+
+  // If the job has previously been throttled, don't throttle it again.
+  if (init_connection_already_resumed_)
+    return false;
+
+  url::SchemeHostPort scheme_host_port(
+      using_ssl_ ? url::kHttpsScheme : url::kHttpScheme,
+      spdy_session_key_.host_port_pair().host(),
+      spdy_session_key_.host_port_pair().port());
+  // Only throttle the request if the server is believed to support H2.
+  return session_->http_server_properties()->GetSupportsSpdy(scheme_host_port);
+}
+
 }  // namespace net
diff --git a/net/http/http_stream_factory_job.h b/net/http/http_stream_factory_job.h
index 6ba6aaa46..0ef29a71 100644
--- a/net/http/http_stream_factory_job.h
+++ b/net/http/http_stream_factory_job.h
@@ -119,12 +119,6 @@
     // contained in |proxy_info| can be skipped.
     virtual bool OnInitConnection(const ProxyInfo& proxy_info) = 0;
 
-    // Invoked to notify the HttpStreamRequest and HttpStreamFactory of the
-    // readiness of new SPDY session.
-    virtual void OnNewSpdySessionReady(
-        Job* job,
-        const base::WeakPtr<SpdySession>& spdy_session) = 0;
-
     // Invoked when the |job| finishes pre-connecting sockets.
     virtual void OnPreconnectsComplete(Job* job) = 0;
 
@@ -268,7 +262,6 @@
     STATE_WAIT,
     STATE_WAIT_COMPLETE,
 
-    STATE_EVALUATE_THROTTLE,
     STATE_INIT_CONNECTION,
     STATE_INIT_CONNECTION_COMPLETE,
     STATE_WAITING_USER_ACTION,
@@ -321,7 +314,6 @@
   int DoStart();
   int DoWait();
   int DoWaitComplete(int result);
-  int DoEvaluateThrottle();
   int DoInitConnection();
   int DoInitConnectionComplete(int result);
   int DoWaitingUserAction(int result);
@@ -394,6 +386,10 @@
                               const AddressList& addresses,
                               const NetLogWithSource& net_log);
 
+  // Returns true if the request should be throttled to allow for only one
+  // connection attempt to be made to an H2 server at a time.
+  bool ShouldThrottleConnectForSpdy() const;
+
   const HttpRequestInfo request_info_;
   RequestPriority priority_;
   const ProxyInfo proxy_info_;
@@ -484,9 +480,6 @@
   // preconnect.
   int num_streams_;
 
-  // Initialized when we create a new SpdySession.
-  base::WeakPtr<SpdySession> new_spdy_session_;
-
   // Initialized when we have an existing SpdySession.
   base::WeakPtr<SpdySession> existing_spdy_session_;
 
diff --git a/net/http/http_stream_factory_job_controller.cc b/net/http/http_stream_factory_job_controller.cc
index f2c53694..e1ce6fdd 100644
--- a/net/http/http_stream_factory_job_controller.cc
+++ b/net/http/http_stream_factory_job_controller.cc
@@ -453,59 +453,6 @@
                                     request_info_.privacy_mode);
 }
 
-void HttpStreamFactory::JobController::OnNewSpdySessionReady(
-    Job* job,
-    const base::WeakPtr<SpdySession>& spdy_session) {
-  DCHECK(job);
-  DCHECK(job->using_spdy());
-  DCHECK(!is_preconnect_);
-
-  bool is_job_orphaned = IsJobOrphaned(job);
-
-  // Cache this so we can still use it if the JobController is deleted.
-  SpdySessionPool* spdy_session_pool = session_->spdy_session_pool();
-
-  // Notify |request_|.
-  if (!is_preconnect_ && !is_job_orphaned) {
-
-    DCHECK(request_);
-
-    // The first case is the usual case.
-    if (!job_bound_) {
-      BindJob(job);
-    }
-
-    MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
-                        job->using_spdy());
-
-    if (is_websocket_) {
-      // TODO(bnc): Re-instate this code when WebSockets over HTTP/2 is
-      // implemented.  https://crbug.com/801564.
-      NOTREACHED();
-    } else if (job->stream_type() == HttpStreamRequest::BIDIRECTIONAL_STREAM) {
-      std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl =
-          job->ReleaseBidirectionalStream();
-      DCHECK(bidirectional_stream_impl);
-      delegate_->OnBidirectionalStreamImplReady(
-          job->server_ssl_config(), job->proxy_info(),
-          std::move(bidirectional_stream_impl));
-    } else {
-      std::unique_ptr<HttpStream> stream = job->ReleaseStream();
-      DCHECK(stream);
-      delegate_->OnStreamReady(job->server_ssl_config(), job->proxy_info(),
-                               std::move(stream));
-    }
-  }
-
-  // Notify other requests that have the same SpdySessionKey.
-  // |request_| and |bound_job_| might be deleted already.
-  if (spdy_session && spdy_session->IsAvailable())
-    spdy_session_pool->OnNewSpdySessionReady(spdy_session);
-
-  if (is_job_orphaned)
-    OnOrphanedJobComplete(job);
-}
-
 void HttpStreamFactory::JobController::OnPreconnectsComplete(Job* job) {
   DCHECK_EQ(main_job_.get(), job);
   main_job_.reset();
diff --git a/net/http/http_stream_factory_job_controller.h b/net/http/http_stream_factory_job_controller.h
index 6a080f9..7a28d51e 100644
--- a/net/http/http_stream_factory_job_controller.h
+++ b/net/http/http_stream_factory_job_controller.h
@@ -132,12 +132,6 @@
 
   bool OnInitConnection(const ProxyInfo& proxy_info) override;
 
-  // Invoked to notify the Request and Factory of the readiness of new
-  // SPDY session.
-  void OnNewSpdySessionReady(
-      Job* job,
-      const base::WeakPtr<SpdySession>& spdy_session) override;
-
   // Invoked when the |job| finishes pre-connecting sockets.
   void OnPreconnectsComplete(Job* job) override;
 
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index 90113f24..922b291 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -20,6 +20,8 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/platform_thread.h"
 #include "net/base/completion_once_callback.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/proxy_server.h"
 #include "net/base/test_proxy_delegate.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_basic_stream.h"
@@ -41,6 +43,7 @@
 #include "net/quic/quic_stream_factory_peer.h"
 #include "net/quic/quic_test_packet_maker.h"
 #include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_session_key.h"
 #include "net/spdy/spdy_test_util_common.h"
 #include "net/test/test_with_scoped_task_environment.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -2329,6 +2332,70 @@
   EXPECT_TRUE(HttpStreamFactoryPeer::IsJobControllerDeleted(factory_));
 }
 
+// Check the case that while a preconnect is waiting in the H2 request queue,
+// and a SPDY session appears, the job completes successfully.
+TEST_F(HttpStreamFactoryJobControllerTest, SpdySessionInterruptsPreconnect) {
+  // Make sure there is only one socket connect.
+  MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+  MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)};
+  tcp_data_ = std::make_unique<SequencedSocketData>(reads, writes);
+  // connect needs to be async, so the H2 session isn't created immediately.
+  tcp_data_->set_connect_data(MockConnect(ASYNC, OK));
+  SSLSocketDataProvider ssl_data(ASYNC, OK);
+  ssl_data.next_proto = kProtoHTTP2;
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data);
+  HttpRequestInfo request_info;
+  request_info.method = "GET";
+  request_info.url = GURL("https://www.example.com");
+  Initialize(request_info);
+
+  // Sets server support HTTP/2.
+  url::SchemeHostPort server(request_info.url);
+  session_->http_server_properties()->SetSupportsSpdy(server, true);
+
+  // Start a non-preconnect request.
+  std::unique_ptr<HttpStreamRequest> stream_request = job_controller_->Start(
+      &request_delegate_, nullptr /* websocket_handshake_create_helper */,
+      NetLogWithSource(), HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY);
+  EXPECT_CALL(request_delegate_, OnStreamReadyImpl(_, _, _));
+
+  // Create and start a preconnect request, which should start watching the
+  // SpdySessionPool.
+  MockHttpStreamRequestDelegate preconnect_request_delegate;
+  HttpStreamFactory::JobController* job_controller =
+      new HttpStreamFactory::JobController(
+          factory_, &preconnect_request_delegate, session_.get(), &job_factory_,
+          request_info, true /* is_preconnect */, false /* is_websocket */,
+          enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(),
+          SSLConfig());
+  HttpStreamFactoryPeer::AddJobController(factory_, job_controller);
+  job_controller->Preconnect(1);
+  EXPECT_TRUE(job_controller->main_job());
+  EXPECT_FALSE(job_controller->alternative_job());
+
+  // The non-preconnect request should create an H2 session, which the
+  // preconnect then sees, and the preconnect request should complete and be
+  // torn down without ever requesting a socket. If it did request a socket, the
+  // test would fail since the mock socket factory would see an unexpected
+  // socket request.
+  base::RunLoop().RunUntilIdle();
+
+  stream_request.reset();
+
+  EXPECT_TRUE(HttpStreamFactoryPeer::IsJobControllerDeleted(factory_));
+
+  // Sanity check - make sure the SpdySession was created.
+  base::WeakPtr<SpdySession> spdy_session =
+      session_->spdy_session_pool()->FindAvailableSession(
+          SpdySessionKey(HostPortPair::FromURL(request_info.url),
+                         ProxyServer::Direct(), request_info.privacy_mode,
+                         SpdySessionKey::IsProxySession::kFalse,
+                         request_info.socket_tag),
+          false /* enable_ip_based_pooling */, false /* is_websocket */,
+          NetLogWithSource());
+  EXPECT_TRUE(spdy_session);
+}
+
 class JobControllerLimitMultipleH2Requests
     : public HttpStreamFactoryJobControllerTest {
  protected:
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index b4e5603..2570dfe 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -1607,9 +1607,11 @@
 // closes the socket while we have a pending transaction waiting for
 // a pending stream creation.  http://crbug.com/52901
 TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
-  // Construct the request.
+  // Construct the request. Each stream uses a different priority to provide
+  // more useful failure information if the requests are made in an unexpected
+  // order.
   spdy::SpdySerializedFrame req(
-      spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
   spdy::SpdySerializedFrame resp(
       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
   spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
@@ -1618,7 +1620,7 @@
   spdy_util_.UpdateWithStreamDestruction(1);
 
   spdy::SpdySerializedFrame req2(
-      spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
   spdy::SpdySerializedFrame resp2(
       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
 
@@ -1629,32 +1631,35 @@
       spdy_util_.ConstructSpdySettings(settings));
   spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
-  MockWrite writes[] = {
-      CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
-      CreateMockWrite(req2, 6),
-  };
+  MockWrite writes[] = {CreateMockWrite(req, 0),
+                        CreateMockWrite(settings_ack, 6),
+                        CreateMockWrite(req2, 7)};
   MockRead reads[] = {
-      CreateMockRead(settings_frame, 1),
-      CreateMockRead(resp, 2),
+      CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
       CreateMockRead(body, 3),
-      CreateMockRead(fin_body, 4),
-      CreateMockRead(resp2, 7),
-      MockRead(ASYNC, ERR_CONNECTION_RESET, 8),  // Abort!
+      // Delay the request here. For this test to pass, the three HTTP streams
+      // have to be created in order, but SpdySession doesn't actually guarantee
+      // that (See note in SpdySession::ProcessPendingStreamRequests). As a
+      // workaround, delay finishing up the first stream until the second and
+      // third streams are waiting in the SPDY stream request queue.
+      MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(fin_body, 5),
+      CreateMockRead(resp2, 8),
+      MockRead(ASYNC, ERR_CONNECTION_RESET, 9),  // Abort!
   };
 
   SequencedSocketData data(reads, writes);
   SequencedSocketData data_placeholder;
 
   TransactionHelperResult out;
-  NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
+  NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
   helper.RunPreTestSetup();
   helper.AddData(&data);
   // We require placeholder data because three get requests are sent out, so
   // there needs to be three sets of SSL connection data.
   helper.AddData(&data_placeholder);
   helper.AddData(&data_placeholder);
-  HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
-  HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+  HttpNetworkTransaction trans1(HIGHEST, helper.session());
+  HttpNetworkTransaction trans2(MEDIUM, helper.session());
   HttpNetworkTransaction* trans3(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
 
@@ -1672,8 +1677,14 @@
   ASSERT_EQ(out.rv, ERR_IO_PENDING);
   out.rv = trans3->Start(&request_, callback3.callback(), log_);
   ASSERT_EQ(out.rv, ERR_IO_PENDING);
+
+  // Run until both transactions are in the SpdySession's queue, waiting for the
+  // final request to complete.
+  base::RunLoop().RunUntilIdle();
+  data.Resume();
+
   out.rv = callback3.WaitForResult();
-  ASSERT_THAT(out.rv, IsError(ERR_ABORTED));
+  EXPECT_THAT(out.rv, IsError(ERR_ABORTED));
 
   const HttpResponseInfo* response1 = trans1.GetResponseInfo();
   ASSERT_TRUE(response1);
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index 18c6e5a..1fa0c7a 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -95,7 +95,8 @@
       greased_http2_frame_(greased_http2_frame),
       time_func_(time_func),
       push_delegate_(nullptr),
-      network_quality_estimator_(network_quality_estimator) {
+      network_quality_estimator_(network_quality_estimator),
+      weak_ptr_factory_(this) {
   NetworkChangeNotifier::AddIPAddressObserver(this);
   if (ssl_config_service_)
     ssl_config_service_->AddObserver(this);
@@ -306,6 +307,39 @@
   return base::WeakPtr<SpdySession>();
 }
 
+base::WeakPtr<SpdySession> SpdySessionPool::RequestSession(
+    const SpdySessionKey& key,
+    bool enable_ip_based_pooling,
+    bool is_websocket,
+    const NetLogWithSource& net_log,
+    base::RepeatingClosure on_request_destroyed_callback,
+    SpdySessionRequest::Delegate* delegate,
+    std::unique_ptr<SpdySessionRequest>* spdy_session_request,
+    bool* is_first_request_for_session) {
+  DCHECK(delegate);
+
+  base::WeakPtr<SpdySession> spdy_session =
+      FindAvailableSession(key, enable_ip_based_pooling, is_websocket, net_log);
+  if (spdy_session) {
+    // This value doesn't really matter, but best to always populate it, for
+    // consistency.
+    *is_first_request_for_session = true;
+    return spdy_session;
+  }
+
+  RequestSet* request_set = &spdy_session_request_map_[key];
+  *is_first_request_for_session = request_set->empty();
+  *spdy_session_request =
+      std::make_unique<SpdySessionRequest>(key, delegate, this);
+  request_set->insert(spdy_session_request->get());
+
+  if (on_request_destroyed_callback && !*is_first_request_for_session) {
+    spdy_session_pending_request_map_[key].push_back(
+        on_request_destroyed_callback);
+  }
+  return nullptr;
+}
+
 void SpdySessionPool::MakeSessionUnavailable(
     const base::WeakPtr<SpdySession>& available_session) {
   UnmapKey(available_session->spdy_session_key());
@@ -403,81 +437,24 @@
   CloseCurrentSessions(ERR_CERT_DATABASE_CHANGED);
 }
 
-void SpdySessionPool::OnNewSpdySessionReady(
-    const base::WeakPtr<SpdySession>& spdy_session) {
-  while (spdy_session) {
-    const SpdySessionKey& spdy_session_key = spdy_session->spdy_session_key();
-    // Each iteration may empty out the RequestSet for |spdy_session_key| in
-    // |spdy_session_request_map_|. So each time, check for RequestSet and use
-    // the first one.
-    //
-    // TODO(willchan): If it's important, switch RequestSet out for a FIFO
-    // queue (Order by priority first, then FIFO within same priority). Unclear
-    // that it matters here.
-    auto iter = spdy_session_request_map_.find(spdy_session_key);
-    if (iter == spdy_session_request_map_.end())
-      return;
-    SpdySessionRequest* request = *iter->second.begin();
-    SpdySessionRequest::Delegate* delegate = request->delegate();
-    RemoveRequestForSpdySession(request);
-    delegate->OnSpdySessionAvailable(spdy_session);
-  }
-  // TODO(mbelshe): Alert other valid requests.
-}
-
-bool SpdySessionPool::StartRequest(const SpdySessionKey& spdy_session_key,
-                                   const base::Closure& callback) {
-  auto iter = spdy_session_pending_request_map_.find(spdy_session_key);
-  if (iter == spdy_session_pending_request_map_.end()) {
-    spdy_session_pending_request_map_.emplace(spdy_session_key,
-                                              std::list<base::Closure>{});
-    return true;
-  }
-  iter->second.push_back(callback);
-  return false;
-}
-
-void SpdySessionPool::ResumePendingRequests(
-    const SpdySessionKey& spdy_session_key) {
-  auto iter = spdy_session_pending_request_map_.find(spdy_session_key);
-  if (iter != spdy_session_pending_request_map_.end()) {
-    for (auto callback : iter->second) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
-    }
-    spdy_session_pending_request_map_.erase(iter);
-  }
-}
-
-std::unique_ptr<SpdySessionPool::SpdySessionRequest>
-SpdySessionPool::CreateRequestForSpdySession(
-    const SpdySessionKey& spdy_session_key,
-    SpdySessionRequest::Delegate* delegate) {
-  DCHECK(delegate);
-
-  RequestSet& request_set = spdy_session_request_map_[spdy_session_key];
-  auto spdy_session_request =
-      std::make_unique<SpdySessionRequest>(spdy_session_key, delegate, this);
-  request_set.insert(spdy_session_request.get());
-  return spdy_session_request;
-}
-
 void SpdySessionPool::RemoveRequestForSpdySession(SpdySessionRequest* request) {
   DCHECK_EQ(this, request->spdy_session_pool());
 
   const SpdySessionKey& spdy_session_key = request->key();
   // Resume all pending requests now that |request| is done/canceled.
-  ResumePendingRequests(spdy_session_key);
+  if (spdy_session_pending_request_map_.find(spdy_session_key) !=
+      spdy_session_pending_request_map_.end()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&SpdySessionPool::UpdatePendingRequests,
+                       weak_ptr_factory_.GetWeakPtr(), spdy_session_key));
+  }
 
   auto iter = spdy_session_request_map_.find(spdy_session_key);
   DCHECK(iter != spdy_session_request_map_.end());
   RequestSet& request_set = iter->second;
   DCHECK(base::ContainsKey(request_set, request));
-  request_set.erase(request);
-  if (request_set.empty())
-    spdy_session_request_map_.erase(spdy_session_key);
-  // Clears |request|'s SpdySessionPool pointer, to prevent it from calling into
-  // this method again.
-  request->OnRemovedFromPool();
+  RemoveRequestInternal(iter, request_set.find(request));
 }
 
 void SpdySessionPool::DumpMemoryStats(
@@ -625,6 +602,10 @@
   sessions_.insert(new_session.release());
   MapKeyToAvailableSession(key, available_session);
 
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&SpdySessionPool::UpdatePendingRequests,
+                                weak_ptr_factory_.GetWeakPtr(), key));
+
   source_net_log.AddEvent(
       NetLogEventType::HTTP2_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET,
       available_session->net_log().source().ToEventParametersCallback());
@@ -643,4 +624,58 @@
   return available_session;
 }
 
+void SpdySessionPool::UpdatePendingRequests(const SpdySessionKey& key) {
+  auto it = LookupAvailableSessionByKey(key);
+  if (it != available_sessions_.end()) {
+    base::WeakPtr<SpdySession> new_session = it->second->GetWeakPtr();
+    while (new_session && new_session->IsAvailable()) {
+      // Each iteration may empty out the RequestSet for |spdy_session_key| in
+      // |spdy_session_request_map_|. So each time, check for RequestSet and use
+      // the first one. Could just keep track if the last iteration removed the
+      // final request, but it's possible that responding to one request will
+      // result in cancelling another one.
+      //
+      // TODO(willchan): If it's important, switch RequestSet out for a FIFO
+      // queue (Order by priority first, then FIFO within same priority).
+      // Unclear that it matters here.
+      auto iter = spdy_session_request_map_.find(key);
+      if (iter == spdy_session_request_map_.end())
+        break;
+      RequestSet* request_set = &iter->second;
+      RequestSet::iterator request = request_set->begin();
+      SpdySessionRequest::Delegate* delegate = (*request)->delegate();
+
+      RemoveRequestInternal(iter, request);
+
+      delegate->OnSpdySessionAvailable(new_session);
+    }
+  }
+
+  auto iter = spdy_session_pending_request_map_.find(key);
+  if (iter == spdy_session_pending_request_map_.end())
+    return;
+  // Remove all pending requests, if there are any. As a result, if one of these
+  // callbacks triggers a new RequestSession() call,
+  // |is_first_request_for_session| will be true.
+  std::list<base::RepeatingClosure> pending_requests = std::move(iter->second);
+  spdy_session_pending_request_map_.erase(iter);
+
+  // Resume any pending requests. This needs to be after the
+  // OnSpdySessionAvailable() calls, to prevent requests from calling into the
+  // socket pools in cases where that's not necessary.
+  for (auto callback : pending_requests) {
+    callback.Run();
+  }
+}
+
+void SpdySessionPool::RemoveRequestInternal(
+    SpdySessionRequestMap::iterator request_map_iterator,
+    RequestSet::iterator request_set_iterator) {
+  SpdySessionRequest* request = *request_set_iterator;
+  request_map_iterator->second.erase(request_set_iterator);
+  if (request_map_iterator->second.empty())
+    spdy_session_request_map_.erase(request_map_iterator);
+  request->OnRemovedFromPool();
+}
+
 }  // namespace net
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 4c29b04..8e18e28 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -188,6 +188,36 @@
       bool is_websocket,
       const NetLogWithSource& net_log);
 
+  // Just like FindAvailableSession.
+  //
+  // Additionally, if it returns nullptr, populates |spdy_session_request| with
+  // a request that will invoke |delegate| once a matching SPDY session becomes
+  // available through the creation of a new SpdySession (as opposed to by
+  // creating an alias for an existing session with a new host).
+  //
+  // |is_first_request_for_session| will be set to |true| if this is the first
+  // request for the session. If |on_request_destroyed_callback| is non-null and
+  // there is already at least one pending request for the session (i.e.,
+  // |is_first_request_for_session| is set to false), it will be invoked
+  // asynchronously whenever any matching |spdy_session_request| is destroyed or
+  // a matching SpdySession is created.
+  //
+  // |delegate|, |spdy_session_request|, and |is_first_request_for_session| must
+  // all be non-null.
+  //
+  // TODO(mmenke): Merge this into FindAvailableSession().
+  // TODO(mmenke): Don't invoke |on_request_destroyed_callback| when all
+  // requests for a session have been successfully responded to.
+  base::WeakPtr<SpdySession> RequestSession(
+      const SpdySessionKey& key,
+      bool enable_ip_based_pooling,
+      bool is_websocket,
+      const NetLogWithSource& net_log,
+      base::RepeatingClosure on_request_destroyed_callback,
+      SpdySessionRequest::Delegate* delegate,
+      std::unique_ptr<SpdySessionRequest>* spdy_session_request,
+      bool* is_first_request_for_session);
+
   // Remove all mappings and aliases for the given session, which must
   // still be available. Except for in tests, this must be called by
   // the given session itself.
@@ -252,31 +282,6 @@
   void DumpMemoryStats(base::trace_event::ProcessMemoryDump* pmd,
                        const std::string& parent_dump_absolute_name) const;
 
-  // Called when a SpdySession is ready. It will find appropriate Requests and
-  // fulfill them.
-  void OnNewSpdySessionReady(const base::WeakPtr<SpdySession>& spdy_session);
-
-  // Called when a HttpStreamRequest is started with |spdy_session_key|.
-  // Returns true if the request should continue. Returns false if the request
-  // should wait until |callback| is invoked before continuing.
-  bool StartRequest(const SpdySessionKey& spdy_session_key,
-                    const base::Closure& callback);
-
-  // Resumes pending requests with |spdy_session_key|.
-  void ResumePendingRequests(const SpdySessionKey& spdy_session_key);
-
-  // Create a request and add it to |spdy_session_request_map_| under
-  // |spdy_session_key| Key. |delegate|'s OnSpdySessionAvailable() callback will
-  // be invoked if a consumer calls OnNewSpdySessionReady() with a live
-  // SpdySession. |delegate| must remain valid until either its
-  // OnSpdySessionAvailable() callback has been invoked, or until the returned
-  // SpdySessionRequest has been destroyed.
-  //
-  // TODO(mmenke):  Merge with FindAvailableSession.
-  std::unique_ptr<SpdySessionRequest> CreateRequestForSpdySession(
-      const SpdySessionKey& spdy_session_key,
-      SpdySessionRequest::Delegate* delegate);
-
   void set_network_quality_estimator(
       NetworkQualityEstimator* network_quality_estimator) {
     network_quality_estimator_ = network_quality_estimator;
@@ -338,6 +343,21 @@
       std::unique_ptr<SpdySession> new_session,
       const NetLogWithSource& source_net_log);
 
+  // If a session with the specified |key| exists, invokes
+  // OnSpdySessionAvailable on all matching members of
+  // |spdy_session_request_map_|, removing them from the map. Regardless of
+  // whether or not such key exists, invokes all corresponding callbacks
+  // currently in |spdy_session_pending_request_map_|.
+  void UpdatePendingRequests(const SpdySessionKey& key);
+
+  // Removes the SpdySessionRequest at |request_set_iterator| from the
+  // RequestSet at |request_map_iterator| and calls OnRemovedFromPool() on the
+  // request. If the RequestSet becomes empty, also removes it from
+  // |spdy_session_request_map_|.
+  void RemoveRequestInternal(
+      SpdySessionRequestMap::iterator request_map_iterator,
+      RequestSet::iterator request_set_iterator);
+
   HttpServerProperties* http_server_properties_;
 
   TransportSecurityState* transport_security_state_;
@@ -386,7 +406,7 @@
 
   // TODO(xunjieli): Merge these two.
   SpdySessionRequestMap spdy_session_request_map_;
-  typedef std::map<SpdySessionKey, std::list<base::Closure>>
+  typedef std::map<SpdySessionKey, std::list<base::RepeatingClosure>>
       SpdySessionPendingRequestMap;
   SpdySessionPendingRequestMap spdy_session_pending_request_map_;
 
@@ -395,6 +415,8 @@
 
   NetworkQualityEstimator* network_quality_estimator_;
 
+  base::WeakPtrFactory<SpdySessionPool> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(SpdySessionPool);
 };
 
diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc
index 4e3ba902..4f0a7df 100644
--- a/services/network/public/cpp/resource_request.cc
+++ b/services/network/public/cpp/resource_request.cc
@@ -33,7 +33,6 @@
          should_reset_appcache == request.should_reset_appcache &&
          is_external_request == request.is_external_request &&
          cors_preflight_policy == request.cors_preflight_policy &&
-         service_worker_provider_id == request.service_worker_provider_id &&
          originated_from_service_worker ==
              request.originated_from_service_worker &&
          skip_service_worker == request.skip_service_worker &&
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 1e906c2c..eff0e42 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -58,7 +58,6 @@
   bool is_external_request = false;
   mojom::CorsPreflightPolicy cors_preflight_policy =
       mojom::CorsPreflightPolicy::kConsiderPreflight;
-  int service_worker_provider_id = -1;
   bool originated_from_service_worker = false;
   bool skip_service_worker = false;
   mojom::FetchRequestMode fetch_request_mode = mojom::FetchRequestMode::kNoCors;
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index 724ce787..c5377f9f 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -192,7 +192,6 @@
   out->appcache_host_id = data.appcache_host_id();
   out->should_reset_appcache = data.should_reset_appcache();
   out->is_external_request = data.is_external_request();
-  out->service_worker_provider_id = data.service_worker_provider_id();
   out->originated_from_service_worker = data.originated_from_service_worker();
   out->skip_service_worker = data.skip_service_worker();
   out->fetch_request_context_type = data.fetch_request_context_type();
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index a3b94fb9..f133b27 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -118,10 +118,6 @@
       const network::ResourceRequest& request) {
     return request.cors_preflight_policy;
   }
-  static int32_t service_worker_provider_id(
-      const network::ResourceRequest& request) {
-    return request.service_worker_provider_id;
-  }
   static bool originated_from_service_worker(
       const network::ResourceRequest& request) {
     return request.originated_from_service_worker;
diff --git a/services/network/public/cpp/url_request_mojom_traits_unittest.cc b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
index aadb113..fa1ff52 100644
--- a/services/network/public/cpp/url_request_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
@@ -68,7 +68,6 @@
   original.is_external_request = false;
   original.cors_preflight_policy =
       mojom::CorsPreflightPolicy::kConsiderPreflight;
-  original.service_worker_provider_id = -1;
   original.originated_from_service_worker = false;
   original.skip_service_worker = false;
   original.fetch_request_mode = mojom::FetchRequestMode::kNoCors;
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index bed9a86b..092fab2 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -175,12 +175,6 @@
   // A policy to decide if CORS-preflight fetch should be performed.
   CorsPreflightPolicy cors_preflight_policy;
 
-  // Indicates which frame (or worker context) the request is being loaded into.
-  // -1 corresponds to kInvalidServiceWorkerProviderId.
-  // TODO(jam): remove this from the struct since network service shouldn't know
-  // about this.
-  int32 service_worker_provider_id;
-
   // True if the request originated from a Service Worker, e.g. due to a
   // fetch() in the Service Worker script.
   bool originated_from_service_worker;
diff --git a/services/service_manager/sandbox/linux/bpf_audio_policy_linux.cc b/services/service_manager/sandbox/linux/bpf_audio_policy_linux.cc
index ee63d9e..dca79767 100644
--- a/services/service_manager/sandbox/linux/bpf_audio_policy_linux.cc
+++ b/services/service_manager/sandbox/linux/bpf_audio_policy_linux.cc
@@ -41,6 +41,9 @@
 #if defined(__NR_ftruncate64)
     case __NR_ftruncate64:
 #endif
+#if defined(__NR_fallocate)
+    case __NR_fallocate:
+#endif
 #if defined(__NR_getdents)
     case __NR_getdents:
 #endif
diff --git a/services/service_manager/sandbox/linux/bpf_cdm_policy_linux.cc b/services/service_manager/sandbox/linux/bpf_cdm_policy_linux.cc
index 214d76a..9d39e5d 100644
--- a/services/service_manager/sandbox/linux/bpf_cdm_policy_linux.cc
+++ b/services/service_manager/sandbox/linux/bpf_cdm_policy_linux.cc
@@ -31,6 +31,7 @@
     case __NR_fdatasync:
     case __NR_fsync:
     case __NR_ftruncate:
+    case __NR_fallocate:
 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
     defined(__aarch64__)
     case __NR_getrlimit:
diff --git a/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc b/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
index 1b966d2..ef7e6e48 100644
--- a/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
+++ b/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
@@ -40,6 +40,7 @@
   switch (sysno) {
 #if !defined(OS_CHROMEOS)
     case __NR_ftruncate:
+    case __NR_fallocate:
 #endif
     case __NR_ioctl:
       return Allow();
diff --git a/skia/ext/opacity_filter_canvas.cc b/skia/ext/opacity_filter_canvas.cc
index d7867591..76578cb 100644
--- a/skia/ext/opacity_filter_canvas.cc
+++ b/skia/ext/opacity_filter_canvas.cc
@@ -15,16 +15,12 @@
       alpha_(SkScalarRoundToInt(opacity * 255)),
       disable_image_filtering_(disable_image_filtering) { }
 
-bool OpacityFilterCanvas::onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type) const {
-  // TODO(fmalita): with the new onFilter() API we could override alpha even
-  // when the original paint is null; is this something we should do?
-  if (*paint) {
-    if (alpha_ < 255)
-      paint->writable()->setAlpha(alpha_);
+bool OpacityFilterCanvas::onFilter(SkPaint& paint) const {
+  if (alpha_ < 255)
+    paint.setAlpha(alpha_);
 
-    if (disable_image_filtering_)
-      paint->writable()->setFilterQuality(kNone_SkFilterQuality);
-  }
+  if (disable_image_filtering_)
+    paint.setFilterQuality(kNone_SkFilterQuality);
 
   return true;
 }
@@ -32,10 +28,10 @@
 void OpacityFilterCanvas::onDrawPicture(const SkPicture* picture,
                                         const SkMatrix* matrix,
                                         const SkPaint* paint) {
-  SkTCopyOnFirstWrite<SkPaint> filteredPaint(paint);
-  if (this->onFilter(&filteredPaint, kPicture_Type)) {
+  SkPaint filteredPaint(paint ? *paint : SkPaint());
+  if (this->onFilter(filteredPaint)) {
     // Unfurl pictures in order to filter nested paints.
-    this->SkCanvas::onDrawPicture(picture, matrix, filteredPaint);
+    this->SkCanvas::onDrawPicture(picture, matrix, &filteredPaint);
   }
 }
 
diff --git a/skia/ext/opacity_filter_canvas.h b/skia/ext/opacity_filter_canvas.h
index 450e378..a3da08ce 100644
--- a/skia/ext/opacity_filter_canvas.h
+++ b/skia/ext/opacity_filter_canvas.h
@@ -20,7 +20,7 @@
                       bool disable_image_filtering);
 
  protected:
-  bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override;
+  bool onFilter(SkPaint& paint) const override;
 
   void onDrawPicture(const SkPicture* picture,
                      const SkMatrix* matrix,
diff --git a/third_party/blink/common/feature_policy/feature_policy.cc b/third_party/blink/common/feature_policy/feature_policy.cc
index 9c280177..beaa203 100644
--- a/third_party/blink/common/feature_policy/feature_policy.cc
+++ b/third_party/blink/common/feature_policy/feature_policy.cc
@@ -387,6 +387,9 @@
        {mojom::FeaturePolicyFeature::kLazyLoad,
         FeatureDefaultValue(FeaturePolicy::FeatureDefault::EnableForAll,
                             mojom::PolicyValueType::kBool)},
+       {mojom::FeaturePolicyFeature::kLoadingFrameDefaultEager,
+        FeatureDefaultValue(FeaturePolicy::FeatureDefault::EnableForAll,
+                            mojom::PolicyValueType::kBool)},
        {mojom::FeaturePolicyFeature::kMagnetometer,
         FeatureDefaultValue(FeaturePolicy::FeatureDefault::EnableForSelf,
                             mojom::PolicyValueType::kBool)},
diff --git a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
index 168e083b..faad34a 100644
--- a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
+++ b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
@@ -91,6 +91,7 @@
   // which interfere with document's input stream (document.write(),
   // document.close(), etc.).
   kDocumentWrite = 28,
+  // TODO(ekaramad): kLazyLoad is deprecated; remove.
   // Used to enforce lazyloading for a frame and any nested <iframe> or image.
   kLazyLoad = 29,
   // Restricts the usage of layout-causing animations in a document.
@@ -126,6 +127,9 @@
   kUnoptimizedLosslessImages = 46,
   kUnoptimizedLosslessImagesStrict = 47,
 
+  // Loading policies.
+  kLoadingFrameDefaultEager = 48,
+
   // Don't change assigned numbers of any item, and don't reuse removed slots.
   // Add new features at the end of the enum.
   // Also, run update_feature_policy_enum.py in
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom b/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
index d748a51..4f61f7b2 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
@@ -22,7 +22,6 @@
 // WebServiceWorkerNetworkProvider used for starting a web worker (dedicated
 // worker or shared worker).
 struct ServiceWorkerProviderInfoForWorker {
-  int32 provider_id;
   associated ServiceWorkerContainerHost host_ptr_info;
   associated ServiceWorkerContainer& client_request;
 };
@@ -30,8 +29,6 @@
 // Sent from the browser process to the renderer. Contains parameters for the
 // WebServiceWorkerNetworkProvider used for starting a service worker.
 struct ServiceWorkerProviderInfoForStartWorker {
-  int32 provider_id;
-
   associated ServiceWorkerContainerHost host_ptr_info;
   associated ServiceWorkerContainer& client_request;
 
@@ -55,7 +52,6 @@
 // ServiceWorkerProviderInfoForWorker, we can unify them as a new struct
 // ServiceWorkerProviderInfoForClient.
 struct ServiceWorkerProviderInfoForWindow {
-  int32 provider_id;
   associated ServiceWorkerContainerHost host_ptr_info;
   associated ServiceWorkerContainer& client_request;
 };
diff --git a/third_party/blink/public/platform/web_url_request.h b/third_party/blink/public/platform/web_url_request.h
index c747fbb..9530944 100644
--- a/third_party/blink/public/platform/web_url_request.h
+++ b/third_party/blink/public/platform/web_url_request.h
@@ -36,7 +36,6 @@
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
-#include "third_party/blink/public/common/service_worker/service_worker_types.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "ui/base/page_transition_types.h"
@@ -132,12 +131,6 @@
     void set_transition_type(ui::PageTransition transition_type) {
       transition_type_ = transition_type;
     }
-    int service_worker_provider_id() const {
-      return service_worker_provider_id_;
-    }
-    void set_service_worker_provider_id(int service_worker_provider_id) {
-      service_worker_provider_id_ = service_worker_provider_id;
-    }
 
     // The request is for a prefetch-only client (i.e. running NoStatePrefetch)
     // and should use LOAD_PREFETCH network flags.
@@ -171,7 +164,6 @@
     bool is_main_frame_ = false;
     bool allow_download_ = true;
     ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK;
-    int service_worker_provider_id_ = blink::kInvalidServiceWorkerProviderId;
     bool is_for_no_state_prefetch_ = false;
     bool originated_from_service_worker_ = false;
     bool initiated_in_secure_context_ = false;
diff --git a/third_party/blink/renderer/DEPS b/third_party/blink/renderer/DEPS
index 8ce5e0b..eb3e573 100644
--- a/third_party/blink/renderer/DEPS
+++ b/third_party/blink/renderer/DEPS
@@ -39,6 +39,8 @@
     "+base/threading/thread_checker.h",
     "+base/time/time.h",
     "+base/timer/elapsed_timer.h",
+    "+base/trace_event/memory_dump_manager.h",
+    "+base/trace_event/memory_dump_provider.h",
     "+build",
     "+components/crash/core/common/crash_key.h",
     "+services/network/public/mojom",
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 6db8e36..37364a49 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -53,7 +53,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 
 namespace blink {
@@ -94,8 +93,6 @@
 Animation* Animation::Create(ExecutionContext* execution_context,
                              AnimationEffect* effect,
                              ExceptionState& exception_state) {
-  DCHECK(RuntimeEnabledFeatures::WebAnimationsAPIEnabled());
-
   Document* document = To<Document>(execution_context);
   return Create(effect, &document->Timeline(), exception_state);
 }
@@ -104,8 +101,6 @@
                              AnimationEffect* effect,
                              AnimationTimeline* timeline,
                              ExceptionState& exception_state) {
-  DCHECK(RuntimeEnabledFeatures::WebAnimationsAPIEnabled());
-
   if (!timeline) {
     return Create(execution_context, effect, exception_state);
   }
diff --git a/third_party/blink/renderer/core/animation/animation.idl b/third_party/blink/renderer/core/animation/animation.idl
index a096e1d..1c5fb3f 100644
--- a/third_party/blink/renderer/core/animation/animation.idl
+++ b/third_party/blink/renderer/core/animation/animation.idl
@@ -33,8 +33,8 @@
 enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
 
 [
+    Exposed=Window,
     Constructor(optional AnimationEffect? effect = null, optional AnimationTimeline? timeline),
-    Exposed(Window WebAnimationsAPI),
     ConstructorCallWith=ExecutionContext,
     RaisesException=Constructor,
     ActiveScriptWrappable
diff --git a/third_party/blink/renderer/core/css/css_keyframe_rule.cc b/third_party/blink/renderer/core/css/css_keyframe_rule.cc
index 22102d24..b4ff8d4 100644
--- a/third_party/blink/renderer/core/css/css_keyframe_rule.cc
+++ b/third_party/blink/renderer/core/css/css_keyframe_rule.cc
@@ -49,7 +49,8 @@
         DOMExceptionCode::kSyntaxError,
         "The key '" + key_text + "' is invalid and cannot be parsed");
 
-  To<CSSKeyframesRule>(parentRule())->StyleChanged();
+  if (auto* parent = To<CSSKeyframesRule>(parentRule()))
+    parent->StyleChanged();
 }
 
 CSSStyleDeclaration* CSSKeyframeRule::style() const {
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.cc b/third_party/blink/renderer/core/css/css_style_sheet.cc
index 1734eda..e011bff 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet.cc
+++ b/third_party/blink/renderer/core/css/css_style_sheet.cc
@@ -42,7 +42,6 @@
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/svg/svg_style_element.h"
-#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
@@ -414,10 +413,11 @@
          child_rule_cssom_wrappers_.size() == contents_->RuleCount());
 
   if (index >= length()) {
-    exception_state.ThrowRangeError(
-        ExceptionMessages::IndexOutsideRange<unsigned>(
-            "index", index, 0, ExceptionMessages::kInclusiveBound, length(),
-            ExceptionMessages::kExclusiveBound));
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kIndexSizeError,
+        "The index provided (" + String::Number(index) +
+            ") is larger than the maximum index (" +
+            String::Number(length() - 1) + ").");
     return;
   }
   RuleMutationScope mutation_scope(this);
diff --git a/third_party/blink/renderer/core/css/keyframe_style_rule_css_style_declaration.cc b/third_party/blink/renderer/core/css/keyframe_style_rule_css_style_declaration.cc
index 7c06339..7f2bc8b5b 100644
--- a/third_party/blink/renderer/core/css/keyframe_style_rule_css_style_declaration.cc
+++ b/third_party/blink/renderer/core/css/keyframe_style_rule_css_style_declaration.cc
@@ -16,7 +16,8 @@
 
 void KeyframeStyleRuleCSSStyleDeclaration::DidMutate(MutationType type) {
   StyleRuleCSSStyleDeclaration::DidMutate(type);
-  To<CSSKeyframesRule>(parent_rule_->parentRule())->StyleChanged();
+  if (auto* parent = To<CSSKeyframesRule>(parent_rule_->parentRule()))
+    parent->StyleChanged();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5 b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
index 8df7b83..ae3df91 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
@@ -107,6 +107,11 @@
       depends_on: ["ExperimentalProductivityFeatures"],
     },
     {
+      name: "LoadingFrameDefaultEager",
+      feature_policy_name: "loading-frame-default-eager",
+      depends_on: ["ExperimentalProductivityFeatures"]
+    },
+    {
       name: "Magnetometer",
       feature_policy_name: "magnetometer",
       depends_on: ["Sensor"],
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index 5ae8f3b7..bfc6b95 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -445,12 +445,16 @@
   if (IsPlugin())
     request.SetSkipServiceWorker(true);
 
+  // When the feature policy "loading-frame-default-eager" is disabled in
+  // the document, loading attribute value "auto" (or unset/invalid values) will
+  // also be interpreted as "lazy".
+  const auto& loading_attr = FastGetAttribute(html_names::kLoadingAttr);
+  bool loading_lazy_set = EqualIgnoringASCIICase(loading_attr, "lazy") ||
+                          (IsLoadingFrameDefaultEagerEnforced() &&
+                           !EqualIgnoringASCIICase(loading_attr, "eager"));
   if (!lazy_load_frame_observer_ &&
-      IsFrameLazyLoadable(
-          GetDocument(), url,
-          EqualIgnoringASCIICase(FastGetAttribute(html_names::kLoadingAttr),
-                                 "lazy"),
-          should_lazy_load_children_)) {
+      IsFrameLazyLoadable(GetDocument(), url, loading_lazy_set,
+                          should_lazy_load_children_)) {
     // By default, avoid deferring subresources inside a lazily loaded frame.
     // This will make it possible for subresources in hidden frames to load that
     // will never be visible, as well as make it so that deferred frames that
@@ -522,4 +526,10 @@
   FrameOwner::Trace(visitor);
 }
 
+bool HTMLFrameOwnerElement::IsLoadingFrameDefaultEagerEnforced() const {
+  return RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
+         !GetDocument().IsFeatureEnabled(
+             mojom::FeaturePolicyFeature::kLoadingFrameDefaultEager);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.h b/third_party/blink/renderer/core/html/html_frame_owner_element.h
index 5169f3c1..c65e9f43 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.h
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.h
@@ -174,6 +174,8 @@
     return network::mojom::ReferrerPolicy::kDefault;
   }
 
+  bool IsLoadingFrameDefaultEagerEnforced() const;
+
   Member<Frame> content_frame_;
   Member<EmbeddedContentView> embedded_content_view_;
   FramePolicy frame_policy_;
diff --git a/third_party/blink/renderer/core/html/portal/html_portal_element.idl b/third_party/blink/renderer/core/html/portal/html_portal_element.idl
index eb09016..e0b1eae 100644
--- a/third_party/blink/renderer/core/html/portal/html_portal_element.idl
+++ b/third_party/blink/renderer/core/html/portal/html_portal_element.idl
@@ -4,7 +4,7 @@
 
 // https://wicg.github.io/portals/#the-portal-element
 
-[HTMLConstructor, RuntimeEnabled=Portals]
+[Exposed=Window, HTMLConstructor, RuntimeEnabled=Portals]
 interface HTMLPortalElement : HTMLElement {
   [CEReactions, Reflect, URL, RaisesException=Setter] attribute URLString src;
   [CallWith=ScriptState] Promise<void> activate(optional PortalActivateOptions options);
diff --git a/third_party/blink/renderer/core/html/portal/portal_host.idl b/third_party/blink/renderer/core/html/portal/portal_host.idl
index 7d972d0..2cf4048 100644
--- a/third_party/blink/renderer/core/html/portal/portal_host.idl
+++ b/third_party/blink/renderer/core/html/portal/portal_host.idl
@@ -4,5 +4,5 @@
 
 // https://wicg.github.io/portals/#the-portalhost-interface
 
-[RuntimeEnabled=Portals]
+[Exposed=Window, RuntimeEnabled=Portals]
 interface PortalHost : EventTarget {};
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 72986ec..3ac6079 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -258,19 +258,6 @@
 
   PropagateStyleToAnonymousChildren();
 
-  // The LayoutView is always a container of fixed positioned descendants. In
-  // addition, SVG foreignObjects become such containers, so that descendants
-  // of a foreignObject cannot escape it. Similarly, text controls let authors
-  // select elements inside that are created by user agent shadow DOM, and we
-  // have (C++) code that assumes that the elements are indeed contained by the
-  // text control. So just make sure this is the case. Finally, computed style
-  // may turn us into a container of all things, e.g. if the element is
-  // transformed, or contain:paint is specified.
-  SetCanContainFixedPositionObjects(
-      IsLayoutView() || IsSVGForeignObject() || IsTextControl() ||
-      new_style.CanContainFixedPositionObjects(IsDocumentElement()) ||
-      ShouldApplyPaintContainment() || ShouldApplyLayoutContainment());
-
   // It's possible for our border/padding to change, but for the overall logical
   // width or height of the block to end up being the same. We keep track of
   // this change so in layoutBlock, we can know to set relayoutChildren=true.
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index c73402e..cafeed7 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -265,6 +265,9 @@
   bool had_layer = HasLayer();
   bool layer_was_self_painting = had_layer && Layer()->IsSelfPaintingLayer();
   bool was_horizontal_writing_mode = IsHorizontalWritingMode();
+  bool could_contain_fixed = ComputeIsFixedContainer(old_style);
+  bool could_contain_absolute =
+      could_contain_fixed || ComputeIsAbsoluteContainer(old_style);
 
   LayoutObject::StyleDidChange(diff, old_style);
   UpdateFromStyle();
@@ -326,10 +329,8 @@
   }
 
   if (old_style &&
-      (old_style->CanContainFixedPositionObjects(IsDocumentElement()) !=
-           StyleRef().CanContainFixedPositionObjects(IsDocumentElement()) ||
-       old_style->CanContainAbsolutePositionObjects() !=
-           StyleRef().CanContainAbsolutePositionObjects())) {
+      (could_contain_fixed != CanContainFixedPositionObjects() ||
+       could_contain_absolute != CanContainAbsolutePositionObjects())) {
     // If out of flow element containment changed, then we need to force a
     // subtree paint property update, since the children elements may now be
     // referencing a different container.
@@ -632,6 +633,7 @@
   SetInline(style_to_use.IsDisplayInlineType());
   SetPositionState(style_to_use.GetPosition());
   SetHorizontalWritingMode(style_to_use.IsHorizontalWritingMode());
+  SetCanContainFixedPositionObjects(ComputeIsFixedContainer(&style_to_use));
 }
 
 LayoutBlock* LayoutBoxModelObject::ContainingBlockForAutoHeightDetection(
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index d7992600..41ea4d16 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -332,12 +332,8 @@
     }
   }
 
-  bool old_style_is_containing_block =
-      old_style && (old_style->CanContainAbsolutePositionObjects() ||
-                    old_style->HasFilter());
-  bool new_style_is_containing_block =
-      old_style &&
-      (new_style.CanContainAbsolutePositionObjects() || new_style.HasFilter());
+  bool old_style_is_containing_block = ComputeIsAbsoluteContainer(old_style);
+  bool new_style_is_containing_block = CanContainAbsolutePositionObjects();
   // If we are changing to/from static, we need to reposition
   // out-of-flow positioned descendants.
   if (old_style_is_containing_block != new_style_is_containing_block) {
@@ -354,9 +350,6 @@
   }
 
   PropagateStyleToAnonymousChildren();
-
-  // Only filtered inlines can contain fixed position elements.
-  SetCanContainFixedPositionObjects(new_style.HasFilter());
 }
 
 void LayoutInline::UpdateAlwaysCreateLineBoxes(bool full_layout) {
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index e681b29..4fd4a786 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1203,6 +1203,41 @@
   return DynamicTo<LayoutBlock>(object);
 }
 
+bool LayoutObject::ComputeIsFixedContainer(const ComputedStyle* style) const {
+  if (!style)
+    return false;
+  // https://www.w3.org/TR/filter-effects-1/#FilterProperty
+  if (style->HasFilter() && !this->IsDocumentElement())
+    return true;
+  // The LayoutView is always a container of fixed positioned descendants. In
+  // addition, SVG foreignObjects become such containers, so that descendants
+  // of a foreignObject cannot escape it. Similarly, text controls let authors
+  // select elements inside that are created by user agent shadow DOM, and we
+  // have (C++) code that assumes that the elements are indeed contained by the
+  // text control. So just make sure this is the case.
+  if (this->IsLayoutView() || this->IsSVGForeignObject() ||
+      this->IsTextControl())
+    return true;
+  // https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants
+  if (style->HasTransformRelatedProperty()) {
+    if (!this->IsInline() || this->IsAtomicInlineLevel())
+      return true;
+  }
+  // https://www.w3.org/TR/css-contain-1/#containment-layout
+  if (this->ShouldApplyPaintContainment(*style) ||
+      this->ShouldApplyLayoutContainment(*style))
+    return true;
+  return false;
+}
+
+bool LayoutObject::ComputeIsAbsoluteContainer(
+    const ComputedStyle* style) const {
+  if (!style)
+    return false;
+  return style->CanContainAbsolutePositionObjects() ||
+         ComputeIsFixedContainer(style);
+}
+
 FloatRect LayoutObject::AbsoluteBoundingBoxFloatRect(
     MapCoordinatesFlags flags) const {
   Vector<FloatQuad> quads;
@@ -1771,28 +1806,41 @@
     LayoutRect& rect,
     VisualRectFlags visual_rect_flags,
     bool& intersects) const {
-  if (!(visual_rect_flags & kUseGeometryMapper) ||
-      !FirstFragment().HasLocalBorderBoxProperties() || !ancestor ||
-      !ancestor->FirstFragment().HasLocalBorderBoxProperties()) {
-    intersects = true;
+  intersects = true;
+  if (!(visual_rect_flags & kUseGeometryMapper) || !ancestor ||
+      !ancestor->FirstFragment().HasLocalBorderBoxProperties())
     return false;
-  }
 
-  if (ancestor == this) {
-    intersects = true;
+  if (ancestor == this)
     return true;
+
+  const auto* property_container = this;
+  AncestorSkipInfo skip_info(ancestor);
+  while (!property_container->FirstFragment().HasLocalBorderBoxProperties()) {
+    property_container = property_container->Container(&skip_info);
+    if (!property_container || skip_info.AncestorSkipped())
+      return false;
   }
 
+  // This works because it's not possible to have any intervening clips,
+  // effects, transforms between |this| and |property_container|, and therefore
+  // FirstFragment().PaintOffset() is relative to the transform space defined by
+  // FirstFragment().LocalBorderBoxProperties() (if this == property_container)
+  // or property_container->FirstFragment().ContentsProperties().
   rect.MoveBy(FirstFragment().PaintOffset());
-  FloatClipRect clip_rect((FloatRect(rect)));
-  intersects = GeometryMapper::LocalToAncestorVisualRect(
-      FirstFragment().LocalBorderBoxProperties(),
-      ancestor->FirstFragment().ContentsProperties(), clip_rect,
-      kIgnorePlatformOverlayScrollbarSize,
-      (visual_rect_flags & kEdgeInclusive) ? kInclusiveIntersect
-                                           : kNonInclusiveIntersect);
-
-  rect = LayoutRect(clip_rect.Rect());
+  if (property_container != ancestor) {
+    FloatClipRect clip_rect((FloatRect(rect)));
+    const auto& local_state =
+        property_container == this
+            ? FirstFragment().LocalBorderBoxProperties()
+            : property_container->FirstFragment().ContentsProperties();
+    intersects = GeometryMapper::LocalToAncestorVisualRect(
+        local_state, ancestor->FirstFragment().ContentsProperties(), clip_rect,
+        kIgnorePlatformOverlayScrollbarSize,
+        (visual_rect_flags & kEdgeInclusive) ? kInclusiveIntersect
+                                             : kNonInclusiveIntersect);
+    rect = LayoutRect(clip_rect.Rect());
+  }
   rect.MoveBy(-ancestor->FirstFragment().PaintOffset());
 
   return true;
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 0554a29..6c0328d4 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -485,16 +485,22 @@
 
   UniqueObjectId UniqueId() const { return fragment_.UniqueId(); }
 
+  inline bool ShouldApplyPaintContainment(const ComputedStyle& style) const {
+    return style.ContainsPaint() && (!IsInline() || IsAtomicInlineLevel()) &&
+           !IsRubyText() && (!IsTablePart() || IsLayoutBlockFlow());
+  }
+
   inline bool ShouldApplyPaintContainment() const {
-    return StyleRef().ContainsPaint() &&
-           (!IsInline() || IsAtomicInlineLevel()) && !IsRubyText() &&
-           (!IsTablePart() || IsLayoutBlockFlow());
+    return ShouldApplyPaintContainment(StyleRef());
+  }
+
+  inline bool ShouldApplyLayoutContainment(const ComputedStyle& style) const {
+    return style.ContainsLayout() && (!IsInline() || IsAtomicInlineLevel()) &&
+           !IsRubyText() && (!IsTablePart() || IsLayoutBlockFlow());
   }
 
   inline bool ShouldApplyLayoutContainment() const {
-    return StyleRef().ContainsLayout() &&
-           (!IsInline() || IsAtomicInlineLevel()) && !IsRubyText() &&
-           (!IsTablePart() || IsLayoutBlockFlow());
+    return ShouldApplyLayoutContainment(StyleRef());
   }
 
   inline bool ShouldApplySizeContainment() const {
@@ -1199,6 +1205,13 @@
            (position == EPosition::kFixed && CanContainFixedPositionObjects());
   }
 
+  // Returns true if style would make this object an absolute container.
+  bool ComputeIsAbsoluteContainer(const ComputedStyle* style) const;
+
+  // Returns true if style would make this object a fixed container.
+  // This value gets cached by bitfields_.can_contain_fixed_position_objects_.
+  bool ComputeIsFixedContainer(const ComputedStyle* style) const;
+
   virtual LayoutObject* HoverAncestor() const { return Parent(); }
 
   Element* OffsetParent(const Element* = nullptr) const;
diff --git a/third_party/blink/renderer/core/layout/layout_table_box_component.cc b/third_party/blink/renderer/core/layout/layout_table_box_component.cc
index b080706..9c162339 100644
--- a/third_party/blink/renderer/core/layout/layout_table_box_component.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_box_component.cc
@@ -57,12 +57,4 @@
   box.last_paint_rect_ = paint_rect;
 }
 
-void LayoutTableBoxComponent::StyleDidChange(StyleDifference diff,
-                                             const ComputedStyle* old_style) {
-  LayoutBox::StyleDidChange(diff, old_style);
-  SetCanContainFixedPositionObjects(
-      StyleRef().CanContainFixedPositionObjects(false) ||
-      ShouldApplyPaintContainment() || ShouldApplyLayoutContainment());
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_table_box_component.h b/third_party/blink/renderer/core/layout/layout_table_box_component.h
index 73c0fa6e..78cca0f 100644
--- a/third_party/blink/renderer/core/layout/layout_table_box_component.h
+++ b/third_party/blink/renderer/core/layout/layout_table_box_component.h
@@ -73,8 +73,6 @@
     return Children()->LastChild();
   }
 
-  void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
-
  private:
   // Column, section and row's visibility has rules different from other
   // elements. For example, column's visibility:hidden doesn't apply; row's
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index 06dce198..bd04c075a8 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -128,27 +128,16 @@
   }
 }
 
-// Answers true if |node| is completely outside the user's (visual) viewport.
-// This logic is used by spatnav to rule out offscreen focus candidates and an
-// offscreen activeElement. When activeElement is offscreen, spatnav doesn't use
-// it as the search origin; the search will start at an edge of the visual
-// viewport instead.
-// TODO(crbug.com/889840): Fix VisibleBoundsInVisualViewport().
-// If VisibleBoundsInVisualViewport() would have taken "element-clips" into
-// account, spatnav could have called it directly; no need to check the
-// LayoutObject's VisibleContentRect.
-bool IsOffscreen(const Node* node) {
-  DCHECK(node);
-
-  LocalFrameView* frame_view = node->GetDocument().View();
+FloatRect RectInViewport(const Node& node) {
+  LocalFrameView* frame_view = node.GetDocument().View();
   if (!frame_view)
-    return true;
+    return FloatRect();
 
   DCHECK(!frame_view->NeedsLayout());
 
-  LayoutObject* object = node->GetLayoutObject();
+  LayoutObject* object = node.GetLayoutObject();
   if (!object)
-    return true;
+    return FloatRect();
 
   // Get the rect in the object's own frame. We use VisualRectInDocument for
   // legacy reasons, it has some special cases for inlines that we'd like to
@@ -181,7 +170,21 @@
       FloatRect(FloatPoint(), FloatSize(visual_viewport.Size()));
   rect_in_viewport.Intersect(viewport_rect);
 
-  return rect_in_viewport.IsEmpty();
+  return rect_in_viewport;
+}
+
+// Answers true if |node| is completely outside the user's (visual) viewport.
+// This logic is used by spatnav to rule out offscreen focus candidates and an
+// offscreen activeElement. When activeElement is offscreen, spatnav doesn't use
+// it as the search origin; the search will start at an edge of the visual
+// viewport instead.
+// TODO(crbug.com/889840): Fix VisibleBoundsInVisualViewport().
+// If VisibleBoundsInVisualViewport() would have taken "element-clips" into
+// account, spatnav could have called it directly; no need to check the
+// LayoutObject's VisibleContentRect.
+bool IsOffscreen(const Node* node) {
+  DCHECK(node);
+  return RectInViewport(*node).IsEmpty();
 }
 
 // As IsOffscreen() but returns visibility through the |node|'s frame's viewport
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h
index eccdac7..ca7e4c8 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.h
+++ b/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -71,6 +71,7 @@
 };
 
 CORE_EXPORT bool HasRemoteFrame(const Node*);
+CORE_EXPORT FloatRect RectInViewport(const Node&);
 CORE_EXPORT bool IsOffscreen(const Node*);
 bool ScrollInDirection(Node* container, SpatialNavigationDirection);
 CORE_EXPORT bool IsScrollableNode(const Node* node);
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
index 7b2b3b94..5525d117 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
@@ -400,9 +401,14 @@
       layout_object->ScrollRectToVisible(
           element->BoundingBoxForScrollIntoView(), WebScrollIntoViewParams());
     }
+
+    DispatchMouseMoveAt(interest_element_);
+
     return;
   }
 
+  DispatchMouseMoveAt(element);
+
   if (!element)
     return;
 
@@ -416,6 +422,28 @@
                              kWebFocusTypeSpatialNavigation, nullptr));
 }
 
+void SpatialNavigationController::DispatchMouseMoveAt(Element* element) {
+  FloatPoint event_position =
+      element ? RectInViewport(*element).Location() : FloatPoint(-1, -1);
+
+  // TODO(bokan): Can we get better screen coordinates?
+  FloatPoint event_position_screen = event_position;
+  int click_count = 0;
+  WebMouseEvent fake_mouse_move_event(
+      WebInputEvent::kMouseMove, event_position, event_position_screen,
+      WebPointerProperties::Button::kNoButton, click_count,
+      WebInputEvent::kRelativeMotionEvent, CurrentTimeTicks());
+  Vector<WebMouseEvent> coalesced_events, predicted_events;
+
+  DCHECK(IsA<LocalFrame>(page_->MainFrame()));
+  LocalFrame* frame = DynamicTo<LocalFrame>(page_->MainFrame());
+
+  DCHECK(frame);
+  frame->GetEventHandler().HandleMouseMoveEvent(
+      TransformWebMouseEvent(frame->View(), fake_mouse_move_event),
+      coalesced_events, predicted_events);
+}
+
 bool SpatialNavigationController::IsValidCandidate(
     const Element& element) const {
   return element.IsKeyboardFocusable();
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.h b/third_party/blink/renderer/core/page/spatial_navigation_controller.h
index 674c3341..db5b9dd 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_controller.h
+++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.h
@@ -75,6 +75,12 @@
   Node* StartingNode();
   void MoveInterestTo(Node* next_node);
 
+  // Dispatches a fake mouse move event at the center of the given element to
+  // produce hover state and mouse enter/exit events. If no element is given,
+  // we dispatch a mouse event outside of the page to simulate the pointer
+  // leaving the page (and clearing hover, producing mouse leave).
+  void DispatchMouseMoveAt(Element* element);
+
   // Returns true if the element should be considered for navigation.
   bool IsValidCandidate(const Element& element) const;
 
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
index 35a114e..9430717 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -4,11 +4,16 @@
 
 #include "third_party/blink/renderer/modules/storage/cached_storage_area.h"
 
+#include <inttypes.h>
+
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/rand_util.h"
+#include "base/task/post_task.h"
+#include "base/trace_event/memory_dump_manager.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
@@ -235,6 +240,10 @@
   mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info;
   binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner));
   mojo_area_->AddObserver(std::move(ptr_info));
+
+  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, "DOMStorage",
+      ThreadScheduler::Current()->DeprecatedDefaultTaskRunner());
 }
 
 // SessionStorage constructor.
@@ -253,9 +262,16 @@
   mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info;
   binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner));
   mojo_area_->AddObserver(std::move(ptr_info));
+
+  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, "DOMStorage",
+      ThreadScheduler::Current()->DeprecatedDefaultTaskRunner());
 }
 
-CachedStorageArea::~CachedStorageArea() = default;
+CachedStorageArea::~CachedStorageArea() {
+  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+      this);
+}
 
 void CachedStorageArea::KeyAdded(const Vector<uint8_t>& key,
                                  const Vector<uint8_t>& value,
@@ -343,6 +359,27 @@
   should_send_old_value_on_mutations_ = value;
 }
 
+bool CachedStorageArea::OnMemoryDump(
+    const base::trace_event::MemoryDumpArgs& args,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  using base::trace_event::MemoryAllocatorDump;
+
+  WTF::String dump_name = WTF::String::Format(
+      "site_storage/%s/0x%" PRIXPTR "/cache_size",
+      IsSessionStorage() ? "session_storage" : "local_storage",
+      reinterpret_cast<uintptr_t>(this));
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name.Utf8().data());
+  // TODO(triploblastic@): rename memory_used() to quota_used() and create
+  // memory_used() function to actually count the memory used.
+  dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                  MemoryAllocatorDump::kUnitsBytes,
+                  memory_used() / sizeof(UChar));
+  pmd->AddSuballocation(
+      dump->guid(),
+      String(WTF::Partitions::kAllocatedObjectPoolName).Utf8().data());
+  return true;
+}
+
 void CachedStorageArea::KeyAddedOrChanged(const Vector<uint8_t>& key,
                                           const Vector<uint8_t>& new_value,
                                           const String& old_value,
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.h b/third_party/blink/renderer/modules/storage/cached_storage_area.h
index fcf1110..0e7dc69 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.h
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_CACHED_STORAGE_AREA_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_CACHED_STORAGE_AREA_H_
 
+#include "base/trace_event/memory_dump_provider.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
@@ -29,7 +30,8 @@
 // objects.
 class MODULES_EXPORT CachedStorageArea
     : public mojom::blink::StorageAreaObserver,
-      public RefCounted<CachedStorageArea> {
+      public RefCounted<CachedStorageArea>,
+      public base::trace_event::MemoryDumpProvider {
  public:
   // Instances of this class are used to identify the "source" of any changes
   // made to this storage area, as well as to dispatch any incoming change
@@ -124,6 +126,10 @@
   void AllDeleted(const String& source) override;
   void ShouldSendOldValueOnMutations(bool value) override;
 
+  // base::trace_event::MemoryDumpProvider:
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+                    base::trace_event::ProcessMemoryDump* pmd) override;
+
   // Common helper for KeyAdded() and KeyChanged()
   void KeyAddedOrChanged(const Vector<uint8_t>& key,
                          const Vector<uint8_t>& new_value,
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_callback.h b/third_party/blink/renderer/modules/webgpu/dawn_callback.h
index d605965..d1fa55b 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_callback.h
+++ b/third_party/blink/renderer/modules/webgpu/dawn_callback.h
@@ -57,20 +57,22 @@
 
   void Reset() { callback_.Reset(); }
 
-  UnboundCallbackFunction UnboundCallback() {
-    return [](Args... args, DawnCallbackUserdata handle) {
-      // After this non-repeating callback is run, it should delete itself.
-      auto callback =
-          std::unique_ptr<DawnCallback>(DawnCallback::FromUserdata(handle));
-      return std::move(*callback).Run(std::forward<Args>(args)...);
-    };
+  static R CallUnboundCallback(Args... args, DawnCallbackUserdata handle) {
+    // After this non-repeating callback is run, it should delete itself.
+    auto callback =
+        std::unique_ptr<DawnCallback>(DawnCallback::FromUserdata(handle));
+    return std::move(*callback).Run(std::forward<Args>(args)...);
   }
 
+  static R CallUnboundRepeatingCallback(Args... args,
+                                        DawnCallbackUserdata handle) {
+    return DawnCallback::FromUserdata(handle)->Run(std::forward<Args>(args)...);
+  }
+
+  UnboundCallbackFunction UnboundCallback() { return CallUnboundCallback; }
+
   UnboundCallbackFunction UnboundRepeatingCallback() {
-    return [](Args... args, DawnCallbackUserdata handle) {
-      return DawnCallback::FromUserdata(handle)->Run(
-          std::forward<Args>(args)...);
-    };
+    return CallUnboundRepeatingCallback;
   }
 
   DawnCallbackUserdata AsUserdata() {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
index 948cd7d3..8184ce5a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -4,19 +4,67 @@
 
 #include "third_party/blink/renderer/modules/webgpu/gpu_buffer.h"
 
+#include "gpu/command_buffer/client/webgpu_interface.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_callback.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_buffer_descriptor.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
 
+namespace {
+
+// crbug.com/951196
+// Currently, this value is less than the maximum ArrayBuffer length which is
+// theoretically 2^53 - 1 (Number.MAX_SAFE_INTEGER). However, creating a typed
+// array from an ArrayBuffer of size greater than TypedArray::kMaxLength crashes
+// DevTools and gives obscure errors.
+constexpr size_t kLargestMappableSize = v8::TypedArray::kMaxLength;
+
+bool ValidateMapSize(uint64_t buffer_size,
+                     ScriptPromiseResolver* resolver,
+                     ExceptionState& exception_state) {
+  if (buffer_size > kLargestMappableSize) {
+    WTF::StringBuilder message_builder;
+    message_builder.Append(WTF::StringView("Buffer of "));
+    message_builder.AppendNumber(buffer_size);
+    message_builder.Append(WTF::StringView(" bytes too large for mapping"));
+
+    WTF::String message = message_builder.ToString();
+
+    exception_state.ThrowRangeError(message);
+    resolver->Reject(
+        DOMException::Create(DOMExceptionCode::kOperationError, message));
+
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
 // static
 GPUBuffer* GPUBuffer::Create(GPUDevice* device,
                              const GPUBufferDescriptor* webgpu_desc) {
-  NOTIMPLEMENTED();
-  return nullptr;
+  DCHECK(device);
+  DCHECK(webgpu_desc);
+
+  DawnBufferDescriptor dawn_desc;
+  dawn_desc.nextInChain = nullptr;
+  dawn_desc.usage = AsDawnEnum<DawnBufferUsageBit>(webgpu_desc->usage());
+  dawn_desc.size = webgpu_desc->size();
+
+  return MakeGarbageCollected<GPUBuffer>(
+      device, dawn_desc.size,
+      device->GetProcs().deviceCreateBuffer(device->GetHandle(), &dawn_desc));
 }
 
-GPUBuffer::GPUBuffer(GPUDevice* device, DawnBuffer buffer)
-    : DawnObject<DawnBuffer>(device, buffer) {}
+GPUBuffer::GPUBuffer(GPUDevice* device, uint64_t size, DawnBuffer buffer)
+    : DawnObject<DawnBuffer>(device, buffer), size_(size) {}
 
 GPUBuffer::~GPUBuffer() {
   if (IsDawnControlClientDestroyed()) {
@@ -25,4 +73,152 @@
   GetProcs().bufferRelease(GetHandle());
 }
 
+void GPUBuffer::Trace(blink::Visitor* visitor) {
+  visitor->Trace(mapped_buffer_);
+  DawnObject<DawnBuffer>::Trace(visitor);
+}
+
+void GPUBuffer::setSubData(uint64_t dst_byte_offset,
+                           const MaybeShared<DOMArrayBufferView>& src,
+                           uint64_t src_byte_offset,
+                           uint64_t byte_length,
+                           ExceptionState& exception_state) {
+  const uint8_t* src_base =
+      reinterpret_cast<const uint8_t*>(src.View()->BaseAddress());
+  size_t src_byte_length = src.View()->byteLength();
+
+  if (src_byte_offset > src_byte_length) {
+    exception_state.ThrowRangeError("srcOffset is too large");
+    return;
+  }
+
+  if (byte_length == 0) {
+    byte_length = src_byte_length - src_byte_offset;
+  } else if (byte_length > src_byte_length - src_byte_offset) {
+    exception_state.ThrowRangeError("byteLength is too large");
+    return;
+  }
+
+  const uint8_t* data = &src_base[src_byte_offset];
+  GetProcs().bufferSetSubData(GetHandle(), dst_byte_offset, byte_length, data);
+}
+
+void GPUBuffer::OnMapAsyncCallback(ScriptPromiseResolver* resolver,
+                                   DawnBufferMapAsyncStatus status,
+                                   void* data,
+                                   uint64_t data_length) {
+  switch (status) {
+    case DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS:
+      DCHECK(data);
+      DCHECK_LE(data_length, kLargestMappableSize);
+      {
+        WTF::ArrayBufferContents::DataHandle handle(
+            data, static_cast<size_t>(data_length),
+            [](void* data, size_t length, void* info) {
+              // DataDeleter does nothing because Dawn wire owns the memory.
+            },
+            nullptr);
+
+        WTF::ArrayBufferContents contents(
+            std::move(handle),
+            WTF::ArrayBufferContents::SharingType::kNotShared);
+
+        mapped_buffer_ = DOMArrayBuffer::Create(contents);
+        resolver->Resolve(mapped_buffer_);
+      }
+      break;
+    case DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR:
+      resolver->Reject(DOMException::Create(DOMExceptionCode::kOperationError));
+      break;
+    case DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN:
+    case DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST:
+      resolver->Reject(DOMException::Create(DOMExceptionCode::kAbortError));
+      break;
+    default:
+      NOTREACHED();
+      resolver->Reject(DOMException::Create(DOMExceptionCode::kAbortError));
+      break;
+  }
+}
+
+ScriptPromise GPUBuffer::mapReadAsync(ScriptState* script_state,
+                                      ExceptionState& exception_state) {
+  ScriptPromiseResolver* resolver =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  if (!ValidateMapSize(size_, resolver, exception_state)) {
+    return promise;
+  }
+
+  auto* callback =
+      BindDawnCallback(&GPUBuffer::OnMapAsyncCallback, WrapPersistent(this),
+                       WrapPersistent(resolver));
+
+  using Callback = std::remove_reference_t<decltype(*callback)>;
+
+  GetProcs().bufferMapReadAsync(
+      GetHandle(),
+      [](DawnBufferMapAsyncStatus status, const void* data,
+         uint64_t data_length, DawnCallbackUserdata userdata) {
+        // It is safe to const_cast the |data| pointer because it is a shadow
+        // copy that Dawn wire makes and does not point to the mapped GPU data.
+        // Dawn wire's copy of the data is not used outside of tests.
+        return Callback::CallUnboundCallback(status, const_cast<void*>(data),
+                                             data_length, userdata);
+      },
+      callback->AsUserdata());
+  // WebGPU guarantees callbacks complete in finite time. Flush now so that
+  // commands reach the GPU process.
+  device_->GetInterface()->FlushCommands();
+
+  return promise;
+}
+
+ScriptPromise GPUBuffer::mapWriteAsync(ScriptState* script_state,
+                                       ExceptionState& exception_state) {
+  ScriptPromiseResolver* resolver =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  if (!ValidateMapSize(size_, resolver, exception_state)) {
+    return promise;
+  }
+
+  auto* callback =
+      BindDawnCallback(&GPUBuffer::OnMapAsyncCallback, WrapPersistent(this),
+                       WrapPersistent(resolver));
+
+  GetProcs().bufferMapWriteAsync(GetHandle(), callback->UnboundCallback(),
+                                 callback->AsUserdata());
+  // WebGPU guarantees callbacks complete in finite time. Flush now so that
+  // commands reach the GPU process.
+  device_->GetInterface()->FlushCommands();
+
+  return promise;
+}
+
+void GPUBuffer::unmap(ScriptState* script_state) {
+  DetachArrayBufferForCurrentMapping(script_state);
+  GetProcs().bufferUnmap(GetHandle());
+}
+
+void GPUBuffer::destroy(ScriptState* script_state) {
+  DetachArrayBufferForCurrentMapping(script_state);
+  GetProcs().bufferDestroy(GetHandle());
+}
+
+void GPUBuffer::DetachArrayBufferForCurrentMapping(ScriptState* script_state) {
+  if (!mapped_buffer_) {
+    return;
+  }
+  v8::Isolate* isolate = script_state->GetIsolate();
+  DOMArrayBuffer* mapped_buffer = mapped_buffer_.Release();
+  DCHECK(mapped_buffer->IsNeuterable(isolate));
+
+  // Detach the array buffer by transferring the contents out and dropping them.
+  WTF::ArrayBufferContents contents;
+  DCHECK(mapped_buffer->Transfer(isolate, contents));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.h b/third_party/blink/renderer/modules/webgpu/gpu_buffer.h
index 7fb653f4..15547fa 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.h
@@ -5,11 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_BUFFER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_BUFFER_H_
 
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 
 namespace blink {
 
+class DOMArrayBuffer;
 class GPUBufferDescriptor;
+class ScriptPromiseResolver;
 
 class GPUBuffer : public DawnObject<DawnBuffer> {
   DEFINE_WRAPPERTYPEINFO();
@@ -17,13 +22,35 @@
  public:
   static GPUBuffer* Create(GPUDevice* device,
                            const GPUBufferDescriptor* webgpu_desc);
-  explicit GPUBuffer(GPUDevice* device, DawnBuffer buffer);
+  explicit GPUBuffer(GPUDevice* device, uint64_t size, DawnBuffer buffer);
   ~GPUBuffer() override;
 
+  void Trace(blink::Visitor* visitor) override;
+
   // gpu_buffer.idl
+  void setSubData(uint64_t dst_byte_offset,
+                  const MaybeShared<DOMArrayBufferView>& src,
+                  uint64_t src_byte_offset,
+                  uint64_t byte_length,
+                  ExceptionState& exception_state);
+  ScriptPromise mapReadAsync(ScriptState* script_state,
+                             ExceptionState& exception_state);
+  ScriptPromise mapWriteAsync(ScriptState* script_state,
+                              ExceptionState& exception_state);
+  void unmap(ScriptState* script_state);
+  void destroy(ScriptState* script_state);
   // TODO(crbug.com/877147): implement GPUBuffer.
 
  private:
+  void OnMapAsyncCallback(ScriptPromiseResolver* resolver,
+                          DawnBufferMapAsyncStatus status,
+                          void* data,
+                          uint64_t data_length);
+  void DetachArrayBufferForCurrentMapping(ScriptState* script_state);
+
+  uint64_t size_;
+  Member<DOMArrayBuffer> mapped_buffer_;
+
   DISALLOW_COPY_AND_ASSIGN(GPUBuffer);
 };
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
index 715670d..9431e7a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
@@ -7,4 +7,13 @@
 [
     RuntimeEnabled=WebGPU
 ] interface GPUBuffer {
+    [RaisesException] void setSubData(
+        unsigned long long dstOffset,
+        [AllowShared] ArrayBufferView src,
+        optional unsigned long long srcOffset = 0,
+        optional unsigned long long byteLength = 0);
+    [CallWith=ScriptState, RaisesException] Promise<ArrayBuffer> mapReadAsync();
+    [CallWith=ScriptState, RaisesException] Promise<ArrayBuffer> mapWriteAsync();
+    [CallWith=ScriptState] void unmap();
+    [CallWith=ScriptState] void destroy();
 };
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index e93f44b..bde3370 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -32,6 +32,7 @@
             # //base constructs that are allowed everywhere
             'base::AdoptRef',
             'base::AutoReset',
+            'base::CreateSequencedTaskRunnerWithTraits',
             'base::ElapsedTimer',
             'base::File',
             'base::FilePath',
@@ -44,7 +45,6 @@
             'base::PlatformThreadId',
             'base::RefCountedData',
             'base::RunLoop',
-            'base::CreateSequencedTaskRunnerWithTraits',
             'base::ReadOnlySharedMemoryMapping',
             'base::ReadOnlySharedMemoryRegion',
             'base::SequencedTaskRunner',
@@ -57,6 +57,11 @@
             'base::TimeDelta',
             'base::TimeTicks',
             'base::ThreadTicks',
+            'base::trace_event::MemoryAllocatorDump',
+            'base::trace_event::MemoryDumpArgs',
+            'base::trace_event::MemoryDumpManager',
+            'base::trace_event::MemoryDumpProvider',
+            'base::trace_event::ProcessMemoryDump',
             'base::UnguessableToken',
             'base::UnguessableTokenHash',
             'base::UnsafeSharedMemoryRegion',
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 5268d2ac..8471582 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5668,6 +5668,9 @@
 crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
 crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html [ Failure ]
 crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
+crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html [ Failure ]
+crbug.com/869492 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html [ Failure ]
 
 crbug.com/914441 external/wpt/user-timing/mark-measure-feature-detection.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/animations/keyframe-rule-cssom-modify-deleted-crash.html b/third_party/blink/web_tests/animations/keyframe-rule-cssom-modify-deleted-crash.html
new file mode 100644
index 0000000..0e29120
--- /dev/null
+++ b/third_party/blink/web_tests/animations/keyframe-rule-cssom-modify-deleted-crash.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<style>
+  @keyframes anim {
+    50% { color: pink }
+  }
+</style>
+<script>
+  const anim = document.styleSheets[0].cssRules[0];
+  const fifty = anim.cssRules[0];
+
+  test(() => {
+    assert_equals(anim.cssRules.length, 1);
+    anim.deleteRule("50%");
+    assert_equals(anim.cssRules.length, 0);
+  }, "");
+
+  test(() => {
+    fifty.keyText = "10%";
+  }, "Setting keyText on a removed keyframe should not crash.");
+
+  test(() => {
+    fifty.style.color = "green";
+  }, "Setting style properties on a removed keyframe should not crash.");
+</script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 7f46d8f..9137c65 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -117460,6 +117460,16 @@
      {}
     ]
    ],
+   "FileAPI/idlharness-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "FileAPI/idlharness.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "FileAPI/reading-data-section/support/blue-100x100.png": [
     [
      {}
@@ -119180,11 +119190,6 @@
      {}
     ]
    ],
-   "animation-worklet/worklet-animation-duration-ref.html": [
-    [
-     {}
-    ]
-   ],
    "animation-worklet/worklet-animation-local-time-after-duration-ref.html": [
     [
      {}
@@ -159910,6 +159915,16 @@
      {}
     ]
    ],
+   "custom-elements/upgrading/Node-cloneNode-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "custom-elements/upgrading/upgrading-parser-created-element-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "device-memory/META.yml": [
     [
      {}
@@ -162940,6 +162955,11 @@
      {}
     ]
    ],
+   "feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html.headers": [
+    [
+     {}
+    ]
+   ],
    "feature-policy/experimental-features/resources/animation-property-height.js": [
     [
      {}
@@ -167600,6 +167620,11 @@
      {}
     ]
    ],
+   "html/dom/elements/global-attributes/dataset-binding.window-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/dom/elements/global-attributes/dir_auto-EN-L-ref.html": [
     [
      {}
@@ -238981,6 +239006,12 @@
      {}
     ]
    ],
+   "css/cssom/stylesheet-deleterule-error.html": [
+    [
+     "css/cssom/stylesheet-deleterule-error.html",
+     {}
+    ]
+   ],
    "css/cssom/stylesheet-same-origin.sub.html": [
     [
      "css/cssom/stylesheet-same-origin.sub.html",
@@ -243332,6 +243363,12 @@
      }
     ]
    ],
+   "element-timing/background-image-data-uri.html": [
+    [
+     "element-timing/background-image-data-uri.html",
+     {}
+    ]
+   ],
    "element-timing/background-image-multiple-elements.html": [
     [
      "element-timing/background-image-multiple-elements.html",
@@ -243380,6 +243417,12 @@
      {}
     ]
    ],
+   "element-timing/image-data-uri.html": [
+    [
+     "element-timing/image-data-uri.html",
+     {}
+    ]
+   ],
    "element-timing/image-not-fully-visible.html": [
     [
      "element-timing/image-not-fully-visible.html",
@@ -253463,6 +253506,12 @@
      {}
     ]
    ],
+   "feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html": [
+    [
+     "feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html",
+     {}
+    ]
+   ],
    "feature-policy/experimental-features/sync-script.tentative.https.sub.html": [
     [
      "feature-policy/experimental-features/sync-script.tentative.https.sub.html",
@@ -256998,6 +257047,18 @@
      {}
     ]
    ],
+   "fetch/sec-metadata/prefetch.tentative.https.sub.html": [
+    [
+     "fetch/sec-metadata/prefetch.tentative.https.sub.html",
+     {}
+    ]
+   ],
+   "fetch/sec-metadata/preload.tentative.https.sub.html": [
+    [
+     "fetch/sec-metadata/preload.tentative.https.sub.html",
+     {}
+    ]
+   ],
    "fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html": [
     [
      "fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html",
@@ -260049,6 +260110,12 @@
      {}
     ]
    ],
+   "html/dom/elements/global-attributes/dataset-binding.window.js": [
+    [
+     "html/dom/elements/global-attributes/dataset-binding.window.html",
+     {}
+    ]
+   ],
    "html/dom/elements/global-attributes/dataset-delete.html": [
     [
      "html/dom/elements/global-attributes/dataset-delete.html",
@@ -337330,10 +337397,18 @@
    "4f841f1763945946a4e2445a85a23b5d4326c386",
    "testharness"
   ],
+  "FileAPI/idlharness-expected.txt": [
+   "a60813743b1fda93d4c6c33bb2d8ddab31ee4911",
+   "support"
+  ],
   "FileAPI/idlharness.html": [
    "db6592e6220d02b608f504f8f2a654779c8b0241",
    "testharness"
   ],
+  "FileAPI/idlharness.worker-expected.txt": [
+   "0d1eaa90fb1610635f62b9cb7b83c83cf67134c7",
+   "support"
+  ],
   "FileAPI/idlharness.worker.js": [
    "5bf82e0b890327d0f389b5cbe95b39eacadb42dd",
    "testharness"
@@ -340714,12 +340789,8 @@
    "3e403feb4366457a800f38030481a7b12f9d24f2",
    "testharness"
   ],
-  "animation-worklet/worklet-animation-duration-ref.html": [
-   "81b01bdca813caccb4a3b5e635db21d4f9411a63",
-   "support"
-  ],
   "animation-worklet/worklet-animation-duration.https.html": [
-   "1526004eaf17d5e420e3989a91ba49bc61f4b704",
+   "1a8afc1e89278d06572e337965a6d1ff1572d0d9",
    "testharness"
   ],
   "animation-worklet/worklet-animation-local-time-after-duration-ref.html": [
@@ -342371,7 +342442,7 @@
    "support"
   ],
   "common/security-features/resources/common.js": [
-   "b18097b1ec2e252a59ec075d0f2c158798e38d08",
+   "936b39e50ed57fdf9293333658fe8966c130712b",
    "support"
   ],
   "common/security-features/subresource/__init__.py": [
@@ -417322,6 +417393,10 @@
    "e86a9a16e3bc9c0a22277996ad1fbb5f273d4bdd",
    "testharness"
   ],
+  "css/cssom/stylesheet-deleterule-error.html": [
+   "e01aa015c737d59e90923795fa730e9599e1ee6e",
+   "testharness"
+  ],
   "css/cssom/stylesheet-replacedata-dynamic-ref.html": [
    "bc9cadebf15d720e9c89b8072c0ef36eca962343",
    "support"
@@ -426274,16 +426349,24 @@
    "b80f90648d110a358bef090d3d9830077264cf70",
    "testharness"
   ],
+  "custom-elements/upgrading/Node-cloneNode-expected.txt": [
+   "6ad8ab1d12032ddad1f76c3f07959d429d9efd9a",
+   "support"
+  ],
   "custom-elements/upgrading/Node-cloneNode.html": [
-   "1a8786e914b9974ce114e9cda227823b3ea4a161",
+   "364cecd76debd8b9657392641267be5f0918e84d",
    "testharness"
   ],
   "custom-elements/upgrading/upgrading-enqueue-reactions.html": [
    "8238eee624afee25f19356b4de244713b5047038",
    "testharness"
   ],
+  "custom-elements/upgrading/upgrading-parser-created-element-expected.txt": [
+   "c520307dd7e3ce5be20fcb6fc6b0b7d8c90955d8",
+   "support"
+  ],
   "custom-elements/upgrading/upgrading-parser-created-element.html": [
-   "7cc3b18aeefb8db55bcac7ac1cf321c1b5fff28c",
+   "0f7f95786dd11fd7013f057fd492cc9b7c924db9",
    "testharness"
   ],
   "device-memory/META.yml": [
@@ -428934,6 +429017,10 @@
    "7cd0be939f16e8aea7b00ff2b13a06102e26cc4d",
    "testharness"
   ],
+  "element-timing/background-image-data-uri.html": [
+   "696f34ff14e8bad8ec68a8687cdbf0949ef6fdef",
+   "testharness"
+  ],
   "element-timing/background-image-multiple-elements.html": [
    "669f94d6b0189ba387cf90c1b49c7d4120319673",
    "testharness"
@@ -428966,6 +429053,10 @@
    "36cf1b15e0df0f99b8312ef56cde211f7c1358dd",
    "testharness"
   ],
+  "element-timing/image-data-uri.html": [
+   "22ff91189b1370b703f89f55d83cde014b6d367d",
+   "testharness"
+  ],
   "element-timing/image-not-fully-visible.html": [
    "279fa03cc2b42029ed01a68f670829c13b282a5c",
    "testharness"
@@ -429035,7 +429126,7 @@
    "support"
   ],
   "element-timing/resources/element-timing-helpers.js": [
-   "66605df824bb5b9687f6f3611c0041714b8e9c01",
+   "b0ddf308df2514bed7c14c3d83382afbc1ad0a21",
    "support"
   ],
   "element-timing/resources/iframe-with-square-sends-entry.html": [
@@ -431750,6 +431841,14 @@
    "a913158982e04d34a79c662673a9754d457bb002",
    "testharness"
   ],
+  "feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html": [
+   "2a6faefcd3bcab4efe6147fa142fc7369efafc81",
+   "testharness"
+  ],
+  "feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html.headers": [
+   "8cba4d2df9c22809641984a0071aae947b4f91ae",
+   "support"
+  ],
   "feature-policy/experimental-features/resources/animation-property-height.js": [
    "79316cb488fade6e877c690f90c74961ff944f52",
    "support"
@@ -434106,6 +434205,14 @@
    "b60ae206c78b3dd8e934dde7a7408fe4a7465932",
    "testharness"
   ],
+  "fetch/sec-metadata/prefetch.tentative.https.sub.html": [
+   "2c230b8949688940067d9bbc151b12f59e20b517",
+   "testharness"
+  ],
+  "fetch/sec-metadata/preload.tentative.https.sub.html": [
+   "2fdf65d5920d5851416679eee21fd9362ca3d532",
+   "testharness"
+  ],
   "fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html": [
    "06b58744fb5a26f16f5ed8fc923f1c91989e2eb8",
    "testharness"
@@ -434171,7 +434278,7 @@
    "support"
   ],
   "fetch/sec-metadata/resources/record-header.py": [
-   "f215b0165073ec6275308ed272cea763d9572a9e",
+   "683c0a6a0c4b6e32e06fce50aa8f6af19eacff76",
    "support"
   ],
   "fetch/sec-metadata/resources/sharedWorker.js": [
@@ -438766,6 +438873,14 @@
    "17077dafd1ff38298b052aa17fcc1e1062a83baf",
    "testharness"
   ],
+  "html/dom/elements/global-attributes/dataset-binding.window-expected.txt": [
+   "0f3419e7fc36e3093a7e183bf3d14f8e08c830ff",
+   "support"
+  ],
+  "html/dom/elements/global-attributes/dataset-binding.window.js": [
+   "e0e85677d1d4c07533a5d8eaa6dc1268305fa0c6",
+   "testharness"
+  ],
   "html/dom/elements/global-attributes/dataset-delete.html": [
    "1440118f6daa531d2bfde982c67676d22cffa197",
    "testharness"
@@ -456007,7 +456122,7 @@
    "support"
   ],
   "interfaces/FileAPI.idl": [
-   "15b2e5582fee1c7fee29e7d20bb82b0ca901af73",
+   "b5b40296429646cfbe13110153f2e281201ba669",
    "support"
   ],
   "interfaces/IndexedDB.idl": [
@@ -459407,7 +459522,7 @@
    "testharness"
   ],
   "mixed-content/generic/mixed-content-test-case.js": [
-   "e7b0baaaafa357bef3b3d90fa4c14ae669ccbd91",
+   "6837258c62294e6e2826bac733cbb2451f9edc12",
    "support"
   ],
   "mixed-content/generic/sanity-checker.js": [
@@ -471191,7 +471306,7 @@
    "support"
   ],
   "referrer-policy/generic/referrer-policy-test-case.js": [
-   "6d570f1dc0fdb4d2973a8b8534897859ea2ab843",
+   "8bdbd3961b9d3a851951f111f803c3f82b9f81ce",
    "support"
   ],
   "referrer-policy/generic/sandboxed-iframe-with-opaque-origin.html": [
@@ -471199,7 +471314,7 @@
    "testharness"
   ],
   "referrer-policy/generic/sanity-checker.js": [
-   "5c01c36f35821d7df2300670b200eb9e1d701307",
+   "e296ce93b965b788ea79f2f2b6cff45d5dce55f0",
    "support"
   ],
   "referrer-policy/generic/subresource-test/area-navigate.html": [
@@ -488923,7 +489038,7 @@
    "support"
   ],
   "tools/manifest/download.py": [
-   "e8f27e7ac100dad8d587a91d67e9a5f2ff0c3433",
+   "91ae664336e4c09ef165db25cf363e61fec3d603",
    "support"
   ],
   "tools/manifest/item.py": [
@@ -488935,7 +489050,7 @@
    "support"
   ],
   "tools/manifest/manifest.py": [
-   "bfe57c7823b26f778e81fb793a7cb9b0fdfd264a",
+   "8634b7089869fbbf9adb604909ebae09efdf36b3",
    "support"
   ],
   "tools/manifest/sourcefile.py": [
@@ -488943,15 +489058,15 @@
    "support"
   ],
   "tools/manifest/update.py": [
-   "321cfebe2a605c9a50267129ed574127ed023634",
+   "f1a70930bb3377d86164767b71d985bad42c0104",
    "support"
   ],
   "tools/manifest/utils.py": [
-   "a097ad5090e16aa1a43c8e43332f0761ecd6f240",
+   "c3456d96604cb31d83de3d0a31dd0e259893e22c",
    "support"
   ],
   "tools/manifest/vcs.py": [
-   "cfb0ff27c364a5a66f85c264bbb4978ae56d9b5b",
+   "b63df4d0a8ae750a3a1edc7ee6c9eaa5fcc3718b",
    "support"
   ],
   "tools/py27-flake8.ini": [
@@ -500967,11 +501082,11 @@
    "support"
   ],
   "webstorage/set.window-expected.txt": [
-   "892713e6f7d3146f3574d130b61b98ae18da9f6b",
+   "bcc6fbbd97ad456565a0cea6f7fad8ce3a9d0daa",
    "support"
   ],
   "webstorage/set.window.js": [
-   "479ad588910b907e6e9fe41d5080b744a22a54fe",
+   "228ce60296697a21520b8c635bd352ed1fbefb2c",
    "testharness"
   ],
   "webstorage/storage_builtins-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/idlharness-expected.txt b/third_party/blink/web_tests/external/wpt/FileAPI/idlharness-expected.txt
new file mode 100644
index 0000000..a608137
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/idlharness-expected.txt
@@ -0,0 +1,112 @@
+This is a testharness.js-based test.
+Found 108 tests; 99 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS idl_test setup
+PASS Partial interface URL: original interface defined
+PASS Partial interface URL: valid exposure set
+PASS Blob interface: existence and properties of interface object
+PASS Blob interface object length
+PASS Blob interface object name
+PASS Blob interface: existence and properties of interface prototype object
+PASS Blob interface: existence and properties of interface prototype object's "constructor" property
+PASS Blob interface: existence and properties of interface prototype object's @@unscopables property
+PASS Blob interface: attribute size
+PASS Blob interface: attribute type
+PASS Blob interface: operation slice(long long, long long, DOMString)
+FAIL Blob interface: operation stream() assert_own_property: interface prototype object missing non-static operation expected property "stream" missing
+FAIL Blob interface: operation text() assert_own_property: interface prototype object missing non-static operation expected property "text" missing
+FAIL Blob interface: operation arrayBuffer() assert_own_property: interface prototype object missing non-static operation expected property "arrayBuffer" missing
+PASS Blob must be primary interface of new Blob(["TEST"])
+PASS Stringification of new Blob(["TEST"])
+PASS Blob interface: new Blob(["TEST"]) must inherit property "size" with the proper type
+PASS Blob interface: new Blob(["TEST"]) must inherit property "type" with the proper type
+PASS Blob interface: new Blob(["TEST"]) must inherit property "slice(long long, long long, DOMString)" with the proper type
+PASS Blob interface: calling slice(long long, long long, DOMString) on new Blob(["TEST"]) with too few arguments must throw TypeError
+FAIL Blob interface: new Blob(["TEST"]) must inherit property "stream()" with the proper type assert_inherits: property "stream" not found in prototype chain
+FAIL Blob interface: new Blob(["TEST"]) must inherit property "text()" with the proper type assert_inherits: property "text" not found in prototype chain
+FAIL Blob interface: new Blob(["TEST"]) must inherit property "arrayBuffer()" with the proper type assert_inherits: property "arrayBuffer" not found in prototype chain
+PASS File interface: existence and properties of interface object
+PASS File interface object length
+PASS File interface object name
+PASS File interface: existence and properties of interface prototype object
+PASS File interface: existence and properties of interface prototype object's "constructor" property
+PASS File interface: existence and properties of interface prototype object's @@unscopables property
+PASS File interface: attribute name
+PASS File interface: attribute lastModified
+PASS File must be primary interface of new File(["myFileBits"], "myFileName")
+PASS Stringification of new File(["myFileBits"], "myFileName")
+PASS File interface: new File(["myFileBits"], "myFileName") must inherit property "name" with the proper type
+PASS File interface: new File(["myFileBits"], "myFileName") must inherit property "lastModified" with the proper type
+PASS Blob interface: new File(["myFileBits"], "myFileName") must inherit property "size" with the proper type
+PASS Blob interface: new File(["myFileBits"], "myFileName") must inherit property "type" with the proper type
+PASS Blob interface: new File(["myFileBits"], "myFileName") must inherit property "slice(long long, long long, DOMString)" with the proper type
+PASS Blob interface: calling slice(long long, long long, DOMString) on new File(["myFileBits"], "myFileName") with too few arguments must throw TypeError
+FAIL Blob interface: new File(["myFileBits"], "myFileName") must inherit property "stream()" with the proper type assert_inherits: property "stream" not found in prototype chain
+FAIL Blob interface: new File(["myFileBits"], "myFileName") must inherit property "text()" with the proper type assert_inherits: property "text" not found in prototype chain
+FAIL Blob interface: new File(["myFileBits"], "myFileName") must inherit property "arrayBuffer()" with the proper type assert_inherits: property "arrayBuffer" not found in prototype chain
+PASS FileList interface: existence and properties of interface object
+PASS FileList interface object length
+PASS FileList interface object name
+PASS FileList interface: existence and properties of interface prototype object
+PASS FileList interface: existence and properties of interface prototype object's "constructor" property
+PASS FileList interface: existence and properties of interface prototype object's @@unscopables property
+PASS FileList interface: operation item(unsigned long)
+PASS FileList interface: attribute length
+PASS FileList must be primary interface of document.querySelector("#fileChooser").files
+PASS Stringification of document.querySelector("#fileChooser").files
+PASS FileList interface: document.querySelector("#fileChooser").files must inherit property "item(unsigned long)" with the proper type
+PASS FileList interface: calling item(unsigned long) on document.querySelector("#fileChooser").files with too few arguments must throw TypeError
+PASS FileList interface: document.querySelector("#fileChooser").files must inherit property "length" with the proper type
+PASS FileReader interface: existence and properties of interface object
+PASS FileReader interface object length
+PASS FileReader interface object name
+PASS FileReader interface: existence and properties of interface prototype object
+PASS FileReader interface: existence and properties of interface prototype object's "constructor" property
+PASS FileReader interface: existence and properties of interface prototype object's @@unscopables property
+PASS FileReader interface: operation readAsArrayBuffer(Blob)
+PASS FileReader interface: operation readAsBinaryString(Blob)
+PASS FileReader interface: operation readAsText(Blob, DOMString)
+PASS FileReader interface: operation readAsDataURL(Blob)
+PASS FileReader interface: operation abort()
+PASS FileReader interface: constant EMPTY on interface object
+PASS FileReader interface: constant EMPTY on interface prototype object
+PASS FileReader interface: constant LOADING on interface object
+PASS FileReader interface: constant LOADING on interface prototype object
+PASS FileReader interface: constant DONE on interface object
+PASS FileReader interface: constant DONE on interface prototype object
+PASS FileReader interface: attribute readyState
+PASS FileReader interface: attribute result
+PASS FileReader interface: attribute error
+PASS FileReader interface: attribute onloadstart
+PASS FileReader interface: attribute onprogress
+PASS FileReader interface: attribute onload
+PASS FileReader interface: attribute onabort
+PASS FileReader interface: attribute onerror
+PASS FileReader interface: attribute onloadend
+PASS FileReader must be primary interface of new FileReader()
+PASS Stringification of new FileReader()
+PASS FileReader interface: new FileReader() must inherit property "readAsArrayBuffer(Blob)" with the proper type
+PASS FileReader interface: calling readAsArrayBuffer(Blob) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "readAsBinaryString(Blob)" with the proper type
+PASS FileReader interface: calling readAsBinaryString(Blob) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "readAsText(Blob, DOMString)" with the proper type
+PASS FileReader interface: calling readAsText(Blob, DOMString) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "readAsDataURL(Blob)" with the proper type
+PASS FileReader interface: calling readAsDataURL(Blob) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "abort()" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "EMPTY" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "LOADING" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "DONE" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "readyState" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "result" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "error" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onloadstart" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onprogress" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onload" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onabort" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onerror" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onloadend" with the proper type
+PASS FileReaderSync interface: existence and properties of interface object
+PASS URL interface: operation createObjectURL([object Object],[object Object])
+PASS URL interface: operation revokeObjectURL(DOMString)
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/idlharness.worker-expected.txt b/third_party/blink/web_tests/external/wpt/FileAPI/idlharness.worker-expected.txt
new file mode 100644
index 0000000..0d1eaa9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/idlharness.worker-expected.txt
@@ -0,0 +1,126 @@
+This is a testharness.js-based test.
+Found 122 tests; 113 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS idl_test setup
+PASS Partial interface URL: original interface defined
+PASS Partial interface URL: valid exposure set
+PASS Blob interface: existence and properties of interface object
+PASS Blob interface object length
+PASS Blob interface object name
+PASS Blob interface: existence and properties of interface prototype object
+PASS Blob interface: existence and properties of interface prototype object's "constructor" property
+PASS Blob interface: existence and properties of interface prototype object's @@unscopables property
+PASS Blob interface: attribute size
+PASS Blob interface: attribute type
+PASS Blob interface: operation slice(long long, long long, DOMString)
+FAIL Blob interface: operation stream() assert_own_property: interface prototype object missing non-static operation expected property "stream" missing
+FAIL Blob interface: operation text() assert_own_property: interface prototype object missing non-static operation expected property "text" missing
+FAIL Blob interface: operation arrayBuffer() assert_own_property: interface prototype object missing non-static operation expected property "arrayBuffer" missing
+PASS Blob must be primary interface of new Blob(["TEST"])
+PASS Stringification of new Blob(["TEST"])
+PASS Blob interface: new Blob(["TEST"]) must inherit property "size" with the proper type
+PASS Blob interface: new Blob(["TEST"]) must inherit property "type" with the proper type
+PASS Blob interface: new Blob(["TEST"]) must inherit property "slice(long long, long long, DOMString)" with the proper type
+PASS Blob interface: calling slice(long long, long long, DOMString) on new Blob(["TEST"]) with too few arguments must throw TypeError
+FAIL Blob interface: new Blob(["TEST"]) must inherit property "stream()" with the proper type assert_inherits: property "stream" not found in prototype chain
+FAIL Blob interface: new Blob(["TEST"]) must inherit property "text()" with the proper type assert_inherits: property "text" not found in prototype chain
+FAIL Blob interface: new Blob(["TEST"]) must inherit property "arrayBuffer()" with the proper type assert_inherits: property "arrayBuffer" not found in prototype chain
+PASS File interface: existence and properties of interface object
+PASS File interface object length
+PASS File interface object name
+PASS File interface: existence and properties of interface prototype object
+PASS File interface: existence and properties of interface prototype object's "constructor" property
+PASS File interface: existence and properties of interface prototype object's @@unscopables property
+PASS File interface: attribute name
+PASS File interface: attribute lastModified
+PASS File must be primary interface of new File(["myFileBits"], "myFileName")
+PASS Stringification of new File(["myFileBits"], "myFileName")
+PASS File interface: new File(["myFileBits"], "myFileName") must inherit property "name" with the proper type
+PASS File interface: new File(["myFileBits"], "myFileName") must inherit property "lastModified" with the proper type
+PASS Blob interface: new File(["myFileBits"], "myFileName") must inherit property "size" with the proper type
+PASS Blob interface: new File(["myFileBits"], "myFileName") must inherit property "type" with the proper type
+PASS Blob interface: new File(["myFileBits"], "myFileName") must inherit property "slice(long long, long long, DOMString)" with the proper type
+PASS Blob interface: calling slice(long long, long long, DOMString) on new File(["myFileBits"], "myFileName") with too few arguments must throw TypeError
+FAIL Blob interface: new File(["myFileBits"], "myFileName") must inherit property "stream()" with the proper type assert_inherits: property "stream" not found in prototype chain
+FAIL Blob interface: new File(["myFileBits"], "myFileName") must inherit property "text()" with the proper type assert_inherits: property "text" not found in prototype chain
+FAIL Blob interface: new File(["myFileBits"], "myFileName") must inherit property "arrayBuffer()" with the proper type assert_inherits: property "arrayBuffer" not found in prototype chain
+PASS FileList interface: existence and properties of interface object
+PASS FileList interface object length
+PASS FileList interface object name
+PASS FileList interface: existence and properties of interface prototype object
+PASS FileList interface: existence and properties of interface prototype object's "constructor" property
+PASS FileList interface: existence and properties of interface prototype object's @@unscopables property
+PASS FileList interface: operation item(unsigned long)
+PASS FileList interface: attribute length
+PASS FileReader interface: existence and properties of interface object
+PASS FileReader interface object length
+PASS FileReader interface object name
+PASS FileReader interface: existence and properties of interface prototype object
+PASS FileReader interface: existence and properties of interface prototype object's "constructor" property
+PASS FileReader interface: existence and properties of interface prototype object's @@unscopables property
+PASS FileReader interface: operation readAsArrayBuffer(Blob)
+PASS FileReader interface: operation readAsBinaryString(Blob)
+PASS FileReader interface: operation readAsText(Blob, DOMString)
+PASS FileReader interface: operation readAsDataURL(Blob)
+PASS FileReader interface: operation abort()
+PASS FileReader interface: constant EMPTY on interface object
+PASS FileReader interface: constant EMPTY on interface prototype object
+PASS FileReader interface: constant LOADING on interface object
+PASS FileReader interface: constant LOADING on interface prototype object
+PASS FileReader interface: constant DONE on interface object
+PASS FileReader interface: constant DONE on interface prototype object
+PASS FileReader interface: attribute readyState
+PASS FileReader interface: attribute result
+PASS FileReader interface: attribute error
+PASS FileReader interface: attribute onloadstart
+PASS FileReader interface: attribute onprogress
+PASS FileReader interface: attribute onload
+PASS FileReader interface: attribute onabort
+PASS FileReader interface: attribute onerror
+PASS FileReader interface: attribute onloadend
+PASS FileReader must be primary interface of new FileReader()
+PASS Stringification of new FileReader()
+PASS FileReader interface: new FileReader() must inherit property "readAsArrayBuffer(Blob)" with the proper type
+PASS FileReader interface: calling readAsArrayBuffer(Blob) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "readAsBinaryString(Blob)" with the proper type
+PASS FileReader interface: calling readAsBinaryString(Blob) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "readAsText(Blob, DOMString)" with the proper type
+PASS FileReader interface: calling readAsText(Blob, DOMString) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "readAsDataURL(Blob)" with the proper type
+PASS FileReader interface: calling readAsDataURL(Blob) on new FileReader() with too few arguments must throw TypeError
+PASS FileReader interface: new FileReader() must inherit property "abort()" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "EMPTY" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "LOADING" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "DONE" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "readyState" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "result" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "error" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onloadstart" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onprogress" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onload" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onabort" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onerror" with the proper type
+PASS FileReader interface: new FileReader() must inherit property "onloadend" with the proper type
+PASS FileReaderSync interface: existence and properties of interface object
+PASS FileReaderSync interface object length
+PASS FileReaderSync interface object name
+PASS FileReaderSync interface: existence and properties of interface prototype object
+PASS FileReaderSync interface: existence and properties of interface prototype object's "constructor" property
+PASS FileReaderSync interface: existence and properties of interface prototype object's @@unscopables property
+PASS FileReaderSync interface: operation readAsArrayBuffer(Blob)
+PASS FileReaderSync interface: operation readAsBinaryString(Blob)
+PASS FileReaderSync interface: operation readAsText(Blob, DOMString)
+PASS FileReaderSync interface: operation readAsDataURL(Blob)
+PASS FileReaderSync must be primary interface of new FileReaderSync()
+PASS Stringification of new FileReaderSync()
+PASS FileReaderSync interface: new FileReaderSync() must inherit property "readAsArrayBuffer(Blob)" with the proper type
+PASS FileReaderSync interface: calling readAsArrayBuffer(Blob) on new FileReaderSync() with too few arguments must throw TypeError
+PASS FileReaderSync interface: new FileReaderSync() must inherit property "readAsBinaryString(Blob)" with the proper type
+PASS FileReaderSync interface: calling readAsBinaryString(Blob) on new FileReaderSync() with too few arguments must throw TypeError
+PASS FileReaderSync interface: new FileReaderSync() must inherit property "readAsText(Blob, DOMString)" with the proper type
+PASS FileReaderSync interface: calling readAsText(Blob, DOMString) on new FileReaderSync() with too few arguments must throw TypeError
+PASS FileReaderSync interface: new FileReaderSync() must inherit property "readAsDataURL(Blob)" with the proper type
+PASS FileReaderSync interface: calling readAsDataURL(Blob) on new FileReaderSync() with too few arguments must throw TypeError
+PASS URL interface: operation createObjectURL([object Object],[object Object])
+PASS URL interface: operation revokeObjectURL(DOMString)
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-deleterule-error.html b/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-deleterule-error.html
deleted file mode 100644
index e01aa01..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-deleterule-error.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>CSSStyleSheet.prototype.deleteRule error message</title>
-<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
-<link rel="help" href="https://heycam.github.io/webidl/#indexsizeerror">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
-test(function () {
-    const styleEl = document.createElement('style');
-    document.head.appendChild(styleEl);
-    try {
-        styleEl.sheet.deleteRule(0);
-        assert_fail("deleteRule on an empty style sheet should throw a RangeError");
-    } catch (e) {
-        assert_equals(e.name,"RangeError");
-        assert_true(e instanceof RangeError);
-    }
-}, 'deleteRule should throw RangeError');
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode-expected.txt b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode-expected.txt
new file mode 100644
index 0000000..6ad8ab1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+PASS Node.prototype.cloneNode(false) must be able to clone a custom element
+PASS Node.prototype.cloneNode(false) must be able to clone as a autonomous custom element when it contains is attribute
+PASS Node.prototype.cloneNode(false) must be able to clone as a customized built-in element when it has an inconsistent "is" attribute
+PASS Node.prototype.cloneNode(false) must be able to clone a custom element inside an iframe
+PASS Node.prototype.cloneNode(true) must be able to clone a descendent custom element
+PASS Node.prototype.cloneNode(true) must set parentNode, previousSibling, and nextSibling before upgrading custom elements
+FAIL HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed due to a custom element constructor constructing itself after super() call assert_equals: expected "TypeError" but got "InvalidStateError"
+FAIL HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed due to a custom element constructor constructing itself before super() call assert_equals: expected "TypeError" but got "InvalidStateError"
+FAIL Upgrading a custom element must throw TypeError when the custom element's constructor returns another element assert_equals: expected "TypeError" but got "InvalidStateError"
+PASS Inserting an element must not try to upgrade a custom element when it had already failed to upgrade once
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode.html b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode.html
index 1a8786e..364cecd 100644
--- a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode.html
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/Node-cloneNode.html
@@ -165,8 +165,8 @@
     var uncaughtError;
     window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
     instance.cloneNode(false);
-    assert_equals(uncaughtError.name, 'InvalidStateError');
-}, 'HTMLElement constructor must throw an InvalidStateError when the top of the construction stack is marked AlreadyConstructed'
+    assert_equals(uncaughtError.name, 'TypeError');
+}, 'HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed'
     + ' due to a custom element constructor constructing itself after super() call');
 
 test(function () {
@@ -183,8 +183,8 @@
     var uncaughtError;
     window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
     instance.cloneNode(false);
-    assert_equals(uncaughtError.name, 'InvalidStateError');
-}, 'HTMLElement constructor must throw an InvalidStateError when the top of the construction stack is marked AlreadyConstructed'
+    assert_equals(uncaughtError.name, 'TypeError');
+}, 'HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed'
     + ' due to a custom element constructor constructing itself before super() call');
 
 test(function () {
@@ -203,8 +203,8 @@
     var uncaughtError;
     window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
     instance.cloneNode(false);
-    assert_equals(uncaughtError.name, 'InvalidStateError');
-}, 'Upgrading a custom element must throw InvalidStateError when the custom element\'s constructor returns another element');
+    assert_equals(uncaughtError.name, 'TypeError');
+}, 'Upgrading a custom element must throw TypeError when the custom element\'s constructor returns another element');
 
 test(function () {
     var instance = document.createElement('my-custom-element-throw-exception');
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element-expected.txt b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element-expected.txt
new file mode 100644
index 0000000..c520307
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Element.prototype.createElement must add an unresolved custom element to the upgrade candidates map
+FAIL HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed due to a custom element constructor constructing itself after super() call assert_equals: expected "TypeError" but got "InvalidStateError"
+FAIL HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed due to a custom element constructor constructing itself before super() call assert_equals: expected "TypeError" but got "InvalidStateError"
+FAIL Upgrading a custom element must throw an TypeError when the returned element is not SameValue as the upgraded element assert_equals: expected "TypeError" but got "InvalidStateError"
+FAIL Upgrading a custom element whose constructor returns a Text node must throw assert_equals: expected "TypeError" but got "InvalidStateError"
+FAIL Upgrading a custom element whose constructor returns an Element must throw assert_equals: expected "TypeError" but got "InvalidStateError"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element.html b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element.html
index 7cc3b18..0f7f957 100644
--- a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element.html
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading/upgrading-parser-created-element.html
@@ -15,6 +15,8 @@
 <instantiates-itself-before-super></instantiates-itself-before-super>
 <my-other-element id="instance"></my-other-element>
 <my-other-element id="otherInstance"></my-other-element>
+<not-an-element></not-an-element>
+<not-an-html-element></not-an-html-element>
 <script>
 
 setup({allow_uncaught_exception:true});
@@ -48,8 +50,8 @@
     var uncaughtError;
     window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
     customElements.define('instantiates-itself-after-super', InstantiatesItselfAfterSuper);
-    assert_equals(uncaughtError.name, 'InvalidStateError');
-}, 'HTMLElement constructor must throw an InvalidStateError when the top of the construction stack is marked AlreadyConstructed'
+    assert_equals(uncaughtError.name, 'TypeError');
+}, 'HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed'
     + ' due to a custom element constructor constructing itself after super() call');
 
 test(function () {
@@ -64,8 +66,8 @@
     var uncaughtError;
     window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
     customElements.define('instantiates-itself-before-super', InstantiatesItselfBeforeSuper);
-    assert_equals(uncaughtError.name, 'InvalidStateError');
-}, 'HTMLElement constructor must throw an InvalidStateError when the top of the construction stack is marked AlreadyConstructed'
+    assert_equals(uncaughtError.name, 'TypeError');
+}, 'HTMLElement constructor must throw an TypeError when the top of the construction stack is marked AlreadyConstructed'
     + ' due to a custom element constructor constructing itself before super() call');
 
 test(function () {
@@ -85,12 +87,38 @@
     var uncaughtError;
     window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
     customElements.define('my-other-element', MyOtherElement);
-    assert_equals(uncaughtError.name, 'InvalidStateError');
+    assert_equals(uncaughtError.name, 'TypeError');
 
     assert_true(document.createElement('my-other-element') instanceof MyOtherElement,
         'Upgrading of custom elements must happen after the definition was added to the registry.');
 
-}, 'Upgrading a custom element must throw an InvalidStateError when the returned element is not SameValue as the upgraded element');
+}, 'Upgrading a custom element must throw an TypeError when the returned element is not SameValue as the upgraded element');
+
+test(() => {
+  class NotAnElement extends HTMLElement {
+    constructor() {
+      return new Text();
+    }
+  }
+
+  let uncaughtError;
+  window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
+  customElements.define("not-an-element", NotAnElement);
+  assert_equals(uncaughtError.name, "TypeError");
+}, "Upgrading a custom element whose constructor returns a Text node must throw");
+
+test(() => {
+  class NotAnHTMLElement extends HTMLElement {
+    constructor() {
+      return document.createElementNS("", "test");
+    }
+  }
+
+  let uncaughtError;
+  window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; }
+  customElements.define("not-an-html-element", NotAnHTMLElement);
+  assert_equals(uncaughtError.name, "TypeError");
+}, "Upgrading a custom element whose constructor returns an Element must throw");
 
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html
new file mode 100644
index 0000000..2a6faef
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/feature-policy/experimental-features/resources/common.js"></script>
+<style>
+html, body {
+  height: 100%;
+  width: 100%;
+}
+
+iframe {
+  width: 400px;
+  height: 400px;
+  margin: 10px;
+}
+
+.spacer {
+  width: 100%;
+  height: 10000px;
+}
+</style>
+<div class="spacer"></div>
+<script>
+  let load_timeout = 600; // ms
+  let expected_timeout_msg = false;
+
+  let cross_origin_url =
+      "http://{{hosts[alt][www]}}:{{ports[http][0]}}/" +
+      "feature-policy/experimental-features/resources/lazyload-contents.html";
+
+  window.scrollTo(0, 0);
+
+  // Verify that when 'loading-frame-default-eager' policy is disabled, the
+  // loading attribute "auto" leads to lazy loading.
+  promise_test(async(t) => {
+    // Add a frame with load="off".
+    let frame_loading_auto = createIframe(document.body, {
+        id: "auto",
+        // Sets the "loading" attribute to "auto".
+        loading: "auto",
+        src: `${cross_origin_url}?id=auto`
+      });
+    // Sanity-check: The frame is not visible.
+    assert_greater_than(
+        frame_loading_auto.getBoundingClientRect().top,
+        window.innerHeight * 2,
+        "Unexpected position for <iframe> with ID 'auto'.");
+    let msg_or_timeout =
+        await waitForMessageOrTimeout(t, "auto", load_timeout);
+    assert_false(msg_or_timeout, "Expected the frame not to load.");
+  }, "When 'loading-frame-default-eager' feature is disabled, a frame with " +
+     "'loading attribute 'auto' will be lazily loaded.");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html.headers b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html.headers
new file mode 100644
index 0000000..8cba4d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: loading-frame-default-eager 'none'
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dataset-binding.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dataset-binding.window-expected.txt
new file mode 100644
index 0000000..0f3419e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dataset-binding.window-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL Getting property descriptor for key 9 assert_equals: expected "value for Getting property descriptor for key 9" but got "9"
+PASS Setting property for key 9 with accessor property on prototype
+PASS Getting property descriptor for key x
+PASS Setting property for key x with accessor property on prototype
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dataset-binding.window.js b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dataset-binding.window.js
new file mode 100644
index 0000000..e0e85677
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dataset-binding.window.js
@@ -0,0 +1,45 @@
+[9, "x"].forEach(function(key) {
+  test(function() {
+    var element = document.createElement("div");
+    var dataset = element.dataset;
+
+    var value = "value for " + this.name;
+
+    assert_equals(dataset[key], undefined);
+
+    element.setAttribute("data-" + key, value);
+    assert_equals(element.getAttribute("data-" + key), value);
+    assert_equals(dataset[key], value);
+
+    var propdesc = Object.getOwnPropertyDescriptor(dataset, key);
+    assert_not_equals(propdesc, undefined);
+    assert_equals(propdesc.value, value);
+    assert_true(propdesc.writable);
+    assert_true(propdesc.enumerable);
+    assert_true(propdesc.configurable);
+  }, "Getting property descriptor for key " + key);
+
+  test(function() {
+    var element = document.createElement("div");
+    var dataset = element.dataset;
+
+    var proto = "proto getter for " + this.name;
+    var calledSetter = [];
+    Object.defineProperty(DOMStringMap.prototype, key, {
+      "get": function() { return proto; },
+      "set": this.unreached_func("Should not call [[Set]] on prototype"),
+      "configurable": true,
+    });
+    this.add_cleanup(function() {
+      delete DOMStringMap.prototype[key];
+    });
+
+    var value = "value for " + this.name;
+
+    assert_equals(dataset[key], proto);
+    assert_equals(element.getAttribute("data-" + key), null);
+    assert_equals(dataset[key] = value, value);
+    assert_equals(dataset[key], value);
+    assert_equals(element.getAttribute("data-" + key), value);
+  }, "Setting property for key " + key + " with accessor property on prototype");
+});
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/FileAPI.idl b/third_party/blink/web_tests/external/wpt/interfaces/FileAPI.idl
index 15b2e55..b5b4029 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/FileAPI.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/FileAPI.idl
@@ -15,6 +15,11 @@
   Blob slice(optional [Clamp] long long start,
             optional [Clamp] long long end,
             optional DOMString contentType);
+
+  // read from the Blob.
+  [NewObject] ReadableStream stream();
+  [NewObject] Promise<USVString> text();
+  [NewObject] Promise<ArrayBuffer> arrayBuffer();
 };
 
 enum EndingType { "transparent", "native" };
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/download.py b/third_party/blink/web_tests/external/wpt/tools/manifest/download.py
index e8f27e7..91ae664 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/download.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/download.py
@@ -15,7 +15,7 @@
 except ImportError:
     zstandard = None
 
-from .vcs import Git
+from .utils import git
 
 from . import log
 
@@ -40,9 +40,9 @@
 
 
 def merge_pr_tags(repo_root, max_count=50):
-    git = Git.get_func(repo_root)
+    gitfunc = git(repo_root)
     tags = []
-    for line in git("log", "--format=%D", "--max-count=%s" % max_count).split("\n"):
+    for line in gitfunc("log", "--format=%D", "--max-count=%s" % max_count).split("\n"):
         for ref in line.split(", "):
             if ref.startswith("tag: merge_pr_"):
                 tags.append(ref[5:])
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
index bfe57c782..8634b708 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
@@ -470,7 +470,7 @@
                     rebuild=False,
                     metadata_path=None,
                     cache_root=None,
-                    working_copy=False,
+                    working_copy=True,
                     types=None,
                     meta_filters=None,
                     write_manifest=True,
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/update.py b/third_party/blink/web_tests/external/wpt/tools/manifest/update.py
index 321cfeb..f1a7093 100755
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/update.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/update.py
@@ -17,7 +17,7 @@
 def update(tests_root,
            manifest,
            manifest_path=None,
-           working_copy=False,
+           working_copy=True,
            cache_root=None,
            rebuild=False):
     logger.warning("Deprecated; use manifest.load_and_update instead")
@@ -41,8 +41,7 @@
                              kwargs["url_base"],
                              update=True,
                              rebuild=kwargs["rebuild"],
-                             cache_root=kwargs["cache_root"],
-                             working_copy=kwargs["work"])
+                             cache_root=kwargs["cache_root"])
 
 
 def abs_path(path):
@@ -59,9 +58,6 @@
         "-r", "--rebuild", action="store_true", default=False,
         help="Force a full rebuild of the manifest.")
     parser.add_argument(
-        "--work", action="store_true", default=False,
-        help="Build from the working tree rather than the latest commit")
-    parser.add_argument(
         "--url-base", action="store", default="/",
         help="Base url to use as the mount point for tests in this manifest.")
     parser.add_argument(
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/utils.py b/third_party/blink/web_tests/external/wpt/tools/manifest/utils.py
index a097ad5..c3456d9 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/utils.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/utils.py
@@ -1,5 +1,6 @@
-import platform
 import os
+import platform
+import subprocess
 
 from six import BytesIO
 
@@ -32,6 +33,27 @@
     return path.replace("/", os.path.sep)
 
 
+def git(path):
+    def gitfunc(cmd, *args):
+        full_cmd = ["git", cmd] + list(args)
+        try:
+            return subprocess.check_output(full_cmd, cwd=path, stderr=subprocess.STDOUT)
+        except Exception as e:
+            if platform.uname()[0] == "Windows" and isinstance(e, WindowsError):
+                full_cmd[0] = "git.bat"
+                return subprocess.check_output(full_cmd, cwd=path, stderr=subprocess.STDOUT)
+            else:
+                raise
+
+    try:
+        # this needs to be a command that fails if we aren't in a git repo
+        gitfunc("rev-parse", "--show-toplevel")
+    except (subprocess.CalledProcessError, OSError):
+        return None
+    else:
+        return gitfunc
+
+
 class ContextManagerBytesIO(BytesIO):
     def __enter__(self):
         return self
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py b/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py
index cfb0ff2..b63df4d 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py
@@ -1,13 +1,10 @@
 import json
 import os
-import platform
 import stat
-import subprocess
 from collections import deque
 
-from six import iteritems
-
 from .sourcefile import SourceFile
+from .utils import git
 
 MYPY = False
 if MYPY:
@@ -16,7 +13,7 @@
 
 
 def get_tree(tests_root, manifest, manifest_path, cache_root,
-             working_copy=False, rebuild=False):
+             working_copy=True, rebuild=False):
     tree = None
     if cache_root is None:
         cache_root = os.path.join(tests_root, ".wptcache")
@@ -27,11 +24,8 @@
             cache_root = None
 
     if not working_copy:
-        tree = Git.for_path(tests_root,
-                            manifest.url_base,
-                            manifest_path=manifest_path,
-                            cache_path=cache_root,
-                            rebuild=rebuild)
+        raise ValueError("working_copy=False unsupported")
+
     if tree is None:
         tree = FileSystem(tests_root,
                           manifest.url_base,
@@ -41,39 +35,9 @@
     return tree
 
 
-class Git(object):
-    def __init__(self, repo_root, url_base, cache_path, manifest_path=None,
-                 rebuild=False):
-        self.root = repo_root
-        self.git = Git.get_func(repo_root)
-        self.url_base = url_base
-        # rebuild is a noop for now since we don't cache anything
-
-    @staticmethod
-    def get_func(repo_path):
-        def git(cmd, *args):
-            full_cmd = ["git", cmd] + list(args)
-            try:
-                return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT)
-            except Exception as e:
-                if platform.uname()[0] == "Windows" and isinstance(e, WindowsError):
-                    full_cmd[0] = "git.bat"
-                    return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT)
-                else:
-                    raise
-        return git
-
-    @classmethod
-    def for_path(cls, path, url_base, cache_path, manifest_path=None, rebuild=False):
-        git = Git.get_func(path)
-        try:
-            # this needs to be a command that fails if we aren't in a git repo
-            git("rev-parse", "--show-toplevel")
-        except (subprocess.CalledProcessError, OSError):
-            return None
-        else:
-            return cls(path, url_base, cache_path,
-                       manifest_path=manifest_path, rebuild=rebuild)
+class GitHasher(object):
+    def __init__(self, path):
+        self.git = git(path)
 
     def _local_changes(self):
         """get a set of files which have changed between HEAD and working copy"""
@@ -95,10 +59,6 @@
 
         return changes
 
-    def _show_file(self, path):
-        path = os.path.relpath(os.path.abspath(path), self.root)
-        return self.git("show", "HEAD:%s" % path)
-
     def hash_cache(self):
         # type: () -> Dict[str, Optional[str]]
         """
@@ -114,20 +74,6 @@
 
         return hash_cache
 
-    def __iter__(self):
-        for rel_path, hash in iteritems(self.hash_cache()):
-            if hash is None:
-                contents = self._show_file(rel_path)
-            else:
-                contents = None
-            yield SourceFile(self.root,
-                             rel_path,
-                             self.url_base,
-                             hash,
-                             contents=contents), True
-
-    def dump_caches(self):
-        pass
 
 
 class FileSystem(object):
@@ -145,7 +91,7 @@
         self.path_filter = gitignore.PathFilter(self.root,
                                                 extras=[".git/"],
                                                 cache=self.ignore_cache)
-        git = Git.for_path(root, url_base, cache_path)
+        git = GitHasher(root)
         if git is not None:
             self.hash_cache = git.hash_cache()
         else:
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/set.window-expected.txt b/third_party/blink/web_tests/external/wpt/webstorage/set.window-expected.txt
index 892713e6..bcc6fbbd 100644
--- a/third_party/blink/web_tests/external/wpt/webstorage/set.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webstorage/set.window-expected.txt
@@ -1,23 +1,23 @@
 This is a testharness.js-based test.
 PASS Setting property for key 9 on localStorage
 PASS Setting property with toString for key 9 on localStorage
-FAIL Setting property for key 9 on localStorage with data property on prototype assert_equals: expected "proto" but got "value"
-FAIL Setting property for key 9 on localStorage with data property on prototype and existing item assert_equals: expected "proto" but got "existing"
-FAIL Setting property for key 9 on localStorage with accessor property on prototype assert_array_equals: lengths differ, expected 1 got 0
+FAIL Setting property for key 9 on localStorage with data property on prototype assert_equals: expected "proto for Setting property for key 9 on localStorage with data property on prototype" but got "value for Setting property for key 9 on localStorage with data property on prototype"
+FAIL Setting property for key 9 on localStorage with data property on prototype and existing item assert_equals: expected "proto for Setting property for key 9 on localStorage with data property on prototype and existing item" but got "existing for Setting property for key 9 on localStorage with data property on prototype and existing item"
+FAIL Setting property for key 9 on localStorage with accessor property on prototype assert_equals: expected "proto getter for Setting property for key 9 on localStorage with accessor property on prototype" but got "value for Setting property for key 9 on localStorage with accessor property on prototype"
 PASS Setting property for key x on localStorage
 PASS Setting property with toString for key x on localStorage
-FAIL Setting property for key x on localStorage with data property on prototype assert_equals: expected "proto" but got "value"
-FAIL Setting property for key x on localStorage with data property on prototype and existing item assert_equals: expected "proto" but got "value"
-FAIL Setting property for key x on localStorage with accessor property on prototype assert_equals: expected "proto getter" but got "value"
+FAIL Setting property for key x on localStorage with data property on prototype assert_equals: expected "proto for Setting property for key x on localStorage with data property on prototype" but got "value for Setting property for key x on localStorage with data property on prototype"
+FAIL Setting property for key x on localStorage with data property on prototype and existing item assert_equals: expected "proto for Setting property for key x on localStorage with data property on prototype and existing item" but got "value for Setting property for key x on localStorage with data property on prototype"
+FAIL Setting property for key x on localStorage with accessor property on prototype assert_equals: expected "proto getter for Setting property for key x on localStorage with accessor property on prototype" but got "value for Setting property for key x on localStorage with data property on prototype"
 PASS Setting property for key 9 on sessionStorage
 PASS Setting property with toString for key 9 on sessionStorage
-FAIL Setting property for key 9 on sessionStorage with data property on prototype assert_equals: expected "proto" but got "value"
-FAIL Setting property for key 9 on sessionStorage with data property on prototype and existing item assert_equals: expected "proto" but got "existing"
-FAIL Setting property for key 9 on sessionStorage with accessor property on prototype assert_array_equals: lengths differ, expected 1 got 0
+FAIL Setting property for key 9 on sessionStorage with data property on prototype assert_equals: expected "proto for Setting property for key 9 on sessionStorage with data property on prototype" but got "value for Setting property for key 9 on sessionStorage with data property on prototype"
+FAIL Setting property for key 9 on sessionStorage with data property on prototype and existing item assert_equals: expected "proto for Setting property for key 9 on sessionStorage with data property on prototype and existing item" but got "existing for Setting property for key 9 on sessionStorage with data property on prototype and existing item"
+FAIL Setting property for key 9 on sessionStorage with accessor property on prototype assert_equals: expected "proto getter for Setting property for key 9 on sessionStorage with accessor property on prototype" but got "value for Setting property for key 9 on sessionStorage with accessor property on prototype"
 PASS Setting property for key x on sessionStorage
 PASS Setting property with toString for key x on sessionStorage
-FAIL Setting property for key x on sessionStorage with data property on prototype assert_equals: expected "proto" but got "value"
-FAIL Setting property for key x on sessionStorage with data property on prototype and existing item assert_equals: expected "proto" but got "value"
-FAIL Setting property for key x on sessionStorage with accessor property on prototype assert_equals: expected "proto getter" but got "value"
+FAIL Setting property for key x on sessionStorage with data property on prototype assert_equals: expected "proto for Setting property for key x on sessionStorage with data property on prototype" but got "value for Setting property for key x on sessionStorage with data property on prototype"
+FAIL Setting property for key x on sessionStorage with data property on prototype and existing item assert_equals: expected "proto for Setting property for key x on sessionStorage with data property on prototype and existing item" but got "value for Setting property for key x on sessionStorage with data property on prototype"
+FAIL Setting property for key x on sessionStorage with accessor property on prototype assert_equals: expected "proto getter for Setting property for key x on sessionStorage with accessor property on prototype" but got "value for Setting property for key x on sessionStorage with data property on prototype"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/set.window.js b/third_party/blink/web_tests/external/wpt/webstorage/set.window.js
index 479ad58..228ce60 100644
--- a/third_party/blink/web_tests/external/wpt/webstorage/set.window.js
+++ b/third_party/blink/web_tests/external/wpt/webstorage/set.window.js
@@ -1,7 +1,8 @@
 ["localStorage", "sessionStorage"].forEach(function(name) {
     [9, "x"].forEach(function(key) {
         test(function() {
-            var value = "value";
+            var expected = "value for " + this.name;
+            var value = expected;
 
             var storage = window[name];
             storage.clear();
@@ -9,13 +10,14 @@
             assert_equals(storage[key], undefined);
             assert_equals(storage.getItem(key), null);
             assert_equals(storage[key] = value, value);
-            assert_equals(storage[key], "value");
-            assert_equals(storage.getItem(key), "value");
+            assert_equals(storage[key], expected);
+            assert_equals(storage.getItem(key), expected);
         }, "Setting property for key " + key + " on " + name);
 
         test(function() {
+            var expected = "value for " + this.name;
             var value = {
-                toString: function() { return "value"; }
+                toString: function() { return expected; }
             };
 
             var storage = window[name];
@@ -24,79 +26,77 @@
             assert_equals(storage[key], undefined);
             assert_equals(storage.getItem(key), null);
             assert_equals(storage[key] = value, value);
-            assert_equals(storage[key], "value");
-            assert_equals(storage.getItem(key), "value");
+            assert_equals(storage[key], expected);
+            assert_equals(storage.getItem(key), expected);
         }, "Setting property with toString for key " + key + " on " + name);
 
         test(function() {
-            Storage.prototype[key] = "proto";
+            var proto = "proto for " + this.name;
+            Storage.prototype[key] = proto;
             this.add_cleanup(function() { delete Storage.prototype[key]; });
 
-            var value = "value";
+            var value = "value for " + this.name;
 
             var storage = window[name];
             storage.clear();
 
-            assert_equals(storage[key], "proto");
+            assert_equals(storage[key], proto);
             assert_equals(storage.getItem(key), null);
             assert_equals(storage[key] = value, value);
             // Hidden because no [OverrideBuiltins].
-            assert_equals(storage[key], "proto");
+            assert_equals(storage[key], proto);
             assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
-            assert_equals(storage.getItem(key), "value");
+            assert_equals(storage.getItem(key), value);
         }, "Setting property for key " + key + " on " + name + " with data property on prototype");
 
         test(function() {
-            Storage.prototype[key] = "proto";
+            var proto = "proto for " + this.name;
+            Storage.prototype[key] = proto;
             this.add_cleanup(function() { delete Storage.prototype[key]; });
 
-            var value = "value";
+            var value = "value for " + this.name;
+            var existing = "existing for " + this.name;
 
             var storage = window[name];
             storage.clear();
 
-            storage.setItem(key, "existing");
+            storage.setItem(key, existing);
 
             // Hidden because no [OverrideBuiltins].
-            assert_equals(storage[key], "proto");
+            assert_equals(storage[key], proto);
             assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
-            assert_equals(storage.getItem(key), "existing");
+            assert_equals(storage.getItem(key), existing);
             assert_equals(storage[key] = value, value);
-            assert_equals(storage[key], "proto");
+            assert_equals(storage[key], proto);
             assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
-            assert_equals(storage.getItem(key), "value");
+            assert_equals(storage.getItem(key), value);
         }, "Setting property for key " + key + " on " + name + " with data property on prototype and existing item");
 
         test(function() {
-            var calledSetter = [];
-            Object.defineProperty(Storage.prototype, key, {
-                "get": function() { return "proto getter"; },
-                "set": function(v) { calledSetter.push(v); },
-                configurable: true,
-            });
-            this.add_cleanup(function() { delete Storage.prototype[key]; });
-
-            var value = "value";
-
             var storage = window[name];
             storage.clear();
 
-            assert_equals(storage[key], "proto getter");
+            var proto = "proto getter for " + this.name;
+            Object.defineProperty(Storage.prototype, key, {
+                "get": function() { return proto; },
+                "set": this.unreached_func("Should not call [[Set]] on prototype"),
+                "configurable": true,
+            });
+            this.add_cleanup(function() {
+                delete Storage.prototype[key];
+                delete storage[key];
+                assert_false(key in storage);
+            });
+
+            var value = "value for " + this.name;
+
+            assert_equals(storage[key], proto);
             assert_equals(storage.getItem(key), null);
             assert_equals(storage[key] = value, value);
             // Property is hidden because no [OverrideBuiltins].
-            if (typeof key === "number") {
-                // P is an array index: call through to OrdinarySetWithOwnDescriptor()
-                assert_array_equals(calledSetter, [value]);
-                assert_equals(storage[key], "proto getter");
-                assert_equals(storage.getItem(key), null);
-            } else {
-                // P is not an array index: early return in [[Set]] step 2.
-                // https://github.com/heycam/webidl/issues/630
-                assert_equals(storage[key], "proto getter");
-                assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
-                assert_equals(storage.getItem(key), "value");
-            }
+            assert_equals(storage[key], proto);
+            assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
+            assert_equals(storage.getItem(key), value);
         }, "Setting property for key " + key + " on " + name + " with accessor property on prototype");
     });
 });
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-applies-hover-mousemove.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-applies-hover-mousemove.html
new file mode 100644
index 0000000..02861c4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-applies-hover-mousemove.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/gesture-util.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    margin: 5px;
+    border: 1px solid black;
+  }
+  div:hover {
+    background-color: dodgerblue;
+  }
+  iframe {
+    width: 200px;
+    height: 200px;
+  }
+</style>
+
+<div id="first" tabindex="0">First</div>
+<iframe srcdoc="
+    <!DOCTYPE html>
+    <style>
+      div:hover {
+        background-color: dodgerblue;
+      }
+      div {
+        width: 100px;
+        height: 100px;
+        margin: 5px;
+        border: 1px solid black;
+      }
+    </style>
+    <div id='second' tabindex='0'>Second</div>"></iframe>
+<div id="third" tabindex="0">Third</div>
+
+<script>
+  window.onload = async () => {
+    // This test checks whether hover state is correctly applied and removed from
+    // elements as the become and lose interest but includes a mouse move to
+    // ensure it doesn't interfere with hover transitions.
+    const iframe = document.querySelector("iframe");
+    const first = document.getElementById("first");
+    const second = iframe.contentDocument.getElementById("second");
+    const third = document.getElementById("third");
+
+    promise_test(async () => {
+      snav.assertSnavEnabledAndTestable();
+
+      // Move interest to |second|.
+      snav.triggerMove("Down"); // |first|
+      snav.triggerMove("Down"); // |iframe|
+      snav.triggerMove("Down"); // |second|
+
+      assert_equals(window.internals.interestedElement,
+                    second, "|second| element gets interest.");
+      assert_true(second.matches(":hover"),
+                  "|second| should be hovered when interested.");
+      assert_true(iframe.matches(":hover"),
+                  "|iframe| should be hovered as element inside is hovered.");
+
+      // Arbitrary mouse move on the main frame. This will un-hover the iframe,
+      // ensure further spatial navigations remove and replace hover correctly.
+      await mouseMoveTo(300, 300);
+      assert_false(iframe.matches(":hover"),
+                  "Mouse move should unhover |iframe|.");
+
+      // Down again to interest |third|.
+      snav.triggerMove("Down");
+      assert_equals(window.internals.interestedElement,
+                    third, "|third| element gets interest.");
+      assert_true(third.matches(":hover"),
+                  "|third| should be hovered when interested.");
+      assert_false(second.matches(":hover"),
+                  "|second| should no longer be hovered.");
+      assert_false(iframe.matches(":hover"),
+                  "|iframe| should no longer be hovered.");
+
+    }, "Test hover application with mouse moves during spatial navigation.");
+  }
+</script>
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-applies-hover.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-applies-hover.html
new file mode 100644
index 0000000..438badec
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-applies-hover.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    margin: 5px;
+    border: 1px solid black;
+  }
+  div:hover {
+    background-color: dodgerblue;
+  }
+  iframe {
+    width: 200px;
+    height: 200px;
+  }
+</style>
+
+<div id="first" tabindex="0">First</div>
+<iframe srcdoc="
+    <!DOCTYPE html>
+    <style>
+      div:hover {
+        background-color: dodgerblue;
+      }
+      div {
+        width: 100px;
+        height: 100px;
+        margin: 5px;
+        border: 1px solid black;
+      }
+    </style>
+    <div id='second' tabindex='0'>Second</div>"></iframe>
+<div id="third" tabindex="0">Third</div>
+
+<script>
+  // This test checks whether hover state is correctly applied and removed from
+  // elements as the become and lose interest. Includes an iframe to get at
+  // least basic exercise of cross-frame cases.
+  snav.assertSnavEnabledAndTestable();
+
+  const t = async_test("Test hover application during spatial navigation.");
+
+  onload = t.step_func(() => {
+    const iframe = document.querySelector("iframe");
+    const first = document.getElementById("first");
+    const second = iframe.contentDocument.getElementById("second");
+    const third = document.getElementById("third");
+
+    // Moves interest to |first| element.
+    snav.triggerMove("Down");
+
+    assert_equals(window.internals.interestedElement,
+                  first, "|first| element gets interest.");
+    assert_true(first.matches(":hover"),
+                "|first| should be hovered when interested.");
+
+    // First down will interest iframe. Down again to interest |second|.
+    snav.triggerMove("Down");
+    snav.triggerMove("Down");
+
+    assert_equals(window.internals.interestedElement,
+                  second, "|second| element gets interest.");
+    assert_true(second.matches(":hover"),
+                "|second| should be hovered when interested.");
+    assert_true(iframe.matches(":hover"),
+                "|iframe| should be hovered as element inside is hovered.");
+    assert_false(first.matches(":hover"),
+                "|first| should no longer be hovered.");
+
+    // Down again to interest |third|.
+    snav.triggerMove("Down");
+    assert_equals(window.internals.interestedElement,
+                  third, "|third| element gets interest.");
+    assert_true(third.matches(":hover"),
+                "|third| should be hovered when interested.");
+    assert_false(second.matches(":hover"),
+                "|second| should no longer be hovered.");
+    assert_false(iframe.matches(":hover"),
+                "|iframe| should no longer be hovered.");
+
+    t.done();
+  });
+</script>
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-mouse-enter-leave.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-mouse-enter-leave.html
new file mode 100644
index 0000000..42238c8
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-mouse-enter-leave.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    margin: 5px;
+    border: 1px solid black;
+  }
+  div:hover {
+    background-color: dodgerblue;
+  }
+  iframe {
+    width: 200px;
+    height: 200px;
+  }
+</style>
+
+<div id="first" tabindex="0">First</div>
+<iframe srcdoc="
+    <!DOCTYPE html>
+    <style>
+      div:hover {
+        background-color: dodgerblue;
+      }
+      div {
+        width: 100px;
+        height: 100px;
+        margin: 5px;
+        border: 1px solid black;
+      }
+    </style>
+    <div id='second' tabindex='0'>Second</div>"></iframe>
+<div id="third" tabindex="0">Third</div>
+
+<script>
+  const iframe = document.querySelector("iframe");
+  iframe.onload = () => {
+    // This test checks whether mouse "boundary" events like mouse enter and
+    // mouse leave are fired when spatial navigation moves from element to
+    // element.
+    const first = document.getElementById("first");
+    const second = iframe.contentDocument.getElementById("second");
+    const third = document.getElementById("third");
+
+    const eventNames = ['mouseenter', 'mouseleave', 'mouseover', 'mouseout'];
+    const elements = [first, second, third];
+
+    function reset() {
+      elements.forEach(element => {
+        element.eventList = [];
+      });
+    }
+
+    reset();
+
+    eventNames.forEach(event => {
+      elements.forEach(element => {
+        element.addEventListener(event, () => { element.eventList.push(event); });
+      });
+    });
+
+    snav.assertSnavEnabledAndTestable(/*focuslessSpatNav=*/true);
+
+    test(() => {
+      // Moves interest to |first| element.
+      snav.triggerMove("Down");
+
+      assert_equals(window.internals.interestedElement,
+                    first, "|first| element gets interest.");
+      assert_equals(first.eventList.join(), "mouseover,mouseenter", "|first| events");
+      assert_equals(second.eventList.join(), "",  "|second| events");
+      assert_equals(third.eventList.join(), "", "|third| events");
+    }, "Interest on |first|");
+
+    reset();
+
+    test(() => {
+      // Moves interest to |iframe| element.
+      snav.triggerMove("Down");
+      assert_equals(window.internals.interestedElement,
+                    iframe, "|iframe| element gets interest.");
+      assert_equals(first.eventList.join(), "mouseout,mouseleave", "|first| events");
+      assert_equals(second.eventList.join(), "",  "|second| events");
+      assert_equals(third.eventList.join(), "", "|third| events");
+    }, "Interest on |iframe|");
+
+    reset();
+
+    test(() => {
+      // Moves interest to |second| element.
+      snav.triggerMove("Down");
+      assert_equals(window.internals.interestedElement,
+                    second, "|second| element gets interest.");
+      assert_equals(first.eventList.join(), "", "|first| events");
+      assert_equals(second.eventList.join(), "mouseover,mouseenter",  "|second| events");
+      assert_equals(third.eventList.join(), "", "|third| events");
+    }, "Interest on |second|");
+
+    reset();
+
+    test(() => {
+      // Moves interest to |second| element.
+      snav.triggerMove("Down");
+      assert_equals(window.internals.interestedElement,
+                    third, "|third| element gets interest.");
+      assert_equals(first.eventList.join(), "", "|first| events");
+      assert_equals(second.eventList.join(), "mouseout,mouseleave",  "|second| events");
+      assert_equals(third.eventList.join(), "mouseover,mouseenter", "|third| events");
+    }, "Interest on |third|");
+
+    reset();
+
+    test(() => {
+      // Moves interest to |second| element.
+      // TODO(bokan): Need to implement clearing interest when element is removed.
+      //third.remove();
+      //assert_equals(window.internals.interestedElement,
+      //              null, "interest was cleared");
+      //assert_equals(first.eventList.join(), "", "|first| events");
+      //assert_equals(second.eventList.join(), "",  "|second| events");
+      //assert_equals(third.eventList.join(), "mouseout,mouseleave", "|third| events");
+    }, "Interest cleared");
+  }
+</script>
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
deleted file mode 100644
index 43bdf17..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-  
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [19, 19],
-      "bounds": [189, 124],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "position": [19, 19],
-      "bounds": [189, 308],
-      "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC",
-      "transform": 1
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "drawsContent": false
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [208, 19],
-      "bounds": [15, 109],
-      "drawsContent": false
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [208, 128],
-      "bounds": [15, 15]
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [249, 19],
-      "bounds": [189, 124],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "position": [249, 19],
-      "bounds": [189, 308],
-      "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC",
-      "transform": 2
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "drawsContent": false
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [438, 19],
-      "bounds": [15, 109],
-      "drawsContent": false
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [438, 128],
-      "bounds": [15, 15]
-    }
-  ],
-  "transforms": [
-    {
-      "id": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, -50, 0, 1]
-      ],
-      "flattenInheritedTransform": false
-    },
-    {
-      "id": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, -50, 0, 1]
-      ],
-      "flattenInheritedTransform": false
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/background/change-text-content-and-background-color-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/background/change-text-content-and-background-color-expected.txt
deleted file mode 100644
index 4aef00ee5..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/background/change-text-content-and-background-color-expected.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl (positioned) INPUT id='input'",
-          "rect": [8, 8, 244, 67],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [30, 30, 200, 23],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [30, 30, 43, 23],
-          "reason": "full"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/clip/control-clip-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/clip/control-clip-expected.txt
deleted file mode 100644
index c5eae1bd..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/clip/control-clip-expected.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (anonymous)",
-          "rect": [9, 84, 198, 14],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (anonymous)",
-          "rect": [16, 114, 184, 13],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [84, 114, 48, 14],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutText (anonymous)",
-          "rect": [9, 84, 47, 14],
-          "reason": "full"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/details-open-repaint-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/details-open-repaint-expected.txt
deleted file mode 100644
index 06969d6..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/details-open-repaint-expected.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='details-content'",
-          "rect": [8, 68, 784, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutTextControl INPUT",
-          "rect": [8, 68, 123, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [11, 71, 117, 13],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutDetailsMarker DIV id='details-marker'",
-          "rect": [8, 53, 11, 11],
-          "reason": "full"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/forms/submit-focus-by-mouse-then-keydown-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/forms/submit-focus-by-mouse-then-keydown-expected.txt
deleted file mode 100644
index 3d2c557f..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/forms/submit-focus-by-mouse-then-keydown-expected.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutButton INPUT",
-          "rect": [3, 4, 64, 29],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [16, 11, 38, 14],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow (anonymous)",
-          "rect": [16, 11, 38, 13],
-          "reason": "subtree"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/forms/textarea-caret-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/forms/textarea-caret-expected.txt
deleted file mode 100644
index 49339ea7..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/forms/textarea-caret-expected.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [5, 5, 167, 38],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [11, 11, 155, 13],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [9, 24, 144, 15],
-          "reason": "scroll control"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [9, 11, 144, 13],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [153, 24, 15, 15],
-          "reason": "scroll control"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [153, 9, 15, 15],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/multi-layout-one-frame-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/multi-layout-one-frame-expected.txt
deleted file mode 100644
index 3d649bf..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/multi-layout-one-frame-expected.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [138, 11, 117, 13],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [11, 11, 117, 13],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [138, 11, 40, 13],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [11, 11, 40, 13],
-          "reason": "full"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt
deleted file mode 100644
index eb092d6..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [407, 11, 2, 13],
-          "reason": "caret"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [404, 11, 2, 13],
-          "reason": "caret"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
deleted file mode 100644
index b474661..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutTextControl INPUT id='root'",
-      "position": [5, 5],
-      "bounds": [54, 25],
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl INPUT id='root'",
-          "rect": [0, 0, 54, 25],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutTextControl INPUT id='root'",
-          "rect": [0, 0, 48, 19],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [6, 6, 42, 13],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [6, 6, 42, 13],
-          "reason": "subtree"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
deleted file mode 100644
index b474661..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutTextControl INPUT id='root'",
-      "position": [5, 5],
-      "bounds": [54, 25],
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl INPUT id='root'",
-          "rect": [0, 0, 54, 25],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutTextControl INPUT id='root'",
-          "rect": [0, 0, 48, 19],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [6, 6, 42, 13],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [6, 6, 42, 13],
-          "reason": "subtree"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/search-field-cancel-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/search-field-cancel-expected.txt
deleted file mode 100644
index c61719d..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/search-field-cancel-expected.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [12, 45, 105, 13],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [12, 45, 54, 13],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
deleted file mode 100644
index 6591452..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl INPUT id='target'",
-          "rect": [5, 5, 54, 25],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [11, 11, 42, 13],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [11, 11, 42, 13],
-          "reason": "subtree"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
deleted file mode 100644
index 6591452..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl INPUT id='target'",
-          "rect": [5, 5, 54, 25],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [11, 11, 42, 13],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [11, 11, 42, 13],
-          "reason": "subtree"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/stacked-diacritics-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/stacked-diacritics-expected.txt
deleted file mode 100644
index b0a5f9e8..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/stacked-diacritics-expected.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='stacked'",
-          "rect": [19, 159, 200, 41],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [19, 153, 131, 47],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/subtree-root-skipped-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/subtree-root-skipped-expected.txt
deleted file mode 100644
index d68163d0..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/paint/invalidation/subtree-root-skipped-expected.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV",
-          "rect": [11, 11, 117, 13],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutText #text",
-          "rect": [11, 11, 26, 13],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV id='div'",
-          "rect": [8, 288, 10, 20],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
deleted file mode 100644
index 43bdf17..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-  
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [19, 19],
-      "bounds": [189, 124],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "position": [19, 19],
-      "bounds": [189, 308],
-      "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC",
-      "transform": 1
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "drawsContent": false
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [208, 19],
-      "bounds": [15, 109],
-      "drawsContent": false
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [208, 128],
-      "bounds": [15, 15]
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [249, 19],
-      "bounds": [189, 124],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "position": [249, 19],
-      "bounds": [189, 308],
-      "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC",
-      "transform": 2
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "drawsContent": false
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [438, 19],
-      "bounds": [15, 109],
-      "drawsContent": false
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [438, 128],
-      "bounds": [15, 15]
-    }
-  ],
-  "transforms": [
-    {
-      "id": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, -50, 0, 1]
-      ],
-      "flattenInheritedTransform": false
-    },
-    {
-      "id": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, -50, 0, 1]
-      ],
-      "flattenInheritedTransform": false
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 489890f..77e5379 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -39,6 +39,27 @@
     setter maxDecibels
     setter minDecibels
     setter smoothingTimeConstant
+interface Animation : EventTarget
+    attribute @@toStringTag
+    getter currentTime
+    getter id
+    getter oncancel
+    getter onfinish
+    getter playState
+    getter playbackRate
+    getter startTime
+    method cancel
+    method constructor
+    method finish
+    method pause
+    method play
+    method reverse
+    setter currentTime
+    setter id
+    setter oncancel
+    setter onfinish
+    setter playbackRate
+    setter startTime
 interface AnimationEvent : Event
     attribute @@toStringTag
     getter animationName
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/web-animations-api-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/web-animations-api-expected.txt
index 52da4863..4f7981f 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/web-animations-api-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/web-animations-api-expected.txt
@@ -2,8 +2,6 @@
 PASS Element.animate() should be exposed.
 PASS Element.getAnimations() should not be exposed without experimental web platform features enabled.
 This test is expected to fail in LayoutTests/webexposed.
-PASS Animation constructor should not be exposed without experimental web platform features enabled.
-This test is expected to fail in LayoutTests/webexposed.
 PASS Timeline should not be exposed without experimental web platform features enabled.
 This test is expected to fail in LayoutTests/webexposed.
 PASS document.timeline should not be exposed without experimental web platform features enabled.
diff --git a/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt b/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
index a92bbec..d3a5d1b 100644
--- a/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
+++ b/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
@@ -17,6 +17,7 @@
 idle-detection
 layout-animations
 lazyload
+loading-frame-default-eager
 magnetometer
 microphone
 midi
diff --git a/third_party/blink/web_tests/webexposed/web-animations-api-expected.txt b/third_party/blink/web_tests/webexposed/web-animations-api-expected.txt
index c9ca885..f00a887 100644
--- a/third_party/blink/web_tests/webexposed/web-animations-api-expected.txt
+++ b/third_party/blink/web_tests/webexposed/web-animations-api-expected.txt
@@ -2,8 +2,6 @@
 PASS Element.animate() should be exposed.
 FAIL Element.getAnimations() should not be exposed without experimental web platform features enabled.
 This test is expected to fail in LayoutTests/webexposed. assert_false: expected false got true
-FAIL Animation constructor should not be exposed without experimental web platform features enabled.
-This test is expected to fail in LayoutTests/webexposed. assert_false: expected false got true
 FAIL Timeline should not be exposed without experimental web platform features enabled.
 This test is expected to fail in LayoutTests/webexposed. assert_false: expected false got true
 FAIL document.timeline should not be exposed without experimental web platform features enabled.
diff --git a/third_party/blink/web_tests/webexposed/web-animations-api.html b/third_party/blink/web_tests/webexposed/web-animations-api.html
index 403e292..cb621d0 100644
--- a/third_party/blink/web_tests/webexposed/web-animations-api.html
+++ b/third_party/blink/web_tests/webexposed/web-animations-api.html
@@ -11,10 +11,6 @@
 }, 'Element.getAnimations() should not be exposed without experimental web platform features enabled.\nThis test is expected to fail in LayoutTests/webexposed.')
 
 test(function() {
-    assert_false('Animation' in window);
-},'Animation constructor should not be exposed without experimental web platform features enabled.\nThis test is expected to fail in LayoutTests/webexposed.');
-
-test(function() {
     assert_false('AnimationTimeline' in window);
 },'Timeline should not be exposed without experimental web platform features enabled.\nThis test is expected to fail in LayoutTests/webexposed.');
 
diff --git a/third_party/chromevox/BUILD.gn b/third_party/chromevox/BUILD.gn
index 4752d59..cf39cd9b 100644
--- a/third_party/chromevox/BUILD.gn
+++ b/third_party/chromevox/BUILD.gn
@@ -1,8 +1,9 @@
 # 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.
+import("//chromecast/chromecast.gni")
 
-assert(is_chromeos)
+assert(is_chromeos || is_chromecast)
 
 chromevox_out_dir = "$root_out_dir/resources/chromeos/chromevox"
 
diff --git a/third_party/feed/README.chromium b/third_party/feed/README.chromium
index 8a3c669..a92ce7b3 100644
--- a/third_party/feed/README.chromium
+++ b/third_party/feed/README.chromium
@@ -2,7 +2,7 @@
 Short name: feed
 URL: https://chromium.googlesource.com/feed
 Version: 0
-Revision: d1e6b4e648a89fb58f706eb182f16053fa95f1fe
+Revision: d50f6d477b1ddf9294f324fa601a1f085084fba5
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/feed/java_sources.gni b/third_party/feed/java_sources.gni
index c89a97f1..9a5f091 100644
--- a/third_party/feed/java_sources.gni
+++ b/third_party/feed/java_sources.gni
@@ -5,12 +5,6 @@
 # Auto-generated by update_java_sources.sh
 
 feed_lib_java_sources = [
-  "src/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionManager.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionReader.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionParser.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionParserFactory.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionSource.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/actionparser/ActionSourceConverter.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/ActionPropertiesWithId.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/DismissActionWithSemanticProperties.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/MutationContext.java",
@@ -22,35 +16,12 @@
   "src/src/main/java/com/google/android/libraries/feed/api/knowncontent/KnownContentApi.java",
   "src/src/main/java/com/google/android/libraries/feed/api/lifecycle/AppLifecycleListener.java",
   "src/src/main/java/com/google/android/libraries/feed/api/lifecycle/Resettable.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/FeatureChange.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/FeatureChangeObserver.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelChild.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelCursor.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelError.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelFeature.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelMutation.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelProvider.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelProviderFactory.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelProviderObserver.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/ModelToken.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/RemoveTracking.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/TokenCompleted.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/modelprovider/TokenCompletedObserver.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/protocoladapter/ProtocolAdapter.java",
   "src/src/main/java/com/google/android/libraries/feed/api/requestmanager/ActionUploadRequestManager.java",
   "src/src/main/java/com/google/android/libraries/feed/api/requestmanager/RequestManager.java",
   "src/src/main/java/com/google/android/libraries/feed/api/scope/ClearAllListener.java",
   "src/src/main/java/com/google/android/libraries/feed/api/scope/FeedProcessScope.java",
   "src/src/main/java/com/google/android/libraries/feed/api/scope/FeedStreamScope.java",
   "src/src/main/java/com/google/android/libraries/feed/api/sessionmanager/SessionManager.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/ActionPropertiesMutation.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/ContentMutation.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/LocalActionMutation.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/SemanticPropertiesMutation.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/SessionMutation.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/Store.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/StoreListener.java",
-  "src/src/main/java/com/google/android/libraries/feed/api/store/UploadableActionMutation.java",
   "src/src/main/java/com/google/android/libraries/feed/api/stream/ContentChangedListener.java",
   "src/src/main/java/com/google/android/libraries/feed/api/stream/Header.java",
   "src/src/main/java/com/google/android/libraries/feed/api/stream/NonDismissibleHeader.java",
@@ -198,6 +169,7 @@
   "src/src/main/java/com/google/android/libraries/feed/host/logging/ScrollType.java",
   "src/src/main/java/com/google/android/libraries/feed/host/logging/SessionEvent.java",
   "src/src/main/java/com/google/android/libraries/feed/host/logging/SpinnerType.java",
+  "src/src/main/java/com/google/android/libraries/feed/host/logging/Task.java",
   "src/src/main/java/com/google/android/libraries/feed/host/logging/ZeroStateShowReason.java",
   "src/src/main/java/com/google/android/libraries/feed/host/network/HttpHeader.java",
   "src/src/main/java/com/google/android/libraries/feed/host/network/HttpRequest.java",
@@ -224,13 +196,42 @@
   "src/src/main/java/com/google/android/libraries/feed/host/stream/TooltipCallbackApi.java",
   "src/src/main/java/com/google/android/libraries/feed/host/stream/TooltipInfo.java",
   "src/src/main/java/com/google/android/libraries/feed/host/stream/TooltipSupportedApi.java",
-  "src/src/main/java/com/google/android/libraries/feed/hostimpl/logging/LoggingApiImpl.java",
+  "src/src/main/java/com/google/android/libraries/feed/hostimpl/logging/NoOpBasicLoggingApi.java",
   "src/src/main/java/com/google/android/libraries/feed/hostimpl/network/NetworkClientWrapper.java",
   "src/src/main/java/com/google/android/libraries/feed/hostimpl/scheduler/SchedulerApiWrapper.java",
   "src/src/main/java/com/google/android/libraries/feed/hostimpl/storage/InMemoryContentStorage.java",
   "src/src/main/java/com/google/android/libraries/feed/hostimpl/storage/InMemoryJournalStorage.java",
   "src/src/main/java/com/google/android/libraries/feed/hostimpl/storage/PersistentContentStorage.java",
   "src/src/main/java/com/google/android/libraries/feed/hostimpl/storage/PersistentJournalStorage.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/actionmanager/ActionManager.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/actionmanager/ActionReader.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/actionparser/ActionParser.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/actionparser/ActionParserFactory.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/actionparser/ActionSource.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/actionparser/ActionSourceConverter.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/FeatureChange.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/FeatureChangeObserver.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelChild.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelCursor.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelError.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelFeature.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelProvider.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelProviderFactory.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelProviderObserver.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/ModelToken.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/RemoveTracking.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/TokenCompleted.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/modelprovider/TokenCompletedObserver.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/protocoladapter/ProtocolAdapter.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/ActionPropertiesMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/ContentMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/LocalActionMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/SemanticPropertiesMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/SessionMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/Store.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/StoreListener.java",
+  "src/src/main/java/com/google/android/libraries/feed/internalapi/store/UploadableActionMutation.java",
   "src/src/main/java/com/google/android/libraries/feed/mocknetworkclient/MockPushServer.java",
   "src/src/main/java/com/google/android/libraries/feed/mocknetworkclient/MockServerNetworkClient.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/AdapterFactory.java",
@@ -279,10 +280,13 @@
   "src/src/main/java/com/google/android/libraries/feed/piet/host/ThrowingCustomElementProvider.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/host/TypefaceProvider.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/AspectRatioScalingImageView.java",
+  "src/src/main/java/com/google/android/libraries/feed/piet/ui/BitmapMaskingRoundedCornerWrapperView.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/BorderDrawable.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/GradientDrawable.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/GradientShader.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/GridRowView.java",
+  "src/src/main/java/com/google/android/libraries/feed/piet/ui/LegacyRoundedCornerWrapperView.java",
+  "src/src/main/java/com/google/android/libraries/feed/piet/ui/OutlineRoundedCornerWrapperView.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerMaskCache.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerViewHelper.java",
   "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerWrapperView.java",
@@ -320,17 +324,17 @@
 feed_conformance_test_lib_sources = [
   "src/src/main/java/com/google/android/libraries/feed/api/common/testing/ContentIdGenerators.java",
   "src/src/main/java/com/google/android/libraries/feed/api/common/testing/InternalProtocolBuilder.java",
-  "src/src/main/java/com/google/android/libraries/feed/common/concurrent/testing/ClockBackedFakeMainThreadRunner.java",
+  "src/src/main/java/com/google/android/libraries/feed/common/concurrent/testing/FakeDirectExecutor.java",
   "src/src/main/java/com/google/android/libraries/feed/common/concurrent/testing/FakeMainThreadRunner.java",
   "src/src/main/java/com/google/android/libraries/feed/common/concurrent/testing/FakeTaskQueue.java",
   "src/src/main/java/com/google/android/libraries/feed/common/concurrent/testing/FakeThreadUtils.java",
-  "src/src/main/java/com/google/android/libraries/feed/common/testing/FakeBasicLoggingApi.java",
-  "src/src/main/java/com/google/android/libraries/feed/common/testing/InfrastructureIntegrationScope.java",
+  "src/src/main/java/com/google/android/libraries/feed/common/testing/InfraIntegrationScope.java",
   "src/src/main/java/com/google/android/libraries/feed/common/testing/ModelProviderValidator.java",
   "src/src/main/java/com/google/android/libraries/feed/common/testing/PagingState.java",
   "src/src/main/java/com/google/android/libraries/feed/common/testing/RequiredConsumer.java",
+  "src/src/main/java/com/google/android/libraries/feed/common/testing/ResponseBuilder.java",
   "src/src/main/java/com/google/android/libraries/feed/common/testing/RunnableSubject.java",
-  "src/src/main/java/com/google/android/libraries/feed/common/testing/WireProtocolResponseBuilder.java",
+  "src/src/main/java/com/google/android/libraries/feed/common/testing/SessionTestUtils.java",
   "src/src/main/java/com/google/android/libraries/feed/common/time/testing/FakeClock.java",
   "src/src/main/java/com/google/android/libraries/feed/testing/conformance/network/NetworkClientConformanceTest.java",
   "src/src/main/java/com/google/android/libraries/feed/testing/conformance/scheduler/SchedulerConformanceTest.java",
@@ -340,4 +344,18 @@
   "src/src/main/java/com/google/android/libraries/feed/testing/conformance/storage/JournalStorageDirectConformanceTest.java",
   "src/src/main/java/com/google/android/libraries/feed/testing/requestmanager/FakeActionUploadRequestManager.java",
   "src/src/main/java/com/google/android/libraries/feed/testing/requestmanager/FakeRequestManager.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/host/logging/FakeBasicLoggingApi.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/host/offlineindicator/FakeOfflineIndicatorApi.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/host/scheduler/FakeSchedulerApi.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/host/stream/FakeCardConfiguration.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/host/stream/FakeTooltipSupportedApi.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelChild.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelCursor.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelFeature.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelMutation.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelProvider.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelProviderFactory.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeModelToken.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FakeViewDepthProvider.java",
+  "src/src/main/java/com/google/android/libraries/feed/testing/modelprovider/FeatureChangeBuilder.java",
 ]
diff --git a/third_party/feed/proto_sources.gni b/third_party/feed/proto_sources.gni
index fc52a3e1..a616f1a 100644
--- a/third_party/feed/proto_sources.gni
+++ b/third_party/feed/proto_sources.gni
@@ -3,10 +3,11 @@
 # found in the LICENSE file.
 
 feed_lib_proto_sources = [
-  "src/src/main/proto/com/google/android/libraries/feed/api/proto/stream_data.proto",
   "src/src/main/proto/com/google/android/libraries/feed/basicstream/internal/proto/stream_saved_instance_state.proto",
+  "src/src/main/proto/com/google/android/libraries/feed/internalapi/proto/stream_data.proto",
   "src/src/main/proto/com/google/android/libraries/feed/sharedstream/proto/scroll_state.proto",
   "src/src/main/proto/com/google/android/libraries/feed/sharedstream/proto/ui_refresh_reason.proto",
+  "src/src/main/proto/com/google/android/libraries/feed/testing/proto/ui_context_for_test.proto",
   "src/src/main/proto/search/now/ui/action/feed_action.proto",
   "src/src/main/proto/search/now/ui/action/feed_action_payload.proto",
   "src/src/main/proto/search/now/ui/action/piet_extensions.proto",
@@ -28,6 +29,7 @@
   "src/src/main/proto/search/now/ui/stream/stream_offline_extension.proto",
   "src/src/main/proto/search/now/ui/stream/stream_structure.proto",
   "src/src/main/proto/search/now/ui/stream/stream_swipe_extension.proto",
+  "src/src/main/proto/search/now/wire/feed/action_payload.proto",
   "src/src/main/proto/search/now/wire/feed/action_properties.proto",
   "src/src/main/proto/search/now/wire/feed/action_request.proto",
   "src/src/main/proto/search/now/wire/feed/action_type.proto",
@@ -55,7 +57,7 @@
   "src/src/main/proto/search/now/wire/feed/response.proto",
   "src/src/main/proto/search/now/wire/feed/semantic_properties.proto",
   "src/src/main/proto/search/now/wire/feed/token.proto",
-  "src/src/main/proto/search/now/wire/feed/upload_action_type.proto",
   "src/src/main/proto/search/now/wire/feed/version.proto",
+  "src/src/test/proto/search/now/wire/feed/action_payload_for_test.proto",
   "src/src/test/proto/search/now/wire/feed/opaque_action_data_for_test.proto",
 ]
diff --git a/third_party/feed/update_java_sources.sh b/third_party/feed/update_java_sources.sh
index da98a86..bc8021a9 100755
--- a/third_party/feed/update_java_sources.sh
+++ b/third_party/feed/update_java_sources.sh
@@ -30,5 +30,9 @@
     env LC_COLLATE=en_US.ASCII sort | sed 's/^\(.*\)$/  "\1",/g' >> java_sources.gni
 find src/src/main/java/com/google/android/libraries/feed/testing/requestmanager -wholename "*.java" |\
     env LC_COLLATE=en_US.ASCII sort | sed 's/^\(.*\)$/  "\1",/g' >> java_sources.gni
+find src/src/main/java/com/google/android/libraries/feed/testing/host -wholename "*.java" |\
+    env LC_COLLATE=en_US.ASCII sort | sed 's/^\(.*\)$/  "\1",/g' >> java_sources.gni
+find src/src/main/java/com/google/android/libraries/feed/testing/modelprovider -wholename "*.java" |\
+    env LC_COLLATE=en_US.ASCII sort | sed 's/^\(.*\)$/  "\1",/g' >> java_sources.gni
 echo "]" >> java_sources.gni
 echo "java_sources.gni generated successfully"
diff --git a/third_party/openh264/OWNERS b/third_party/openh264/OWNERS
index 4be2fd6..f9316a7af 100644
--- a/third_party/openh264/OWNERS
+++ b/third_party/openh264/OWNERS
@@ -1,2 +1,2 @@
-hbos@chromium.org
+sprang@chromium.org
 ssilkin@chromium.org
diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium
index 8bd3197..56342bd 100644
--- a/third_party/opus/README.chromium
+++ b/third_party/opus/README.chromium
@@ -20,3 +20,4 @@
 * Make sure HB_gain is not NaN in an attempt to fix chromium:826914
 * Saturate add to avoid int overflow to fix chromium:842528. This should be
   reverted when updating to v1.3
+* Apply https://github.com/xiph/opus/commit/4f4b11c2398e96134dc62ee794bfe33ecd6e9bd2
diff --git a/third_party/opus/src/include/opus_defines.h b/third_party/opus/src/include/opus_defines.h
index 33c5acd..653d9168 100644
--- a/third_party/opus/src/include/opus_defines.h
+++ b/third_party/opus/src/include/opus_defines.h
@@ -168,6 +168,7 @@
 /* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
 #define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
 #define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
+#define OPUS_GET_IN_DTX_REQUEST              4049
 
 /* Macros to trigger compilation errors when the wrong types are provided to a CTL */
 #define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
@@ -712,6 +713,16 @@
   * </dl>
   * @hideinitializer */
 #define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+/** Gets the DTX state of the encoder.
+  * Returns whether the last encoded frame was either a comfort noise update
+  * during DTX or not encoded because of DTX.
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>0</dt><dd>The encoder is not in DTX.</dd>
+  * <dt>1</dt><dd>The encoder is in DTX.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)
 
 /**@}*/
 
diff --git a/third_party/opus/src/src/opus_encoder.c b/third_party/opus/src/src/opus_encoder.c
index 2149c20b..7fa6be0c 100644
--- a/third_party/opus/src/src/opus_encoder.c
+++ b/third_party/opus/src/src/opus_encoder.c
@@ -2716,6 +2716,33 @@
             ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value));
         }
         break;
+        case OPUS_GET_IN_DTX_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+                goto bad_arg;
+            }
+            if (st->silk_mode.useDTX && (st->prev_mode == MODE_SILK_ONLY || st->prev_mode == MODE_HYBRID)) {
+                /* DTX determined by Silk. */
+                int n;
+                void *silk_enc = (char*)st+st->silk_enc_offset;
+                *value = 1;
+                for (n=0;n<st->silk_mode.nChannelsInternal;n++) {
+                    *value = *value && ((silk_encoder*)silk_enc)->state_Fxx[n].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX;
+                }
+            }
+#ifndef DISABLE_FLOAT_API
+            else if (st->use_dtx) {
+                /* DTX determined by Opus. */
+                *value = st->nb_no_activity_frames >= NB_SPEECH_FRAMES_BEFORE_DTX;
+            }
+#endif
+            else {
+                *value = 0;
+            }
+        }
+        break;
 
         case CELT_GET_MODE_REQUEST:
         {
diff --git a/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js b/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
index ad2fad0..26e537ff 100644
--- a/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
+++ b/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
@@ -326,7 +326,6 @@
     this.setTitle(this.options.textXRNotFoundTitle);
 
     if (options.supportedSessionTypes.length > 0 && navigator.xr) {
-      console.log(options.supportedSessionTypes);
       navigator.xr.addEventListener('devicechange', () => this.__onDeviceChange());
 
       // Force a call now in case the initial event from the page load was missed.
diff --git a/third_party/webxr_test_pages/webxr-samples/positional-audio.html b/third_party/webxr_test_pages/webxr-samples/positional-audio.html
index fa9f107d..35a3cab 100644
--- a/third_party/webxr_test_pages/webxr-samples/positional-audio.html
+++ b/third_party/webxr_test_pages/webxr-samples/positional-audio.html
@@ -269,6 +269,7 @@
         });
         document.querySelector('header').appendChild(xrButton.domElement);
 
+        if (navigator.xr) {
           // Load multiple audio sources.
           Promise.all([
             createAudioSource({
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 5e5f4bf..c284aff1 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -90,6 +90,8 @@
 if 'LLVM_REPO_URL' in os.environ:
   LLVM_REPO_URL = os.environ['LLVM_REPO_URL']
 
+BUG_REPORT_URL = ('https://crbug.com and run tools/clang/scripts/upload_crash.py'
+                  ' (only works inside Google) which will upload a report')
 
 
 def DownloadUrl(url, output_file):
@@ -559,6 +561,7 @@
                      '-DCLANG_ENABLE_ARCMT=OFF',
                      # TODO(crbug.com/929645): Use newer toolchain to host.
                      '-DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON',
+                     '-DBUG_REPORT_URL=' + BUG_REPORT_URL,
                      ]
 
   if sys.platform != 'win32':
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index f0ada6c..7826963 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -399,9 +399,9 @@
       ('infra/tools/luci/logdog/butler/${platform}',
        'git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c'),
       ('infra/tools/luci/vpython-native/${platform}',
-       'git_revision:0bff6ebf817352838b0e6f65fd6460b38c505c9c'),
+       'git_revision:cc09450f1c27c0034ec08b1f6d63bbc298294763'),
       ('infra/tools/luci/vpython/${platform}',
-       'git_revision:0bff6ebf817352838b0e6f65fd6460b38c505c9c'),
+       'git_revision:cc09450f1c27c0034ec08b1f6d63bbc298294763'),
     ]
     for pkg, vers in cipd_packages:
       cmd.append('--cipd-package=.swarming_module:%s:%s' % (pkg, vers))
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 8c10582..12a060c 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -569,7 +569,6 @@
     'chromium.webrtc': {
       'WebRTC Chromium Android Builder': 'android_debug_static_bot_arm64',
       'WebRTC Chromium Linux Builder': 'gpu_tests_release_bot',
-      'WebRTC Chromium Linux Builder (RBE)': 'gpu_tests_release_bot',
       'WebRTC Chromium Mac Builder': 'gpu_tests_release_bot',
       'WebRTC Chromium Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks_with_codecs',
     },
@@ -579,9 +578,7 @@
       'WebRTC Chromium FYI Android Builder (dbg)': 'android_debug_static_bot',
       'WebRTC Chromium FYI Android Builder ARM64 (dbg)': 'android_debug_static_bot_arm64',
       'WebRTC Chromium FYI Linux Builder': 'gpu_tests_release_bot',
-      'WebRTC Chromium FYI Linux Builder (RBE)': 'gpu_tests_release_bot',
       'WebRTC Chromium FYI Linux Builder (dbg)': 'debug_bot',
-      'WebRTC Chromium FYI Linux Builder (dbg) (RBE)': 'debug_bot',
       'WebRTC Chromium FYI Mac Builder': 'gpu_tests_release_bot',
       'WebRTC Chromium FYI Mac Builder (dbg)': 'debug_bot',
       'WebRTC Chromium FYI Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks_with_codecs',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 28782f2..f727156 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -6881,6 +6881,40 @@
   <int value="10" label="Image was not required for activation."/>
 </enum>
 
+<enum name="ChromeBrowsingDataRemoverTasks">
+  <int value="1" label="kSynchronous"/>
+  <int value="2" label="kHistory"/>
+  <int value="3" label="kHostNameResolution"/>
+  <int value="4" label="kNaclCache"/>
+  <int value="5" label="kPnaclCache"/>
+  <int value="6" label="kAutofillData"/>
+  <int value="7" label="kAutofillOrigins"/>
+  <int value="8" label="kPluginData"/>
+  <int value="9" label="kFlashLsoHelper"/>
+  <int value="10" label="kDomainReliability"/>
+  <int value="11" label="kNetworkPredictor"/>
+  <int value="12" label="kWebrtcLogs"/>
+  <int value="13" label="kVideoDecodeHistory"/>
+  <int value="14" label="kCookies"/>
+  <int value="15" label="kPasswords"/>
+  <int value="16" label="kHttpAuthCache"/>
+  <int value="17" label="kDisableAutoSignin"/>
+  <int value="18" label="kPasswordsStatistics"/>
+  <int value="19" label="kKeywordsModel"/>
+  <int value="20" label="kReportingCache"/>
+  <int value="21" label="kNetworkErrorLogging"/>
+  <int value="22" label="kFlashDeauthorization"/>
+  <int value="23" label="kOfflinePages"/>
+  <int value="24" label="kPrecache"/>
+  <int value="25" label="kExploreSites"/>
+  <int value="26" label="kLegacyStrikes"/>
+  <int value="27" label="kWebrtcEventLogs"/>
+  <int value="28" label="kDrmLicenses"/>
+  <int value="29" label="kHostCache"/>
+  <int value="30" label="kTpmAttestationKeys"/>
+  <int value="31" label="kStrikes"/>
+</enum>
+
 <enum name="ChromeChannelForHistogram">
   <int value="0" label="UNKNOWN"/>
   <int value="1" label="CANARY"/>
@@ -16517,6 +16551,7 @@
   <int value="550" label="DeviceBatteryChargeMode"/>
   <int value="551" label="DeviceBatteryChargeCustomStartCharging"/>
   <int value="552" label="DeviceBatteryChargeCustomStopCharging"/>
+  <int value="553" label="DeviceUsbPowerShareEnabled"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -22826,6 +22861,7 @@
   <int value="45" label="UnoptimizedLossyImages"/>
   <int value="46" label="UnoptimizedLosslessImages"/>
   <int value="47" label="UnoptimizedLosslessImagesStrict"/>
+  <int value="48" label="LoadingFrameDefaultEager"/>
 </enum>
 
 <enum name="FeedbackSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b14fc83d..42eedab 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -43442,6 +43442,16 @@
   </summary>
 </histogram>
 
+<histogram name="History.ClearBrowsingData.Duration.SlowTasks180sChrome"
+    enum="ChromeBrowsingDataRemoverTasks">
+  <owner>dullweber@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <summary>
+    Record tasks from ChromeBrowsingDataRemoverDelegate that took more than 180s
+    to finish.
+  </summary>
+</histogram>
+
 <histogram
     name="History.ClearBrowsingData.HistoryNoticeShownInFooterWhenUpdated"
     enum="BooleanShown">
@@ -129620,7 +129630,10 @@
 </histogram>
 
 <histogram name="UMA.FileMetricsProvider.EmbeddedProfile.DroppedHistogramCount"
-    expires_after="M80">
+    expires_after="M75">
+  <obsolete>
+    Removed 2019/04 with the resolution of https://crbug.com/695880
+  </obsolete>
   <owner>asvitkine@chromium.org</owner>
   <owner>bcwhite@chromium.org</owner>
   <summary>
@@ -129643,7 +129656,10 @@
 </histogram>
 
 <histogram name="UMA.FileMetricsProvider.EmbeddedProfileResult"
-    enum="FileMetricsProviderEmbeddedProfileResult" expires_after="M80">
+    enum="FileMetricsProviderEmbeddedProfileResult" expires_after="M75">
+  <obsolete>
+    Removed 2019/04 with the resolution of https://crbug.com/695880
+  </obsolete>
   <owner>asvitkine@chromium.org</owner>
   <owner>bcwhite@chromium.org</owner>
   <summary>
diff --git a/tools/variations/fieldtrial_to_struct.py b/tools/variations/fieldtrial_to_struct.py
index 20a12f1..41128753 100755
--- a/tools/variations/fieldtrial_to_struct.py
+++ b/tools/variations/fieldtrial_to_struct.py
@@ -32,12 +32,22 @@
   'windows',
 ]
 
+_form_factors = [
+  'desktop',
+  'phone',
+  'tablet',
+]
+
 # Convert a platform argument to the matching Platform enum value in
 # components/variations/proto/study.proto.
 def _PlatformEnumValue(platform):
   assert platform in _platforms
   return 'Study::PLATFORM_' + platform.upper()
 
+def _FormFactorEnumValue(form_factor):
+  assert form_factor in _form_factors
+  return 'Study::' + form_factor.upper()
+
 def _Load(filename):
   """Loads a JSON file into a Python object and return this object.
   """
@@ -51,11 +61,15 @@
   """
   return _FieldTrialConfigToDescription(_Load(filename), platforms)
 
-def _CreateExperiment(experiment_data, platforms, is_low_end_device):
+def _CreateExperiment(experiment_data,
+                      platforms,
+                      is_low_end_device,
+                      form_factors):
   experiment = {
     'name': experiment_data['name'],
     'platforms': [_PlatformEnumValue(p) for p in platforms],
-    'is_low_end_device': is_low_end_device
+    'is_low_end_device': is_low_end_device,
+    'form_factors': [_FormFactorEnumValue(f) for f in form_factors],
   }
   forcing_flags_data = experiment_data.get('forcing_flag')
   if forcing_flags_data:
@@ -89,7 +103,10 @@
 
     if platform_intersection:
       experiments += [_CreateExperiment(
-                          e, platform_intersection, is_low_end_device)
+                          e,
+                          platform_intersection,
+                          is_low_end_device,
+                          config.get('form_factors', []))
                       for e in config['experiments']]
   return {
     'name': study_name,
diff --git a/tools/variations/fieldtrial_to_struct_unittest.py b/tools/variations/fieldtrial_to_struct_unittest.py
index 4f0c443..4314b94 100644
--- a/tools/variations/fieldtrial_to_struct_unittest.py
+++ b/tools/variations/fieldtrial_to_struct_unittest.py
@@ -80,7 +80,8 @@
                   ],
                   'enable_features': ['A', 'B'],
                   'disable_features': ['C'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': [],
                 },
                 {
                   'name': 'Group2',
@@ -91,7 +92,8 @@
                   ],
                   'enable_features': ['D', 'E'],
                   'disable_features': ['F'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': [],
                 },
               ],
             },
@@ -101,7 +103,8 @@
                 {
                   'name': 'OtherGroup',
                   'platforms': ['Study::PLATFORM_WINDOWS'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': [],
                 }
               ]
             },
@@ -112,7 +115,8 @@
                     'name': 'ForcedGroup',
                     'platforms': ['Study::PLATFORM_WINDOWS'],
                     'forcing_flag': "my-forcing-flag",
-                    'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING'
+                    'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                    'form_factors': [],
                   }
               ]
             },
@@ -185,7 +189,8 @@
                   ],
                   'enable_features': ['A', 'B'],
                   'disable_features': ['C'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_TRUE'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_TRUE',
+                  'form_factors': [],
                 },
                 {
                   'name': 'Group2',
@@ -196,12 +201,14 @@
                   ],
                   'enable_features': ['D', 'E'],
                   'disable_features': ['F'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_TRUE'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_TRUE',
+                  'form_factors': [],
                 },
                 {
                   'name': 'IOSOnly',
                   'platforms': ['Study::PLATFORM_IOS'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': [],
                 },
               ],
             },
@@ -225,7 +232,61 @@
                 {
                   'name': 'OtherGroup',
                   'platforms': ['Study::PLATFORM_MAC'],
-                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING'
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': [],
+                },
+              ],
+            },
+          ]
+        }
+      }
+    }
+    self.maxDiff = None
+    self.assertEqual(expected, result)
+
+  _MULTIPLE_FORM_FACTORS_CONFIG = {
+      'Trial1': [
+        {
+          'platforms': ['windows'],
+          'form_factors': ['desktop', 'phone'],
+          'experiments': [{'name': 'Group1'}]
+        }
+      ],
+      'Trial2': [
+        {
+          'platforms': ['windows'],
+          'form_factors': ['tablet'],
+          'experiments': [{'name': 'OtherGroup'}]
+        }
+      ]
+    }
+
+  def test_FieldTrialToDescriptionMultipleFormFactorsTrial(self):
+    result = fieldtrial_to_struct._FieldTrialConfigToDescription(
+        self._MULTIPLE_FORM_FACTORS_CONFIG, ['windows'])
+    expected = {
+      'elements': {
+        'kFieldTrialConfig': {
+          'studies': [
+            {
+              'name': 'Trial1',
+              'experiments': [
+                {
+                  'name': 'Group1',
+                  'platforms': ['Study::PLATFORM_WINDOWS'],
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': ['Study::DESKTOP', 'Study::PHONE'],
+                },
+              ],
+            },
+            {
+              'name': 'Trial2',
+              'experiments': [
+                {
+                  'name': 'OtherGroup',
+                  'platforms': ['Study::PLATFORM_WINDOWS'],
+                  'is_low_end_device': 'Study::OPTIONAL_BOOL_MISSING',
+                  'form_factors': ['Study::TABLET'],
                 },
               ],
             },
diff --git a/tools/variations/unittest_data/expected_output.cc b/tools/variations/unittest_data/expected_output.cc
index b51ac07..933ab9e2 100644
--- a/tools/variations/unittest_data/expected_output.cc
+++ b/tools/variations/unittest_data/expected_output.cc
@@ -10,6 +10,53 @@
 #include "test_output.h"
 
 
+const Study::FormFactor array_kFieldTrialConfig_form_factors_7[] = {
+      Study::TABLET,
+};
+const Study::Platform array_kFieldTrialConfig_platforms_7[] = {
+      Study::PLATFORM_WINDOWS,
+};
+const Study::FormFactor array_kFieldTrialConfig_form_factors_6[] = {
+      Study::DESKTOP,
+      Study::PHONE,
+};
+const Study::Platform array_kFieldTrialConfig_platforms_6[] = {
+      Study::PLATFORM_WINDOWS,
+};
+const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_4[] = {
+    {
+      "TestGroup1",
+      array_kFieldTrialConfig_platforms_6,
+      1,
+      array_kFieldTrialConfig_form_factors_6,
+      2,
+      Study::OPTIONAL_BOOL_MISSING,
+      NULL,
+      0,
+      NULL,
+      0,
+      NULL,
+      0,
+      NULL,
+    },
+    {
+      "TestGroup2",
+      array_kFieldTrialConfig_platforms_7,
+      1,
+      array_kFieldTrialConfig_form_factors_7,
+      1,
+      Study::OPTIONAL_BOOL_MISSING,
+      NULL,
+      0,
+      NULL,
+      0,
+      NULL,
+      0,
+      NULL,
+    },
+};
+const Study::FormFactor array_kFieldTrialConfig_form_factors_5[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms_5[] = {
       Study::PLATFORM_WINDOWS,
 };
@@ -18,6 +65,8 @@
       "ForcedGroup",
       array_kFieldTrialConfig_platforms_5,
       1,
+      array_kFieldTrialConfig_form_factors_5,
+      0,
       Study::OPTIONAL_BOOL_MISSING,
       NULL,
       0,
@@ -28,9 +77,13 @@
       "my-forcing-flag",
     },
 };
+const Study::FormFactor array_kFieldTrialConfig_form_factors_4[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms_4[] = {
       Study::PLATFORM_WINDOWS,
 };
+const Study::FormFactor array_kFieldTrialConfig_form_factors_3[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms_3[] = {
       Study::PLATFORM_WINDOWS,
 };
@@ -39,6 +92,8 @@
       "TestGroup1",
       array_kFieldTrialConfig_platforms_3,
       1,
+      array_kFieldTrialConfig_form_factors_3,
+      0,
       Study::OPTIONAL_BOOL_TRUE,
       NULL,
       0,
@@ -52,6 +107,8 @@
       "TestGroup2",
       array_kFieldTrialConfig_platforms_4,
       1,
+      array_kFieldTrialConfig_form_factors_4,
+      0,
       Study::OPTIONAL_BOOL_FALSE,
       NULL,
       0,
@@ -65,6 +122,8 @@
 const char* const array_kFieldTrialConfig_enable_features_1[] = {
       "X",
 };
+const Study::FormFactor array_kFieldTrialConfig_form_factors_2[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms_2[] = {
       Study::PLATFORM_WINDOWS,
 };
@@ -73,6 +132,8 @@
       "TestGroup3",
       array_kFieldTrialConfig_platforms_2,
       1,
+      array_kFieldTrialConfig_form_factors_2,
+      0,
       Study::OPTIONAL_BOOL_MISSING,
       NULL,
       0,
@@ -100,6 +161,8 @@
         "4",
       },
 };
+const Study::FormFactor array_kFieldTrialConfig_form_factors_1[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms_1[] = {
       Study::PLATFORM_WINDOWS,
 };
@@ -120,6 +183,8 @@
         "2",
       },
 };
+const Study::FormFactor array_kFieldTrialConfig_form_factors_0[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms_0[] = {
       Study::PLATFORM_WINDOWS,
 };
@@ -128,6 +193,8 @@
       "TestGroup2",
       array_kFieldTrialConfig_platforms_0,
       1,
+      array_kFieldTrialConfig_form_factors_0,
+      0,
       Study::OPTIONAL_BOOL_MISSING,
       array_kFieldTrialConfig_params,
       2,
@@ -141,6 +208,8 @@
       "TestGroup2-2",
       array_kFieldTrialConfig_platforms_1,
       1,
+      array_kFieldTrialConfig_form_factors_1,
+      0,
       Study::OPTIONAL_BOOL_MISSING,
       array_kFieldTrialConfig_params_0,
       2,
@@ -151,6 +220,8 @@
       NULL,
     },
 };
+const Study::FormFactor array_kFieldTrialConfig_form_factors[] = {
+};
 const Study::Platform array_kFieldTrialConfig_platforms[] = {
       Study::PLATFORM_WINDOWS,
 };
@@ -159,6 +230,8 @@
       "TestGroup1",
       array_kFieldTrialConfig_platforms,
       1,
+      array_kFieldTrialConfig_form_factors,
+      0,
       Study::OPTIONAL_BOOL_MISSING,
       NULL,
       0,
@@ -195,8 +268,13 @@
     array_kFieldTrialConfig_experiments_3,
     1,
   },
+  {
+    "TrialWithFormFactors",
+    array_kFieldTrialConfig_experiments_4,
+    2,
+  },
 };
 const FieldTrialTestingConfig kFieldTrialConfig = {
   array_kFieldTrialConfig_studies,
-  5,
+  6,
 };
diff --git a/tools/variations/unittest_data/expected_output.h b/tools/variations/unittest_data/expected_output.h
index 8db61103..e01eee7c 100644
--- a/tools/variations/unittest_data/expected_output.h
+++ b/tools/variations/unittest_data/expected_output.h
@@ -23,6 +23,8 @@
   const char* const name;
   const Study::Platform * platforms;
   const size_t platforms_size;
+  const Study::FormFactor * form_factors;
+  const size_t form_factors_size;
   const Study::OptionalBool is_low_end_device;
   const FieldTrialTestingExperimentParams * params;
   const size_t params_size;
diff --git a/tools/variations/unittest_data/test_config.json b/tools/variations/unittest_data/test_config.json
index 525f63e6..8b34c79 100644
--- a/tools/variations/unittest_data/test_config.json
+++ b/tools/variations/unittest_data/test_config.json
@@ -58,5 +58,17 @@
       "is_low_end_device": false,
       "experiments": [{"name": "TestGroup2"}]
     }
+  ],
+  "TrialWithFormFactors": [
+    {
+      "platforms": ["windows"],
+      "form_factors": ["desktop", "phone"],
+      "experiments": [{"name": "TestGroup1"}]
+    },
+    {
+      "platforms": ["windows"],
+      "form_factors": ["tablet"],
+      "experiments": [{"name": "TestGroup2"}]
+    }
   ]
 }
diff --git a/tools/win/DebugVisualizers/BUILD.gn b/tools/win/DebugVisualizers/BUILD.gn
index cdd7a23..ddbb8e6 100644
--- a/tools/win/DebugVisualizers/BUILD.gn
+++ b/tools/win/DebugVisualizers/BUILD.gn
@@ -24,6 +24,10 @@
   ldflags = [ "/NATVIS:" + rebase_path("chrome.natvis", root_build_dir) ]
 }
 
+config("libc++") {
+  ldflags = [ "/NATVIS:" + rebase_path("libc++.natvis", root_build_dir) ]
+}
+
 config("skia") {
   ldflags = [ "/NATVIS:" + rebase_path("skia.natvis", root_build_dir) ]
 }
diff --git a/tools/win/DebugVisualizers/libc++.natvis b/tools/win/DebugVisualizers/libc++.natvis
new file mode 100644
index 0000000..ae5101dd3
--- /dev/null
+++ b/tools/win/DebugVisualizers/libc++.natvis
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<AutoVisualizer
+  xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+
+  <!--libc++'s short string optimization:
+      A basic_string is 3 size_t words long. In the "alternate string layout" that we use,
+      they are: pointer to data, size, capacity.
+      (In the normal layout, it's capacity, size, data instead.)
+      If a string is short enough that it fits in these three size_ts instead,
+      the string data is stored inline in these 3 words, with the last byte of
+      the storage storing the length of the string.
+      The highest bit of the "capacity" word is set for normal, "long" strings,
+      and that bit needs to be masked out to know the real capacity.
+      If this bit is not set, the string data is stored inline.
+      (In the normal layout, if the lowest bit in the first byte is set,
+      it's a "long" string, requiring a long string to always have even
+      capacity. A short string here stores its length in the first byte
+      and the inline data in the remaining storage.)
+  -->
+
+  <Type Name="std::__1::basic_string&lt;char,*&gt;">
+    <!--<Intrinsic Name="is_long"
+            Expression="((__rep*)&amp;__r_)-&gt;__s.__size_ &amp; 0x80" />-->
+    <!-- The above doesn't work for reasons I don't understand.
+         The below assumes the alternate string layout and little endianness :/
+    -->
+    <Intrinsic Name="is_long"
+        Expression="*(((char*)this) + 3*sizeof(size_t) - 1) &amp; 0x80" />
+    <DisplayString Condition="is_long()">{*(char**)this}</DisplayString>
+    <DisplayString Condition="!is_long()">{(char*)this}</DisplayString>
+    <StringView Condition="is_long()">*(char**)this</StringView>
+    <StringView Condition="!is_long()">(char*)this</StringView>
+    <Expand>
+      <Item Name="[size]" Condition="is_long()"
+          ExcludeView="simple">((size_t*)this)[1]</Item>
+      <Item Name="[size]" Condition="!is_long()"
+          ExcludeView="simple">*(((char*)this) + 3*sizeof(size_t) - 1)</Item>
+      <Item Name="[capacity]" Condition="is_long()" ExcludeView="simple">
+        ((size_t*)this)[2] &amp; (~((size_t)0) &gt;&gt; 1)
+      </Item>
+      <Item Name="[capacity]" Condition="!is_long()"
+          ExcludeView="simple">22</Item>
+      <ArrayItems>
+        <Size Condition="is_long()">((size_t*)this)[1]</Size>
+        <Size Condition="!is_long()">
+          *(((char*)this) + 3*sizeof(size_t) - 1)
+        </Size>
+        <ValuePointer Condition="is_long()">*(char**)this</ValuePointer>
+        <ValuePointer Condition="!is_long()">(char*)this</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+
+  <Type Name="std::__1::basic_string&lt;wchar_t,*&gt;">
+    <Intrinsic Name="is_long"
+        Expression="*(((char*)this) + 3*sizeof(size_t) - 1) &amp; 0x80" />
+    <DisplayString Condition="is_long()">{*(wchar_t**)this}</DisplayString>
+    <DisplayString Condition="!is_long()">{(wchar_t*)this}</DisplayString>
+    <StringView Condition="is_long()">*(wchar_t**)this</StringView>
+    <StringView Condition="!is_long()">(wchar_t*)this</StringView>
+    <Expand>
+      <Item Name="[size]" Condition="is_long()"
+          ExcludeView="simple">((size_t*)this)[1]</Item>
+      <Item Name="[size]" Condition="!is_long()"
+          ExcludeView="simple">*(((char*)this) + 3*sizeof(size_t) - 1)</Item>
+      <Item Name="[capacity]" Condition="is_long()" ExcludeView="simple">
+        ((size_t*)this)[2] &amp; (~((size_t)0) &gt;&gt; 1)
+      </Item>
+      <Item Name="[capacity]" Condition="!is_long()"
+          ExcludeView="simple">10</Item>
+      <ArrayItems>
+        <Size Condition="is_long()">((size_t*)this)[1]</Size>
+        <Size Condition="!is_long()">
+          *(((char*)this) + 3*sizeof(size_t) - 1)
+        </Size>
+        <ValuePointer Condition="is_long()">*(wchar_t**)this</ValuePointer>
+        <ValuePointer Condition="!is_long()">(wchar_t*)this</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+
+  <Type Name="std::__1::vector&lt;*&gt;">
+    <Intrinsic Name="size" Expression="__end_ - __begin_" />
+    <Expand>
+      <ArrayItems>
+        <Size>size()</Size>
+        <ValuePointer>__begin_</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+</AutoVisualizer>
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index 8411c04..25f4f634 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -113,11 +113,21 @@
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_TEXTRANGE_EXPANDTOENCLOSINGUNIT);
   UIA_VALIDATE_TEXTRANGEPROVIDER_CALL();
 
-  // Determine if start is on a TextUnit boundary.
-  // If it is not, move backwards until it is.
-  // Try to move backwards, do not pass boundary.
+  // Determine if start is on a TextUnit boundary. If it is not, move backwards
+  // until it is. Move the end forwards from start until it is on the next
+  // TextUnit boundary, if one exists.
   switch (unit) {
-    case TextUnit_Character:
+    case TextUnit_Character: {
+      // For characters, start_ will always be on a TextUnit boundary. Thus,
+      // end_ is the only position that needs to be moved.
+      AXNodePosition::AXPositionInstance next =
+          start_->CreateNextCharacterPosition(
+              ui::AXBoundaryBehavior::CrossBoundary);
+      if (!next->IsNullPosition()) {
+        end_ = next->Clone();
+      }
+      break;
+    }
     case TextUnit_Format:
     case TextUnit_Word:
     case TextUnit_Paragraph:
@@ -129,10 +139,12 @@
     case TextUnit_Document:
       start_ = start_->CreatePositionAtStartOfDocument()->AsLeafTextPosition();
       end_ = start_->CreatePositionAtEndOfDocument();
-      return S_OK;
+      break;
     default:
       return UIA_E_NOTSUPPORTED;
   }
+
+  return S_OK;
 }
 
 STDMETHODIMP AXPlatformNodeTextRangeProviderWin::FindAttribute(
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index b79fac73..9d047706 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -401,6 +401,117 @@
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
+       TestITextRangeProviderExpandToEnclosingCharacter) {
+  ui::AXNodeData text_data;
+  text_data.id = 2;
+  text_data.role = ax::mojom::Role::kStaticText;
+  text_data.SetName("some text");
+
+  ui::AXNodeData more_text_data;
+  more_text_data.id = 3;
+  more_text_data.role = ax::mojom::Role::kStaticText;
+  more_text_data.SetName("more text");
+
+  ui::AXNodeData root_data;
+  root_data.id = 1;
+  root_data.role = ax::mojom::Role::kRootWebArea;
+  root_data.child_ids = {2, 3};
+
+  ui::AXTreeUpdate update;
+  ui::AXTreeData tree_data;
+  tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  update.tree_data = tree_data;
+  update.has_tree_data = true;
+  update.root_id = root_data.id;
+  update.nodes.push_back(root_data);
+  update.nodes.push_back(text_data);
+  update.nodes.push_back(more_text_data);
+
+  Init(update);
+
+  AXNode* root_node = GetRootNode();
+  AXNodePosition::SetTreeForTesting(tree_.get());
+
+  ComPtr<IRawElementProviderSimple> root_node_raw =
+      QueryInterfaceFromNode<IRawElementProviderSimple>(root_node);
+
+  ComPtr<ITextProvider> text_provider;
+  EXPECT_HRESULT_SUCCEEDED(
+      root_node_raw->GetPatternProvider(UIA_TextPatternId, &text_provider));
+
+  ComPtr<ITextRangeProvider> text_range_provider;
+  EXPECT_HRESULT_SUCCEEDED(
+      text_provider->get_DocumentRange(&text_range_provider));
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->ExpandToEnclosingUnit(TextUnit_Character));
+
+  base::win::ScopedBstr text_content;
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->GetText(-1, text_content.Receive()));
+  EXPECT_STREQ(L"s", text_content);
+  text_content.Reset();
+
+  int count;
+  ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+      TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 2, &count));
+  ASSERT_EQ(2, count);
+  ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+      TextPatternRangeEndpoint_Start, TextUnit_Character, /*count*/ 1, &count));
+  ASSERT_EQ(1, count);
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->GetText(-1, text_content.Receive()));
+  EXPECT_STREQ(L"om", text_content);
+  text_content.Reset();
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->ExpandToEnclosingUnit(TextUnit_Character));
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->GetText(-1, text_content.Receive()));
+  EXPECT_STREQ(L"o", text_content);
+  text_content.Reset();
+
+  ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+      TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 10, &count));
+  ASSERT_EQ(10, count);
+  ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+      TextPatternRangeEndpoint_Start, TextUnit_Character, /*count*/ 9, &count));
+  ASSERT_EQ(9, count);
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->GetText(-1, text_content.Receive()));
+  EXPECT_STREQ(L"mo", text_content);
+  text_content.Reset();
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->ExpandToEnclosingUnit(TextUnit_Character));
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->GetText(-1, text_content.Receive()));
+  EXPECT_STREQ(L"m", text_content);
+  text_content.Reset();
+
+  // Move the start and end to the end of the document.
+  // Expand to enclosing unit should never return a null position.
+  ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+      TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 9, &count));
+  ASSERT_EQ(8, count);
+  ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+      TextPatternRangeEndpoint_Start, TextUnit_Character, /*count*/ 9, &count));
+  ASSERT_EQ(9, count);
+
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->ExpandToEnclosingUnit(TextUnit_Character));
+  ASSERT_HRESULT_SUCCEEDED(
+      text_range_provider->GetText(-1, text_content.Receive()));
+  EXPECT_STREQ(L"", text_content);
+  text_content.Reset();
+
+  AXNodePosition::SetTreeForTesting(nullptr);
+}
+
+TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingDocument) {
   Init(BuildTextDocument({"some text", "more text", "even more text"}));
   AXNodePosition::SetTreeForTesting(tree_.get());
@@ -434,6 +545,7 @@
     EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
                             L"some textmore texteven more text");
   }
+  AXNodePosition::SetTreeForTesting(nullptr);
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
diff --git a/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java b/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
index f41bf20f..b8b084b 100644
--- a/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
+++ b/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
@@ -108,34 +108,6 @@
     }
 
     /**
-     * Return one default locale-specific PAK file name associated with a given language.
-     *
-     * @param language Language name (e.g. "en").
-     * @return A Chromium-specific locale name (e.g. "en-US") matching the input language
-     *         that can be used to access compressed locale pak files.
-     */
-    public static String getDefaultCompressedPakLocaleForLanguage(String language) {
-        // IMPORTANT: Keep in sync with the mapping found in:
-        // //build/android/gyp/resource_utils.py
-
-        // NOTE: All languages provide locale files named '<language>.pak', except
-        //       for a few exceptions listed below. E.g. for the English language,
-        //       the 'en-US.pak' and 'en-GB.pak' files are provided, and there is
-        //       no 'en.pak' file.
-        switch (language) {
-            case "en":
-                return "en-US";
-            case "pt":
-                return "pt-PT";
-            case "zh":
-                return "zh-CN";
-            default:
-                // NOTE: for Spanish (es), both es.pak and es-419.pak are used. Hence this works.
-                return language;
-        }
-    }
-
-    /**
      * Return true iff a locale string matches a specific language string.
      *
      * @param locale Chromium locale name (e.g. "fil", or "en-US").
diff --git a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
index 25aef12..69f7f4c 100644
--- a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
+++ b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
@@ -4,10 +4,17 @@
 
 package org.chromium.ui.base;
 
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+
 import org.chromium.base.BuildConfig;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.LocaleUtils;
+import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
+import java.io.IOException;
 import java.util.Arrays;
 
 /**
@@ -18,10 +25,51 @@
 final class ResourceBundle {
     private ResourceBundle() {}
 
+    private static final String TAG = "ResourceBundle";
+
+    /**
+     * Return the location of a locale-specific uncompress .pak file asset.
+     *
+     * @param locale Chromium locale name.
+     * @param inBundle If true, return the path of the uncompressed .pak file
+     *                 containing Chromium UI strings within app bundles. If
+     *                 false, return the path of the uncompressed WebView UI
+     *                 strings instead. Note that APK .pak files are stored
+     *                 compressed and handled differently.
+     * @return Asset path to uncompressed .pak file, or null if the locale is
+     *         not supported by this version of Chromium, or the file is
+     *         missing.
+     */
     @CalledByNative
-    private static String getLocalePakResourcePath(String locale) {
-        if (Arrays.binarySearch(BuildConfig.UNCOMPRESSED_LOCALES, locale) >= 0) {
-            return "assets/stored-locales/" + locale + ".pak";
+    private static String getLocalePakResourcePath(String locale, boolean inBundle) {
+        if (Arrays.binarySearch(BuildConfig.UNCOMPRESSED_LOCALES, locale) < 0) {
+            // This locale is not supported by Chromium.
+            return null;
+        }
+        String pathPrefix = "assets/stored-locales/";
+        if (inBundle) {
+            if (locale.equals("en-US")) {
+                pathPrefix = "assets/fallback-locales/";
+            } else {
+                String lang = LocalizationUtils.getSplitLanguageForAndroid(
+                        LocaleUtils.toLanguage(locale));
+                pathPrefix = "assets/locales#lang_" + lang + "/";
+            }
+        }
+        String assetPath = pathPrefix + locale + ".pak";
+        AssetManager manager = ContextUtils.getApplicationContext().getAssets();
+        try (AssetFileDescriptor afd = manager.openNonAssetFd(assetPath)) {
+            return assetPath;
+        } catch (IOException e) {
+            // It makes sense to log here when the file exists, but is unable to be opened as an fd
+            // because (for example) it is unexpectedly compressed in an apk. In that case, the log
+            // message might save someone some time working out what has gone wrong.
+            // For that reason, we only suppress the message when the exception message doesn't look
+            // informative (Android framework passes the filename as the message on actual file not
+            // found, and the empty string also wouldn't give any useful information for debugging)
+            if (!e.getMessage().equals("") && !e.getMessage().equals(assetPath)) {
+                Log.e(TAG, "Error while loading asset %s: %s", assetPath, e);
+            }
         }
         return null;
     }
diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java b/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
index 123c8f1f..75370d6 100644
--- a/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
+++ b/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
@@ -39,8 +39,8 @@
     private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
     private static final String FALLBACK_LOCALE = "en-US";
     private static final String COMPRESSED_LOCALES_DIR = "locales";
-    private static final String COMPRESSED_LOCALES_FALLBACK_DIR = "fallback-locales";
     private static final int BUFFER_SIZE = 16 * 1024;
+    private static final boolean DEBUG = false;
 
     private class ExtractTask implements Runnable {
         private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
@@ -159,8 +159,10 @@
         // NOTE: The UI language will differ from the application's language
         // when the system locale is not directly supported by Chrome's
         // resources.
-        Log.i(TAG, "Using UI locale %s, system locale: %s (Android name: %s)", uiLanguage,
-                chromiumLanguage, androidLanguage);
+        if (DEBUG) {
+            Log.i(TAG, "Using UI language %s, system language: %s (Android name: %s)", uiLanguage,
+                    chromiumLanguage, androidLanguage);
+        }
 
         // Currenty (Apr 2018), this array can be as big as 6 entries, so using a capacity
         // that allows a bit of growth, but is still in the right ballpark..
@@ -176,64 +178,35 @@
             activeLocales.add(FALLBACK_LOCALE);
         }
 
+        // * For bundles, locale pak files are always stored uncompressed
+        //   either under base.apk!/assets/fallback-locales/<locale>.pak or
+        //   base-<lang>.apk!/assets/locales#lang_<lang>/<locale>.pak. They
+        //   never need to be extracted.
+        //
         // * For regular APKs, the locale pak files are stored under:
         //      base.apk!/assets/locales/<locale>.pak
         //
         //   where <locale> is a Chromium-specific locale name.
         //
-        // * When using app bundles, the locale pak files are stored in
-        //   language-specific directories that look like:
-        //      <split>.apk!/assets/locales#lang_<lang>/<locale>.pak
-        //
-        //   Where <lang> is an Android-specific ISO-639-1 language identifier.
-        //
-        // * With the exception of the fallback (English) pak files which are stored
-        //   in the base module under:
-        //       assets/locales-fallback/<locale>.pak
-        //
-        //   Moreover, when the bundle uses APK splits, there is no guarantee that the split
-        //   corresponding to the current device locale is installed yet, but the one matching
-        //   uiLanguage should be there, since the value is determined by loading a resource string
-        //   from the current application's asset manager.
-        //
         AssetManager assetManager = ContextUtils.getApplicationAssets();
-        String localesSrcDir;
-        String androidSplitLanguage = LocalizationUtils.getSplitLanguageForAndroid(uiLanguage);
-        String langSpecificPath = COMPRESSED_LOCALES_DIR + "#lang_" + androidSplitLanguage;
-        String defaultLocalePakName =
-                LocalizationUtils.getDefaultCompressedPakLocaleForLanguage(uiLanguage) + ".pak";
-
-        if (assetPathHasFile(assetManager, langSpecificPath, defaultLocalePakName)) {
-            // This is an app bundle, and the split containing the pak files for
-            // the current locale is installed.
-            localesSrcDir = langSpecificPath;
-        } else if (assetPathHasFile(
-                           assetManager, COMPRESSED_LOCALES_DIR, activeLocales.get(0) + ".pak")) {
-            // This is a regular APK, and all pak files are available.
-            localesSrcDir = COMPRESSED_LOCALES_DIR;
-        } else if (assetPathHasFile(assetManager, COMPRESSED_LOCALES_FALLBACK_DIR,
-                           activeLocales.get(0) + ".pak")) {
-            // This is a fallback language pak file.
-            localesSrcDir = COMPRESSED_LOCALES_FALLBACK_DIR;
-        } else {
-            // This is an app bundle, but the split containing the pak files for the current UI
-            // locale is *not* installed yet. This should never happen in theory, and there is
-            // little that can be done at this point, so return an empty list. Nothing will get
-            // extracted, and Chromium may later crash when trying to access the PAK file from
-            // native code.
-            Log.e(TAG, "Android Locale: %s misses split for .pak files: %s", defaultLocale,
-                    Arrays.toString(activeLocales.toArray()));
+        if (!assetPathHasFile(
+                    assetManager, COMPRESSED_LOCALES_DIR, activeLocales.get(0) + ".pak")) {
+            if (DEBUG) {
+                Log.i(TAG, "No locale pak files to extract, assuming app bundle.");
+            }
             return new String[] {};
         }
 
+        // This is a regular APK, and all pak files are available.
         // Return the list of locale pak file paths corresponding to the current language.
         String[] localePakFiles = new String[activeLocales.size()];
         for (int n = 0; n < activeLocales.size(); ++n) {
-            localePakFiles[n] = localesSrcDir + '/' + activeLocales.get(n) + ".pak";
+            localePakFiles[n] = COMPRESSED_LOCALES_DIR + '/' + activeLocales.get(n) + ".pak";
         }
-        Log.i(TAG, "Using app bundle locale directory: " + localesSrcDir);
-        Log.i(TAG, "UI Language: %s requires .pak files: %s", uiLanguage,
-                Arrays.toString(activeLocales.toArray()));
+        if (DEBUG) {
+            Log.i(TAG, "UI Language '%s' will use %s.", uiLanguage,
+                    Arrays.toString(localePakFiles));
+        }
 
         return localePakFiles;
     }
@@ -252,10 +225,14 @@
         try {
             InputStream input = assetManager.open(assetFilePath);
             input.close();
-            Log.i(TAG, "Found asset file: " + assetFilePath);
+            if (DEBUG) {
+                Log.i(TAG, "Found asset file: " + assetFilePath);
+            }
             return true;
         } catch (IOException e) {
-            Log.i(TAG, "Missing asset file: " + assetFilePath);
+            if (DEBUG) {
+                Log.i(TAG, "No asset file at: " + assetFilePath);
+            }
             return false;
         }
     }
diff --git a/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java b/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java
index d061381..09724c4 100644
--- a/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java
+++ b/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java
@@ -24,16 +24,6 @@
 public class LocalizationUtilsTest {
     @Test
     @SmallTest
-    public void testGetDefaultCompressedPakLocaleForLanguage() {
-        assertEquals("fr", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("fr"));
-        assertEquals("es", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("es"));
-        assertEquals("en-US", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("en"));
-        assertEquals("pt-PT", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("pt"));
-        assertEquals("zh-CN", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("zh"));
-    }
-
-    @Test
-    @SmallTest
     public void testGetSplitLanguageForAndroid() {
         assertEquals("en", LocalizationUtils.getSplitLanguageForAndroid("en"));
         assertEquals("es", LocalizationUtils.getSplitLanguageForAndroid("es"));
diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc
index 899bb583..0b80d9c7 100644
--- a/ui/base/resource/resource_bundle_android.cc
+++ b/ui/base/resource/resource_bundle_android.cc
@@ -55,9 +55,10 @@
 }
 
 int LoadLocalePakFromApk(const std::string& app_locale,
+                         bool in_split,
                          base::MemoryMappedFile::Region* out_region) {
   std::string locale_path_within_apk =
-      GetPathForAndroidLocalePakWithinApk(app_locale);
+      GetPathForAndroidLocalePakWithinApk(app_locale, in_split);
   if (locale_path_within_apk.empty()) {
     LOG(WARNING) << "locale_path_within_apk.empty() for locale "
                  << app_locale;
@@ -107,8 +108,10 @@
 // static
 bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
   if (g_locale_paks_in_apk) {
-    return !GetPathForAndroidLocalePakWithinApk(locale).empty();
+    return !GetPathForAndroidLocalePakWithinApk(locale, false).empty();
   }
+  if (!GetPathForAndroidLocalePakWithinApk(locale, true).empty())
+    return true;
   return !GetLocaleFilePath(locale, true).empty();
 }
 
@@ -123,23 +126,75 @@
   }
   std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
 
+  // Some Chromium apps have two sets of .pak files for their UI strings, i.e.:
+  //
+  // a) WebView strings, which are always stored uncompressed under
+  //    assets/stored-locales/ inside the APK or App Bundle.
+  //
+  // b) For APKs, the Chrome UI strings are stored under assets/locales/
+  //    in compressed form. The relevant pak files is extracted on startup
+  //    and stored on the /data partition, with a version-specific suffix.
+  //
+  // c) For App Bundles, Chrome UI strings are stored uncompressed under
+  //    assets/locales#lang_<lang>/ (where <lang> is an Android language code)
+  //    and assets/fallback-locales/ (for en-US.pak only).
+  //
+  // Which .pak files to load are determined here by two global variables with
+  // the following meaning:
+  //
+  //  g_locale_paks_in_apk:
+  //    If true, load the WebView strings from stored-locales/<locale>.pak file
+  //    as the primary locale pak file.
+  //
+  //    If false, try to load it from the app bundle specific location
+  //    (e.g. locales#lang_<language>/<locale>.pak). If the latter does not
+  //    exist, try to lookup the extracted APK-specific locale .pak file
+  //    from /data/app/.../<locale>.pak@<version> instead.
+  //
+  //    g_locale_paks_in_apk is set by SetLocalePaksStoredInApk() which
+  //    is called from the WebView startup code.
+  //
+  //  g_load_secondary_locale_paks:
+  //    If true, load the Webview strings from stored-locales/<locale>.pak file
+  //    as the secondary locale pak file. Otherwise don't load a secondary
+  //    locale at all.
+  //
+  //    This is set by SetLoadSecondaryLocalePaks() which is called
+  //    during ChromeMainDelegate::PostEarlyInitialization() with a value
+  //    that is true iff there are stored-locale/ .pak files.
+  //
+  // In other words, if both |g_locale_paks_in_apk| and
+  // |g_load_secondary_locale_paks| are true, the stored-locales file will be
+  // loaded twice as both the primary and secondary. However, this should
+  // never happen in practice.
+
   // Load primary locale .pak file.
   if (g_locale_paks_in_apk) {
-    g_locale_pack_fd = LoadLocalePakFromApk(app_locale, &g_locale_pack_region);
+    g_locale_pack_fd =
+        LoadLocalePakFromApk(app_locale, false, &g_locale_pack_region);
   } else {
+    // Support overridden pak path for testing.
     base::FilePath locale_file_path = GetOverriddenPakPath();
-    if (locale_file_path.empty())
-      locale_file_path = GetLocaleFilePath(app_locale, true);
-
     if (locale_file_path.empty()) {
-      // It's possible that there is no locale.pak.
-      LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale;
-      LogLoadLocaleFailureReason(LoadFailureReason::kLocalePakNotFound);
-      return std::string();
+      // Try to find the uncompressed split-specific asset file.
+      g_locale_pack_fd =
+          LoadLocalePakFromApk(app_locale, true, &g_locale_pack_region);
     }
-    int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
-    g_locale_pack_fd = base::File(locale_file_path, flags).TakePlatformFile();
-    g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile;
+    if (g_locale_pack_fd < 0) {
+      // Otherwise, try to locate the extracted locale .pak file.
+      if (locale_file_path.empty())
+        locale_file_path = GetLocaleFilePath(app_locale, true);
+
+      if (locale_file_path.empty()) {
+        // It's possible that there is no locale.pak.
+        LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale;
+        LogLoadLocaleFailureReason(LoadFailureReason::kLocalePakNotFound);
+        return std::string();
+      }
+      int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
+      g_locale_pack_fd = base::File(locale_file_path, flags).TakePlatformFile();
+      g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile;
+    }
   }
 
   locale_resources_data_ = LoadDataPackFromLocalePak(
@@ -156,7 +211,7 @@
   // would have a copy of all the resources in the secondary locale pak.
   if (g_load_secondary_locale_paks) {
     g_secondary_locale_pack_fd = LoadLocalePakFromApk(
-        app_locale, &g_secondary_locale_pack_region);
+        app_locale, false, &g_secondary_locale_pack_region);
 
     secondary_locale_resources_data_ = LoadDataPackFromLocalePak(
         g_secondary_locale_pack_fd, g_secondary_locale_pack_region);
@@ -217,11 +272,12 @@
   return g_secondary_locale_pack_fd;
 }
 
-std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) {
+std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale,
+                                                bool in_bundle) {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jstring> ret =
       Java_ResourceBundle_getLocalePakResourcePath(
-          env, base::android::ConvertUTF8ToJavaString(env, locale));
+          env, base::android::ConvertUTF8ToJavaString(env, locale), in_bundle);
   if (ret.obj() == nullptr) {
     return std::string();
   }
diff --git a/ui/base/resource/resource_bundle_android.h b/ui/base/resource/resource_bundle_android.h
index 57059b0..48bea432 100644
--- a/ui/base/resource/resource_bundle_android.h
+++ b/ui/base/resource/resource_bundle_android.h
@@ -45,8 +45,12 @@
 // Returns the path within the apk for the given locale's .pak file, or an
 // empty string if it doesn't exist.
 // Only locale paks for the active Android language can be retrieved.
+// If |inSplit| is true, look into bundle split-specific location (e.g.
+// 'assets/locales#lang_<lang>/<locale>.pak', otherwise use the default
+// WebView-related location, i.e. 'assets/stored-locales/<locale>.pak'.
 UI_BASE_EXPORT std::string GetPathForAndroidLocalePakWithinApk(
-    const std::string& locale);
+    const std::string& locale,
+    bool in_split = false);
 
 // Get the density of the primary display. Use this instead of using Display
 // to avoid initializing Display in child processes.
diff --git a/ui/shell_dialogs/BUILD.gn b/ui/shell_dialogs/BUILD.gn
index 935723a2..486d158 100644
--- a/ui/shell_dialogs/BUILD.gn
+++ b/ui/shell_dialogs/BUILD.gn
@@ -101,4 +101,9 @@
     "//ui/resources:ui_test_pak_data",
     "//ui/strings",
   ]
+
+  # TODO: Remove once http://crbug.com/951419 is fixed.
+  if (is_android) {
+    deps += [ "//ui/android:ui_java" ]
+  }
 }
diff --git a/ui/views/metadata/OWNERS b/ui/views/metadata/OWNERS
new file mode 100644
index 0000000..657bd63
--- /dev/null
+++ b/ui/views/metadata/OWNERS
@@ -0,0 +1 @@
+kylixrd@chromium.org