diff --git a/.gitignore b/.gitignore
index e2227af..e49951ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -146,9 +146,10 @@
 /chrome/test/data/perf/private/
 /chrome/test/data/perf/third_party/
 /chrome/test/data/plugin/
+/chrome/test/data/vr/
+/chrome/test/data/webrtc/resources
 /chrome/test/data/xr/webvr_info/
 /chrome/test/data/xr/webxr_samples/
-/chrome/test/data/webrtc/resources
 /chrome/test/media_router/internal
 /chrome/test/python_tests/
 /chrome/tools/memory
diff --git a/DEPS b/DEPS
index c4f5c10..71551e8 100644
--- a/DEPS
+++ b/DEPS
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '0be37b44499672aa5f86d50f7087ff6e2de1c4fd',
+  'angle_revision': 'd754eb5620ed7eb6fc26f6b19494d37e4c6d19f1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'abf9829bc4112e5d25e4d0e2f57341fac22daccd',
+  'pdfium_revision': 'c68109a2dac3be544b7753d1fd677255d859745b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -165,7 +165,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': 'd26f5c315d5ed3e9389ea209a51611f979a18db7',
+  'catapult_revision': '213eaf4f79bcdfc088cb7a6512948b7777403c7f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -539,7 +539,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '25fb576a3ccd21459dda7b9ac4dd203e632cdcb9',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b6704082f43ca9ac410ff6422a9c973fb0ca1e8e',
       'condition': 'checkout_linux',
   },
 
@@ -564,7 +564,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3899f1bcce7bb87be6af32aec08f8a373e5ae417',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '807abf149a5d70e80b2ed1fee11dcec2a7d255bc',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -768,7 +768,7 @@
     Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'd955c63ec7048d59dffd20af25eeec23da878d27',
 
   'src/third_party/libaom/source/libaom': {
-    'url': Var('aomedia_git') + '/aom.git' + '@' +  '369ab2088d3f20df1b653c970151d2c654167334',
+    'url': Var('aomedia_git') + '/aom.git' + '@' +  '88e4b0a4ee32d39371e15040fa0a1ee7c9d8a19d',
     'condition': 'checkout_libaom',
   },
 
@@ -912,7 +912,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'ca307e9c43bb44692239ee6d8e2d6d7d32a6d77e',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '89f205cedfcf2cb37f72162cbee5d18c201b4f33',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index cde8ba3..24237157 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -142,8 +142,9 @@
   viz::SurfaceDrawQuad* surface_quad =
       render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
   surface_quad->SetNew(quad_state, gfx::Rect(quad_state->quad_layer_rect),
-                       gfx::Rect(quad_state->quad_layer_rect), child_id,
-                       base::nullopt, SK_ColorWHITE, false);
+                       gfx::Rect(quad_state->quad_layer_rect),
+                       viz::SurfaceRange(base::nullopt, child_id),
+                       SK_ColorWHITE, false);
 
   viz::CompositorFrame frame;
   // We draw synchronously, so acknowledge a manual BeginFrame.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e8f642d..804508c 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -30,8 +30,6 @@
     "accelerators/accelerator_confirmation_dialog.h",
     "accelerators/accelerator_controller.cc",
     "accelerators/accelerator_controller.h",
-    "accelerators/accelerator_controller_registrar.cc",
-    "accelerators/accelerator_controller_registrar.h",
     "accelerators/accelerator_delegate.cc",
     "accelerators/accelerator_delegate.h",
     "accelerators/accelerator_handler.h",
@@ -204,8 +202,6 @@
     "display/display_prefs.h",
     "display/display_shutdown_observer.cc",
     "display/display_shutdown_observer.h",
-    "display/display_synchronizer.cc",
-    "display/display_synchronizer.h",
     "display/display_util.cc",
     "display/display_util.h",
     "display/event_transformation_handler.cc",
@@ -579,8 +575,6 @@
     "shell_port.h",
     "shell_port_classic.cc",
     "shell_port_classic.h",
-    "shell_port_mash.cc",
-    "shell_port_mash.h",
     "shell_state.cc",
     "shell_state.h",
     "shutdown_controller.cc",
@@ -1062,10 +1056,6 @@
     "wallpaper/wallpaper_widget_controller.h",
     "wallpaper/wallpaper_window_state_manager.cc",
     "wallpaper/wallpaper_window_state_manager.h",
-    "window_manager.cc",
-    "window_manager.h",
-    "window_manager_service.cc",
-    "window_manager_service.h",
     "window_user_data.h",
     "wm/always_on_top_controller.cc",
     "wm/always_on_top_controller.h",
@@ -1118,8 +1108,6 @@
     "wm/lock_state_observer.h",
     "wm/lock_window_state.cc",
     "wm/lock_window_state.h",
-    "wm/move_event_handler.cc",
-    "wm/move_event_handler.h",
     "wm/mru_window_tracker.cc",
     "wm/mru_window_tracker.h",
     "wm/native_cursor_manager_ash.h",
@@ -1303,8 +1291,6 @@
     "wm/workspace/workspace_event_handler.h",
     "wm/workspace/workspace_event_handler_classic.cc",
     "wm/workspace/workspace_event_handler_classic.h",
-    "wm/workspace/workspace_event_handler_mash.cc",
-    "wm/workspace/workspace_event_handler_mash.h",
     "wm/workspace/workspace_layout_manager.cc",
     "wm/workspace/workspace_layout_manager.h",
     "wm/workspace/workspace_types.h",
@@ -1934,7 +1920,6 @@
     "wallpaper/wallpaper_utils/wallpaper_color_calculator_unittest.cc",
     "wallpaper/wallpaper_utils/wallpaper_resizer_unittest.cc",
     "wallpaper/wallpaper_window_state_manager_unittest.cc",
-    "window_manager_common_unittests.cc",
     "window_user_data_unittest.cc",
     "wm/always_on_top_controller_unittest.cc",
     "wm/ash_focus_rules_unittest.cc",
diff --git a/ash/accelerators/accelerator_controller_registrar.cc b/ash/accelerators/accelerator_controller_registrar.cc
deleted file mode 100644
index 549d3a1d..0000000
--- a/ash/accelerators/accelerator_controller_registrar.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/accelerators/accelerator_controller_registrar.h"
-
-#include <limits>
-
-#include "ash/accelerators/accelerator_controller.h"
-#include "ash/accelerators/accelerator_ids.h"
-#include "ash/accelerators/accelerator_router.h"
-#include "ash/public/interfaces/event_properties.mojom.h"
-#include "ash/shell.h"
-#include "ash/window_manager.h"
-#include "ash/wm/window_cycle_controller.h"
-#include "ash/wm/window_util.h"
-#include "base/logging.h"
-#include "services/ui/common/accelerator_util.h"
-#include "services/ui/public/cpp/property_type_converters.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/accelerator_history.h"
-
-namespace ash {
-namespace {
-
-// Callback from registering the accelerators.
-void OnAcceleratorsAdded(const std::vector<ui::Accelerator>& accelerators,
-                         bool added) {
-  // All our accelerators should be registered, so we expect |added| to be true.
-  DCHECK(added) << "Unexpected accelerator vector registration failure.";
-}
-
-}  // namespace
-
-AcceleratorControllerRegistrar::AcceleratorControllerRegistrar(
-    WindowManager* window_manager,
-    uint16_t id_namespace)
-    : window_cycle_complete_accelerator_(ui::VKEY_MENU,
-                                         ui::EF_NONE,
-                                         ui::Accelerator::KeyState::RELEASED),
-      window_cycle_cancel_accelerator_(ui::VKEY_ESCAPE, ui::EF_ALT_DOWN),
-      window_manager_(window_manager),
-      id_namespace_(id_namespace),
-      next_id_(0),
-      router_(new AcceleratorRouter) {
-  window_manager_->AddAcceleratorHandler(id_namespace, this);
-  RegisterWindowCycleAccelerators();
-}
-
-AcceleratorControllerRegistrar::~AcceleratorControllerRegistrar() {
-  window_manager_->RemoveAcceleratorHandler(id_namespace_);
-
-  if (!window_manager_->window_manager_client())
-    return;
-
-  // TODO(sky): consider not doing this. If we assume the destructor is called
-  // during shutdown, then this is unnecessary and results in a bunch of
-  // messages that are dropped.
-  for (uint16_t local_id : ids_) {
-    window_manager_->window_manager_client()->RemoveAccelerator(
-        ComputeAcceleratorId(id_namespace_, local_id));
-  }
-}
-
-ui::mojom::EventResult AcceleratorControllerRegistrar::OnAccelerator(
-    uint32_t id,
-    const ui::Event& event,
-    base::flat_map<std::string, std::vector<uint8_t>>* properties) {
-  const ui::Accelerator accelerator(*event.AsKeyEvent());
-  auto iter = accelerator_to_ids_.find(accelerator);
-  if (iter == accelerator_to_ids_.end()) {
-    // Because of timing we may have unregistered the accelerator already,
-    // ignore in that case.
-    return ui::mojom::EventResult::UNHANDLED;
-  }
-
-  const Ids& ids = iter->second;
-  AcceleratorController* accelerator_controller =
-      Shell::Get()->accelerator_controller();
-  const bool is_pre = GetAcceleratorLocalId(id) == ids.pre_id;
-  if (is_pre) {
-    // TODO(sky): this does not exactly match ash code. In particular ash code
-    // is called for *all* key events, where as this is only called for
-    // registered accelerators. This means the previous accelerator isn't the
-    // same as it was in ash. We need to figure out exactly what is needed of
-    // previous accelerator so that we can either register for the right set of
-    // accelerators, or make WS send the previous accelerator.
-    // http://crbug.com/630683.
-    accelerator_controller->accelerator_history()->StoreCurrentAccelerator(
-        accelerator);
-    if (HandleWindowCycleAccelerator(accelerator))
-      return ui::mojom::EventResult::HANDLED;
-    aura::Window* target_window = wm::GetFocusedWindow();
-    if (!target_window)
-      target_window = Shell::GetRootWindowForNewWindows();
-    DCHECK(target_window);
-    if (router_->ProcessAccelerator(target_window, *(event.AsKeyEvent()),
-                                    accelerator)) {
-      return ui::mojom::EventResult::HANDLED;
-    }
-    if (accelerator_controller->IsActionForAcceleratorEnabled(accelerator)) {
-      // We do have an accelerator for the key. Set a property so that the real
-      // target knows we have an accelerator.
-      (*properties)[mojom::kWillProcessAccelerator_KeyEventProperty] =
-          std::vector<uint8_t>();
-    }
-    return ui::mojom::EventResult::UNHANDLED;
-  }
-  DCHECK_EQ(GetAcceleratorLocalId(id), ids.post_id);
-  // NOTE: for post return value doesn't really matter.
-  return Shell::Get()->accelerator_controller()->Process(accelerator)
-             ? ui::mojom::EventResult::HANDLED
-             : ui::mojom::EventResult::UNHANDLED;
-}
-
-void AcceleratorControllerRegistrar::OnAcceleratorsRegistered(
-    const std::vector<ui::Accelerator>& accelerators) {
-  std::vector<ui::mojom::WmAcceleratorPtr> accelerator_vector;
-
-  for (const ui::Accelerator& accelerator : accelerators)
-    AddAcceleratorToVector(accelerator, accelerator_vector);
-
-  window_manager_->window_manager_client()->AddAccelerators(
-      std::move(accelerator_vector),
-      base::Bind(OnAcceleratorsAdded, accelerators));
-}
-
-void AcceleratorControllerRegistrar::OnAcceleratorUnregistered(
-    const ui::Accelerator& accelerator) {
-  auto iter = accelerator_to_ids_.find(accelerator);
-  DCHECK(iter != accelerator_to_ids_.end());
-  Ids ids = iter->second;
-  accelerator_to_ids_.erase(iter);
-  ids_.erase(ids.pre_id);
-  ids_.erase(ids.post_id);
-  DCHECK_EQ(accelerator_to_ids_.size() * 2, ids_.size());
-  window_manager_->window_manager_client()->RemoveAccelerator(
-      ComputeAcceleratorId(id_namespace_, ids.pre_id));
-  window_manager_->window_manager_client()->RemoveAccelerator(
-      ComputeAcceleratorId(id_namespace_, ids.post_id));
-}
-
-void AcceleratorControllerRegistrar::AddAcceleratorToVector(
-    const ui::Accelerator& accelerator,
-    std::vector<ui::mojom::WmAcceleratorPtr>& accelerator_vector) {
-  Ids ids;
-  if (!GenerateIds(&ids)) {
-    LOG(ERROR) << "max number of accelerators registered, dropping request";
-    return;
-  }
-  DCHECK_EQ(0u, accelerator_to_ids_.count(accelerator));
-  accelerator_to_ids_[accelerator] = ids;
-  DCHECK_EQ(accelerator_to_ids_.size() * 2, ids_.size());
-
-  ui::mojom::EventMatcherPtr pre_event_matcher = ui::CreateKeyMatcher(
-      static_cast<ui::mojom::KeyboardCode>(accelerator.key_code()),
-      accelerator.modifiers());
-  pre_event_matcher->accelerator_phase =
-      ui::mojom::AcceleratorPhase::PRE_TARGET;
-  pre_event_matcher->type_matcher->type =
-      accelerator.key_state() == ui::Accelerator::KeyState::PRESSED
-          ? ui::mojom::EventType::KEY_PRESSED
-          : ui::mojom::EventType::KEY_RELEASED;
-
-  ui::mojom::EventMatcherPtr post_event_matcher = pre_event_matcher.Clone();
-  post_event_matcher->accelerator_phase =
-      ui::mojom::AcceleratorPhase::POST_TARGET;
-
-  accelerator_vector.push_back(
-      ui::CreateAccelerator(ComputeAcceleratorId(id_namespace_, ids.pre_id),
-                            std::move(pre_event_matcher)));
-
-  accelerator_vector.push_back(
-      ui::CreateAccelerator(ComputeAcceleratorId(id_namespace_, ids.post_id),
-                            std::move(post_event_matcher)));
-}
-
-bool AcceleratorControllerRegistrar::GenerateIds(Ids* ids) {
-  if (ids_.size() + 2 >= std::numeric_limits<uint16_t>::max())
-    return false;
-  ids->pre_id = GetNextLocalAcceleratorId();
-  ids->post_id = GetNextLocalAcceleratorId();
-  return true;
-}
-
-uint16_t AcceleratorControllerRegistrar::GetNextLocalAcceleratorId() {
-  DCHECK_LT(ids_.size(), std::numeric_limits<uint16_t>::max());
-  // Common case is we never wrap once, so this is typically cheap. Additionally
-  // we expect there not to be too many accelerators.
-  while (ids_.count(next_id_) > 0)
-    ++next_id_;
-  ids_.insert(next_id_);
-  return next_id_++;
-}
-
-void AcceleratorControllerRegistrar::RegisterWindowCycleAccelerators() {
-  std::vector<ui::Accelerator> accelerators;
-  accelerators.push_back(window_cycle_complete_accelerator_);
-  accelerators.push_back(window_cycle_cancel_accelerator_);
-  OnAcceleratorsRegistered(accelerators);
-}
-
-bool AcceleratorControllerRegistrar::HandleWindowCycleAccelerator(
-    const ui::Accelerator& accelerator) {
-  ash::WindowCycleController* window_cycle_controller =
-      Shell::Get()->window_cycle_controller();
-  if (!window_cycle_controller->IsCycling())
-    return false;
-
-  if (accelerator == window_cycle_complete_accelerator_) {
-    window_cycle_controller->CompleteCycling();
-    return true;
-  }
-
-  if (accelerator == window_cycle_cancel_accelerator_) {
-    window_cycle_controller->CancelCycling();
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace ash
diff --git a/ash/accelerators/accelerator_controller_registrar.h b/ash/accelerators/accelerator_controller_registrar.h
deleted file mode 100644
index 6f6902a..0000000
--- a/ash/accelerators/accelerator_controller_registrar.h
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_REGISTRAR_H_
-#define ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_REGISTRAR_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <vector>
-
-#include "ash/accelerators/accelerator_handler.h"
-#include "base/macros.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/accelerator_manager_delegate.h"
-#include "ui/events/mojo/event_constants.mojom.h"
-
-namespace ash {
-
-class AcceleratorControllerRegistrarTestApi;
-class AcceleratorRouter;
-class WindowManager;
-
-// Responsible for registering accelerators created by AcceleratorController
-// with the WindowManager, as well as routing handling of accelerators to
-// the right place.
-class AcceleratorControllerRegistrar : public AcceleratorHandler,
-                                       public ui::AcceleratorManagerDelegate {
- public:
-  AcceleratorControllerRegistrar(WindowManager* window_manager,
-                                 uint16_t id_namespace);
-  ~AcceleratorControllerRegistrar() override;
-
-  // AcceleratorHandler:
-  ui::mojom::EventResult OnAccelerator(
-      uint32_t id,
-      const ui::Event& event,
-      base::flat_map<std::string, std::vector<uint8_t>>* properties) override;
-
- private:
-  friend class AcceleratorControllerRegistrarTestApi;
-
-  // Accelerators for window cycle.
-  const ui::Accelerator window_cycle_complete_accelerator_;
-  const ui::Accelerator window_cycle_cancel_accelerator_;
-
-  // ui::AcceleratorManagerDelegate:
-  void OnAcceleratorsRegistered(
-      const std::vector<ui::Accelerator>& accelerators) override;
-  void OnAcceleratorUnregistered(const ui::Accelerator& accelerator) override;
-
-  // Generate id and add the corresponding accelerator to accelerator vector.
-  // Creates a PRE_TARGET and POST_TARGET mojom accelerators for the provided
-  // |accelerator| and adds them to the provided |accelerator_vector|.
-  void AddAcceleratorToVector(
-      const ui::Accelerator& accelerator,
-      std::vector<ui::mojom::WmAcceleratorPtr>& accelerator_vector);
-
-  // TODO(moshayedi): crbug.com/629191. Handling window cycle accelerators here
-  // is just a temporary solution and we should remove these once we have a
-  // proper solution.
-  void RegisterWindowCycleAccelerators();
-  bool HandleWindowCycleAccelerator(const ui::Accelerator& accelerator);
-
-  // The flow of accelerators in ash is:
-  // . wm::AcceleratorFilter() sees events first as it's a pre-target handler.
-  // . AcceleratorFilter forwards to its delegate, which indirectly is
-  //   implemented by AcceleratorRouter.
-  // . AcceleratorRouter may early out, if not it calls through to
-  //   AcceleratorController. This may stop propagation entirely.
-  // . If focus is on a Widget, then NativeWidgetAura gets the key event, calls
-  //   to Widget::OnKeyEvent(), which calls to FocusManager::OnKeyEvent(), which
-  //   calls to AshFocusManagerFactory::Delegate::ProcessAccelerator() finally
-  //   ending up in AcceleratorController::Process().
-  // . OTOH if focus is on a content, then
-  //   RenderWidgetHostViewAura::OnKeyEvent() is called and may end up consuming
-  //   the event.
-  //
-  // To get this behavior for mash we register accelerators for both pre and
-  // post. Pre gives the behavior of AcceleratorRouter and post that of
-  // AshFocusManagerFactory.
-  //
-  // These ids all use the namespace |id_namespace_|.
-  struct Ids {
-    uint16_t pre_id;
-    uint16_t post_id;
-  };
-
-  // Returns the next local id for an accelerator, or false if the max number of
-  // accelerators have been registered.
-  bool GenerateIds(Ids* ids);
-
-  // Used internally by GenerateIds(). Returns the next local id (as well as
-  // updating |ids_|). This *must* be called from GenerateIds().
-  uint16_t GetNextLocalAcceleratorId();
-
-  WindowManager* window_manager_;
-
-  const uint16_t id_namespace_;
-
-  // Id to use for the next accelerator.
-  uint16_t next_id_;
-
-  std::unique_ptr<AcceleratorRouter> router_;
-
-  // Set of registered local ids.
-  std::set<uint16_t> ids_;
-
-  // Maps from accelerator to the two ids registered for it.
-  std::map<ui::Accelerator, Ids> accelerator_to_ids_;
-
-  DISALLOW_COPY_AND_ASSIGN(AcceleratorControllerRegistrar);
-};
-
-}  // namespace ash
-
-#endif  // ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_REGISTRAR_H_
diff --git a/ash/accelerators/accelerator_handler.h b/ash/accelerators/accelerator_handler.h
index 398e46d..661c725 100644
--- a/ash/accelerators/accelerator_handler.h
+++ b/ash/accelerators/accelerator_handler.h
@@ -16,6 +16,7 @@
 namespace ash {
 
 // Used by WindowManager for handling accelerators. This is only used in mash.
+// TODO: this should no longer be necessary, remove. https://crbug.com/842365
 class AcceleratorHandler {
  public:
   // See WindowManagerDelegate for details on |properties|.
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 9f6f455..736ea9d 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -366,15 +366,24 @@
           Adobe Flash Player update available
         </message>
       </if>
+      <message name="IDS_ROLLBACK_NOTIFICATION_TITLE" desc="The title of the notification to notify that the user should restart to roll back the device.">
+        Device will be rolled back
+      </message>
       <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_LEARN_MORE" desc="The body of the notification to notify that the user should restart to get system updates. This notification body links to the info page on the update.">
         Learn more about the latest <ph name="SYSTEM_APP_NAME">$1<ex>Chromium OS</ex></ph> update
       </message>
       <message name="IDS_UPDATE_NOTIFICATION_RESTART_BUTTON" meaning="button label" desc="The label used as the button to restart system and update. Displayed as the action button of the notification for system update.">
         Restart to update
       </message>
+      <message name="IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON" meaning="button label" desc="The label used as the button to restart system to rollback. Displayed as the action button of the notification for system rollback.">
+        Restart and reset
+      </message>
       <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH" desc="The notification message used in the system notification update when user need to powerwash the device in order to update the system.">
         This update requires powerwashing your device. Learn more about the latest <ph name="SYSTEM_APP_NAME">$1<ex>Chromium OS</ex></ph> update.
       </message>
+      <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK" desc="The notification message used in the system notification update when the device is rolled back and data will be deleted.">
+        Your administrator is rolling back your device. All data will be deleted when the device is restarted.
+      </message>
 
       <message name="IDS_ASH_STATUS_TRAY_VOLUME" desc="The accessible text for the volume slider.">
         Volume
diff --git a/ash/display/display_synchronizer.cc b/ash/display/display_synchronizer.cc
deleted file mode 100644
index 1b86a63d..0000000
--- a/ash/display/display_synchronizer.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/display/display_synchronizer.h"
-
-#include "ash/display/mirror_window_controller.h"
-#include "ash/host/ash_window_tree_host.h"
-#include "ash/shell.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
-#include "ui/aura/mus/window_manager_delegate.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/base/ui_base_switches_util.h"
-#include "ui/display/manager/display_manager.h"
-#include "ui/display/manager/managed_display_info.h"
-
-namespace ash {
-namespace {
-
-aura::WindowTreeHostMus* ToWindowTreeHostMus(AshWindowTreeHost* ash_host) {
-  return static_cast<aura::WindowTreeHostMus*>(ash_host->AsWindowTreeHost());
-}
-
-// Get the metrics for the display with the given |id|.
-ui::mojom::WmViewportMetricsPtr GetMetricsForDisplay(int64_t id) {
-  ui::mojom::WmViewportMetricsPtr metrics = ui::mojom::WmViewportMetrics::New();
-  const display::ManagedDisplayInfo& display_info =
-      Shell::Get()->display_manager()->GetDisplayInfo(id);
-  metrics->bounds_in_pixels = display_info.bounds_in_native();
-  metrics->device_scale_factor = display_info.device_scale_factor();
-  metrics->ui_scale_factor = display_info.configured_ui_scale();
-  return metrics;
-}
-
-}  // namespace
-
-DisplaySynchronizer::DisplaySynchronizer(
-    aura::WindowManagerClient* window_manager_client)
-    : window_manager_client_(window_manager_client) {
-  Shell::Get()->window_tree_host_manager()->AddObserver(this);
-  Shell::Get()->display_manager()->AddObserver(this);
-  SendDisplayConfigurationToServer();
-}
-
-DisplaySynchronizer::~DisplaySynchronizer() {
-  Shell::Get()->display_manager()->RemoveObserver(this);
-  Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
-}
-
-void DisplaySynchronizer::SendDisplayConfigurationToServer() {
-  if (processing_display_changes_)
-    return;
-
-  display::DisplayManager* display_manager = Shell::Get()->display_manager();
-  const size_t display_count = display_manager->GetNumDisplays();
-  if (display_count == 0)
-    return;
-
-  std::vector<display::Display> displays;
-  std::vector<ui::mojom::WmViewportMetricsPtr> metrics;
-  for (size_t i = 0; i < display_count; ++i) {
-    displays.push_back(display_manager->GetDisplayAt(i));
-    metrics.push_back(GetMetricsForDisplay(displays[i].id()));
-  }
-  std::vector<display::Display> mirrors;
-  MirrorWindowController* mirror_window_controller =
-      Shell::Get()->window_tree_host_manager()->mirror_window_controller();
-  for (const auto& mirror :
-       display_manager->software_mirroring_display_list()) {
-    if (base::FeatureList::IsEnabled(features::kMashDeprecated)) {
-      // If mus is hosting viz, the window server handle mirrors internally.
-      mirrors.push_back(mirror);
-      metrics.push_back(GetMetricsForDisplay(mirror.id()));
-    } else if (mirror_window_controller->GetAshWindowTreeHostForDisplayId(
-                   mirror.id())) {
-      // Otherwise, if MirrorWindowController constructed a window tree host
-      // the window server should construct a normal ws::Display for the mirror.
-      displays.push_back(mirror);
-      metrics.push_back(GetMetricsForDisplay(mirror.id()));
-    }
-  }
-
-  window_manager_client_->SetDisplayConfiguration(
-      displays, std::move(metrics),
-      WindowTreeHostManager::GetPrimaryDisplayId(), mirrors);
-
-  sent_initial_config_ = true;
-}
-
-void DisplaySynchronizer::OnDisplaysInitialized() {
-  SendDisplayConfigurationToServer();
-}
-
-void DisplaySynchronizer::OnDisplayConfigurationChanged() {
-  SendDisplayConfigurationToServer();
-}
-
-void DisplaySynchronizer::OnWindowTreeHostReusedForDisplay(
-    AshWindowTreeHost* window_tree_host,
-    const display::Display& display) {
-  aura::WindowTreeHostMus* window_tree_host_mus =
-      ToWindowTreeHostMus(window_tree_host);
-  if (window_tree_host_mus->display_id() == display.id())
-    return;
-  const display::ManagedDisplayInfo& display_info =
-      Shell::Get()->display_manager()->GetDisplayInfo(display.id());
-  ui::mojom::WmViewportMetricsPtr viewport_metrics =
-      ui::mojom::WmViewportMetrics::New();
-  viewport_metrics->bounds_in_pixels = display_info.bounds_in_native();
-  viewport_metrics->device_scale_factor = display.device_scale_factor();
-  viewport_metrics->ui_scale_factor = display_info.configured_ui_scale();
-  window_manager_client_->AddDisplayReusingWindowTreeHost(
-      ToWindowTreeHostMus(window_tree_host), display,
-      std::move(viewport_metrics));
-}
-
-void DisplaySynchronizer::OnWindowTreeHostsSwappedDisplays(
-    AshWindowTreeHost* host1,
-    AshWindowTreeHost* host2) {
-  DCHECK(host1);
-  DCHECK(host2);
-  window_manager_client_->SwapDisplayRoots(ToWindowTreeHostMus(host1),
-                                           ToWindowTreeHostMus(host2));
-}
-
-void DisplaySynchronizer::OnWillProcessDisplayChanges() {
-  DCHECK(!processing_display_changes_);
-  processing_display_changes_ = true;
-}
-
-void DisplaySynchronizer::OnDidProcessDisplayChanges() {
-  DCHECK(processing_display_changes_);
-  processing_display_changes_ = false;
-  SendDisplayConfigurationToServer();
-}
-
-void DisplaySynchronizer::OnDisplayMetricsChanged(
-    const display::Display& display,
-    uint32_t changed_metrics) {
-  // Changing only the work area doesn't trigger
-  // OnDisplayConfigurationChanged().
-  // Wait for the initial config before sending anything as initial display
-  // creation may trigger numerous calls to OnDisplayConfigurationChanged().
-  if (sent_initial_config_ && changed_metrics == DISPLAY_METRIC_WORK_AREA)
-    SendDisplayConfigurationToServer();
-}
-
-}  // namespace ash
diff --git a/ash/display/display_synchronizer.h b/ash/display/display_synchronizer.h
deleted file mode 100644
index 98e135b..0000000
--- a/ash/display/display_synchronizer.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_DISPLAY_DISPLAY_SYNCHRONIZER_H_
-#define ASH_DISPLAY_DISPLAY_SYNCHRONIZER_H_
-
-#include "ash/display/window_tree_host_manager.h"
-#include "base/macros.h"
-#include "ui/display/display_observer.h"
-
-namespace aura {
-class WindowManagerClient;
-}
-
-namespace ash {
-
-// DisplaySynchronizer keeps the display state in mus in sync with ash's display
-// state. As ash controls the overall display state this synchronization is one
-// way (from ash to mus).
-class DisplaySynchronizer : public WindowTreeHostManager::Observer,
-                            public display::DisplayObserver {
- public:
-  explicit DisplaySynchronizer(
-      aura::WindowManagerClient* window_manager_client);
-  ~DisplaySynchronizer() override;
-
- private:
-  void SendDisplayConfigurationToServer();
-
-  // WindowTreeHostManager::Observer:
-  void OnDisplaysInitialized() override;
-  void OnDisplayConfigurationChanged() override;
-  void OnWindowTreeHostReusedForDisplay(
-      AshWindowTreeHost* window_tree_host,
-      const display::Display& display) override;
-  void OnWindowTreeHostsSwappedDisplays(AshWindowTreeHost* host1,
-                                        AshWindowTreeHost* host2) override;
-
-  // display::DisplayObserver:
-  void OnWillProcessDisplayChanges() override;
-  void OnDidProcessDisplayChanges() override;
-  void OnDisplayMetricsChanged(const display::Display& display,
-                               uint32_t changed_metrics) override;
-
-  aura::WindowManagerClient* window_manager_client_;
-
-  bool sent_initial_config_ = false;
-
-  // Set to true when OnWillProcessDisplayChanges() is called and false in
-  // OnDidProcessDisplayChanges(). DisplayManager calls out while the list of
-  // displays contains both newly added displays and displays that have been
-  // removed. This means if we attempt to access the list of displays during
-  // this time we may get the wrong state (SendDisplayConfigurationToServer()
-  // would send a bogus display to the window server). By only processing the
-  // change after DisplayManager has updated its internal state we ensure we
-  // don't send a bad config.
-  bool processing_display_changes_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(DisplaySynchronizer);
-};
-
-}  // namespace ash
-
-#endif  // ASH_DISPLAY_DISPLAY_SYNCHRONIZER_H_
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 22f0ef50..0042697 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -28,9 +28,6 @@
 const base::Feature kLockScreenNotifications{"LockScreenNotifications",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kNewOverviewAnimations{"NewOverviewAnimations",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kNewWallpaperPicker{"NewWallpaperPicker",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index d95e7a3..e58f1c7 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -39,11 +39,6 @@
 // Enables notifications on the lock screen.
 ASH_PUBLIC_EXPORT extern const base::Feature kLockScreenNotifications;
 
-// Enables the new overview animations.
-// TODO(wutao): Remove this after the feature is fully launched.
-// https://crbug.com/801465.
-ASH_PUBLIC_EXPORT extern const base::Feature kNewOverviewAnimations;
-
 // Enables the new wallpaper picker.
 // TODO(wzang): Remove this after the feature is fully launched.
 // https://crbug.com/777293.
diff --git a/ash/public/interfaces/system_tray.mojom b/ash/public/interfaces/system_tray.mojom
index c90c3e29..7ef30f3 100644
--- a/ash/public/interfaces/system_tray.mojom
+++ b/ash/public/interfaces/system_tray.mojom
@@ -33,11 +33,21 @@
   // tracing is running.
   SetPerformanceTracingIconVisible(bool visible);
 
-  // Shows an icon in the system tray indicating that a software update is
-  // available. Once shown the icon persists until reboot. |severity| and
-  // |factory_reset_required| are used to set the icon, color, and tooltip.
+  // Shows an icon in the system tray or a notification on the unified system
+  // menu indicating that a software update is available. Once shown, the icon
+  // or the notification persists until reboot.
+  // |severity| specifies how critical is the update.
+  // |factory_reset_required| is true if during the update the device will
+  //     be wiped.
+  // |rollback| specifies whether the update is actually an admin-initiated
+  //     rollback. This implies that a the device will be wiped.
+  // |update_type| specifies the component which has been updated.
+  //
+  // These values are used to control the icon, color and the text of the
+  // tooltip or the notification.
   ShowUpdateIcon(UpdateSeverity severity,
                  bool factory_reset_required,
+                 bool rollback,
                  UpdateType update_type);
 
   // If |visible| is true, shows an icon in the system tray which indicates that
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index b13fd55d..695acb42 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -72,8 +72,6 @@
 #include "ui/aura/client/drag_drop_client.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/client/window_types.h"
-#include "ui/aura/mus/window_mus.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_observer.h"
@@ -255,10 +253,6 @@
   aura::Window* window =
       new aura::Window(nullptr, aura::client::WINDOW_TYPE_UNKNOWN);
   window->Init(ui::LAYER_NOT_DRAWN);
-  if (Shell::GetAshConfig() != Config::CLASSIC) {
-    window->SetEventTargetingPolicy(
-        ui::mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
-  }
   window->set_id(window_id);
   window->SetName(name);
   parent->AddChild(window);
@@ -268,15 +262,7 @@
 }
 
 bool ShouldDestroyWindowInCloseChildWindows(aura::Window* window) {
-  if (!window->owned_by_parent())
-    return false;
-
-  if (Shell::GetAshConfig() != Config::MASH_DEPRECATED)
-    return true;
-
-  aura::WindowMus* window_mus = aura::WindowMus::Get(window);
-  return Shell::window_tree_client()->WasCreatedByThisClient(window_mus) ||
-         Shell::window_tree_client()->IsRoot(window_mus);
+  return window->owned_by_parent();
 }
 
 }  // namespace
diff --git a/ash/shell.cc b/ash/shell.cc
index b16ddcb1ec..28a74cd 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -180,9 +180,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/aura/layout_manager.h"
-#include "ui/aura/mus/focus_synchronizer.h"
 #include "ui/aura/mus/user_activity_forwarder.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/ui_base_features.h"
@@ -264,10 +262,6 @@
 
 // static
 Shell* Shell::instance_ = nullptr;
-// static
-aura::WindowTreeClient* Shell::window_tree_client_ = nullptr;
-// static
-aura::WindowManagerClient* Shell::window_manager_client_ = nullptr;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Shell, public:
@@ -724,8 +718,6 @@
 Shell::~Shell() {
   TRACE_EVENT0("shutdown", "ash::Shell::Destructor");
 
-  const Config config = shell_port_->GetAshConfig();
-
   // Wayland depends upon some ash specific objects. Destroy it early on.
   wayland_server_controller_.reset();
 
@@ -910,11 +902,6 @@
   // Depends on |focus_controller_|, so must be destroyed before.
   window_tree_host_manager_.reset();
   focus_controller_->RemoveObserver(this);
-  if (config != Config::CLASSIC &&
-      window_tree_client_->focus_synchronizer()->active_focus_client() ==
-          focus_controller_.get()) {
-    window_tree_client_->focus_synchronizer()->SetSingletonFocusClient(nullptr);
-  }
   focus_controller_.reset();
   screen_position_controller_.reset();
 
@@ -1085,10 +1072,6 @@
   focus_controller_ =
       std::make_unique<::wm::FocusController>(new wm::AshFocusRules());
   focus_controller_->AddObserver(this);
-  if (config != Config::CLASSIC) {
-    window_tree_client_->focus_synchronizer()->SetSingletonFocusClient(
-        focus_controller_.get());
-  }
 
   screen_position_controller_.reset(new ScreenPositionController);
 
diff --git a/ash/shell.h b/ash/shell.h
index 42c3d8106..62ffbeff7 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -34,8 +34,6 @@
 class RootWindow;
 class UserActivityForwarder;
 class Window;
-class WindowManagerClient;
-class WindowTreeClient;
 }  // namespace aura
 
 namespace display {
@@ -274,23 +272,6 @@
   // Returns true if a system-modal dialog window is currently open.
   static bool IsSystemModalWindowOpen();
 
-  // TODO(sky): move this and WindowManagerClient into ShellMash that is owned
-  // by Shell. Doing the move is gated on having mash create Shell.
-  static void set_window_tree_client(aura::WindowTreeClient* client) {
-    window_tree_client_ = client;
-  }
-
-  static aura::WindowTreeClient* window_tree_client() {
-    return window_tree_client_;
-  }
-
-  static void set_window_manager_client(aura::WindowManagerClient* client) {
-    window_manager_client_ = client;
-  }
-  static aura::WindowManagerClient* window_manager_client() {
-    return window_manager_client_;
-  }
-
   static Config GetAshConfig();
   static bool ShouldUseIMEService();
 
@@ -717,10 +698,6 @@
 
   static Shell* instance_;
 
-  // Only valid in mash, for classic ash this is null.
-  static aura::WindowTreeClient* window_tree_client_;
-  static aura::WindowManagerClient* window_manager_client_;
-
   std::unique_ptr<ShellPort> shell_port_;
 
   // The CompoundEventFilter owned by aura::Env object.
diff --git a/ash/shell_init_params.h b/ash/shell_init_params.h
index 71fb2d5..11269cd 100644
--- a/ash/shell_init_params.h
+++ b/ash/shell_init_params.h
@@ -35,6 +35,7 @@
   ShellInitParams(ShellInitParams&& other);
   ~ShellInitParams();
 
+  // TODO(sky): remove this, no longer needed. https://crbug.com/842365
   std::unique_ptr<ShellPort> shell_port;
   std::unique_ptr<ShellDelegate> delegate;
   ui::ContextFactory* context_factory = nullptr;                 // Non-owning.
diff --git a/ash/shell_port_mash.cc b/ash/shell_port_mash.cc
deleted file mode 100644
index 69ed7a4f..0000000
--- a/ash/shell_port_mash.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/shell_port_mash.h"
-
-#include <memory>
-#include <utility>
-
-#include "ash/accelerators/accelerator_controller.h"
-#include "ash/accelerators/accelerator_controller_registrar.h"
-#include "ash/display/display_synchronizer.h"
-#include "ash/host/ash_window_tree_host_init_params.h"
-#include "ash/host/ash_window_tree_host_mus.h"
-#include "ash/keyboard/keyboard_ui_mash.h"
-#include "ash/public/cpp/config.h"
-#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shell.h"
-#include "ash/touch/touch_transform_setter_mus.h"
-#include "ash/window_manager.h"
-#include "ash/wm/drag_window_resizer_mash.h"
-#include "ash/wm/immersive_handler_factory_mash.h"
-#include "ash/wm/tablet_mode/tablet_mode_event_handler.h"
-#include "ash/wm/window_cycle_event_filter.h"
-#include "ash/wm/window_resizer.h"
-#include "ash/wm/window_util.h"
-#include "ash/wm/workspace/workspace_event_handler_mash.h"
-#include "services/ui/public/interfaces/constants.mojom.h"
-#include "services/ui/public/interfaces/video_detector.mojom.h"
-#include "ui/aura/env.h"
-#include "ui/aura/mus/window_tree_host_mus_init_params.h"
-#include "ui/aura/window.h"
-#include "ui/display/display.h"
-#include "ui/display/manager/display_manager.h"
-#include "ui/display/manager/forwarding_display_delegate.h"
-#include "ui/display/mojo/native_display_delegate.mojom.h"
-#include "ui/views/mus/pointer_watcher_event_router.h"
-
-namespace ash {
-
-ShellPortMash::ShellPortMash(
-    WindowManager* window_manager,
-    views::PointerWatcherEventRouter* pointer_watcher_event_router)
-    : window_manager_(window_manager),
-      pointer_watcher_event_router_(pointer_watcher_event_router),
-      immersive_handler_factory_(
-          std::make_unique<ImmersiveHandlerFactoryMash>()) {
-  DCHECK(window_manager_);
-  DCHECK(pointer_watcher_event_router_);
-  DCHECK_EQ(Config::MASH_DEPRECATED, GetAshConfig());
-}
-
-ShellPortMash::~ShellPortMash() = default;
-
-// static
-ShellPortMash* ShellPortMash::Get() {
-  const ash::Config config = ShellPort::Get()->GetAshConfig();
-  CHECK_EQ(Config::MASH_DEPRECATED, config);
-  return static_cast<ShellPortMash*>(ShellPort::Get());
-}
-
-void ShellPortMash::Shutdown() {
-  display_synchronizer_.reset();
-  ShellPort::Shutdown();
-}
-
-Config ShellPortMash::GetAshConfig() const {
-  return Config::MASH_DEPRECATED;
-}
-
-std::unique_ptr<display::TouchTransformSetter>
-ShellPortMash::CreateTouchTransformDelegate() {
-  return std::make_unique<TouchTransformSetterMus>(
-      window_manager_->connector());
-}
-
-void ShellPortMash::LockCursor() {
-  // When we are running in mus, we need to keep track of state not just in the
-  // window server, but also locally in ash because ash treats the cursor
-  // manager as the canonical state for now. NativeCursorManagerAsh will keep
-  // this state, while also forwarding it to the window manager for us.
-  window_manager_->window_manager_client()->LockCursor();
-}
-
-void ShellPortMash::UnlockCursor() {
-  window_manager_->window_manager_client()->UnlockCursor();
-}
-
-void ShellPortMash::ShowCursor() {
-  window_manager_->window_manager_client()->SetCursorVisible(true);
-}
-
-void ShellPortMash::HideCursor() {
-  window_manager_->window_manager_client()->SetCursorVisible(false);
-}
-
-void ShellPortMash::SetCursorSize(ui::CursorSize cursor_size) {
-  window_manager_->window_manager_client()->SetCursorSize(cursor_size);
-}
-
-void ShellPortMash::SetGlobalOverrideCursor(
-    base::Optional<ui::CursorData> cursor) {
-  window_manager_->window_manager_client()->SetGlobalOverrideCursor(
-      std::move(cursor));
-}
-
-bool ShellPortMash::IsMouseEventsEnabled() {
-  return cursor_touch_visible_;
-}
-
-void ShellPortMash::SetCursorTouchVisible(bool enabled) {
-  window_manager_->window_manager_client()->SetCursorTouchVisible(enabled);
-}
-
-void ShellPortMash::OnCursorTouchVisibleChanged(bool enabled) {
-  cursor_touch_visible_ = enabled;
-}
-
-std::unique_ptr<WindowResizer> ShellPortMash::CreateDragWindowResizer(
-    std::unique_ptr<WindowResizer> next_window_resizer,
-    wm::WindowState* window_state) {
-  return std::make_unique<ash::DragWindowResizerMash>(
-      std::move(next_window_resizer), window_state);
-}
-
-std::unique_ptr<WindowCycleEventFilter>
-ShellPortMash::CreateWindowCycleEventFilter() {
-  // TODO: implement me, http://crbug.com/629191.
-  return nullptr;
-}
-
-std::unique_ptr<wm::TabletModeEventHandler>
-ShellPortMash::CreateTabletModeEventHandler() {
-  // TODO: need support for window manager to get events before client:
-  // http://crbug.com/624157.
-  NOTIMPLEMENTED_LOG_ONCE();
-  return nullptr;
-}
-
-std::unique_ptr<WorkspaceEventHandler>
-ShellPortMash::CreateWorkspaceEventHandler(aura::Window* workspace_window) {
-  return std::make_unique<WorkspaceEventHandlerMash>(workspace_window);
-}
-
-std::unique_ptr<KeyboardUI> ShellPortMash::CreateKeyboardUI() {
-  return KeyboardUIMash::Create(window_manager_->connector());
-}
-
-void ShellPortMash::AddPointerWatcher(views::PointerWatcher* watcher,
-                                      views::PointerWatcherEventTypes events) {
-  // TODO: implement drags for mus pointer watcher, http://crbug.com/641164.
-  // NOTIMPLEMENTED_LOG_ONCE drags for mus pointer watcher.
-  pointer_watcher_event_router_->AddPointerWatcher(
-      watcher, events == views::PointerWatcherEventTypes::MOVES);
-}
-
-void ShellPortMash::RemovePointerWatcher(views::PointerWatcher* watcher) {
-  pointer_watcher_event_router_->RemovePointerWatcher(watcher);
-}
-
-bool ShellPortMash::IsTouchDown() {
-  // TODO: implement me, http://crbug.com/634967.
-  return false;
-}
-
-void ShellPortMash::ToggleIgnoreExternalKeyboard() {
-  NOTIMPLEMENTED_LOG_ONCE();
-}
-
-void ShellPortMash::CreatePointerWatcherAdapter() {
-  // In Config::CLASSIC PointerWatcherAdapterClassic must be created when this
-  // function is called (it is order dependent), that is not the case with
-  // Config::MASH_DEPRECATED.
-}
-
-std::unique_ptr<AshWindowTreeHost> ShellPortMash::CreateAshWindowTreeHost(
-    const AshWindowTreeHostInitParams& init_params) {
-  auto display_params = std::make_unique<aura::DisplayInitParams>();
-  display_params->viewport_metrics.bounds_in_pixels =
-      init_params.initial_bounds;
-  display_params->viewport_metrics.device_scale_factor =
-      init_params.device_scale_factor;
-  display_params->viewport_metrics.ui_scale_factor =
-      init_params.ui_scale_factor;
-  display::DisplayManager* display_manager = Shell::Get()->display_manager();
-  display::Display mirrored_display =
-      display_manager->GetMirroringDisplayById(init_params.display_id);
-  if (mirrored_display.is_valid()) {
-    display_params->display =
-        std::make_unique<display::Display>(mirrored_display);
-  }
-  display_params->is_primary_display = true;
-  display_params->mirrors = display_manager->software_mirroring_display_list();
-  aura::WindowTreeHostMusInitParams aura_init_params =
-      window_manager_->window_manager_client()->CreateInitParamsForNewDisplay();
-  aura_init_params.display_id = init_params.display_id;
-  aura_init_params.display_init_params = std::move(display_params);
-  aura_init_params.use_classic_ime = !Shell::ShouldUseIMEService();
-  return std::make_unique<AshWindowTreeHostMus>(std::move(aura_init_params));
-}
-
-void ShellPortMash::OnCreatedRootWindowContainers(
-    RootWindowController* root_window_controller) {
-  // TODO: To avoid lots of IPC AddActivationParent() should take an array.
-  // http://crbug.com/682048.
-  aura::Window* root_window = root_window_controller->GetRootWindow();
-  for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
-    window_manager_->window_manager_client()->AddActivationParent(
-        root_window->GetChildById(kActivatableShellWindowIds[i]));
-  }
-
-  UpdateSystemModalAndBlockingContainers();
-}
-
-void ShellPortMash::UpdateSystemModalAndBlockingContainers() {
-  std::vector<aura::BlockingContainers> all_blocking_containers;
-  for (RootWindowController* root_window_controller :
-       Shell::GetAllRootWindowControllers()) {
-    aura::BlockingContainers blocking_containers;
-    wm::GetBlockingContainersForRoot(
-        root_window_controller->GetRootWindow(),
-        &blocking_containers.min_container,
-        &blocking_containers.system_modal_container);
-    all_blocking_containers.push_back(blocking_containers);
-  }
-  window_manager_->window_manager_client()->SetBlockingContainers(
-      all_blocking_containers);
-}
-
-void ShellPortMash::OnHostsInitialized() {
-  display_synchronizer_ = std::make_unique<DisplaySynchronizer>(
-      window_manager_->window_manager_client());
-}
-
-std::unique_ptr<display::NativeDisplayDelegate>
-ShellPortMash::CreateNativeDisplayDelegate() {
-  display::mojom::NativeDisplayDelegatePtr native_display_delegate;
-  if (window_manager_->connector()) {
-    window_manager_->connector()->BindInterface(ui::mojom::kServiceName,
-                                                &native_display_delegate);
-  }
-  return std::make_unique<display::ForwardingDisplayDelegate>(
-      std::move(native_display_delegate));
-}
-
-std::unique_ptr<AcceleratorController>
-ShellPortMash::CreateAcceleratorController() {
-  uint16_t accelerator_namespace_id = 0u;
-  const bool add_result =
-      window_manager_->GetNextAcceleratorNamespaceId(&accelerator_namespace_id);
-  // ShellPortMash is created early on, so that GetNextAcceleratorNamespaceId()
-  // should always succeed.
-  DCHECK(add_result);
-
-  accelerator_controller_registrar_ =
-      std::make_unique<AcceleratorControllerRegistrar>(
-          window_manager_, accelerator_namespace_id);
-  return std::make_unique<AcceleratorController>(
-      accelerator_controller_registrar_.get());
-}
-
-void ShellPortMash::AddVideoDetectorObserver(
-    viz::mojom::VideoDetectorObserverPtr observer) {
-  // We may not have access to the connector in unit tests.
-  if (!window_manager_->connector())
-    return;
-
-  ui::mojom::VideoDetectorPtr video_detector;
-  window_manager_->connector()->BindInterface(ui::mojom::kServiceName,
-                                              &video_detector);
-  video_detector->AddObserver(std::move(observer));
-}
-
-}  // namespace ash
diff --git a/ash/shell_port_mash.h b/ash/shell_port_mash.h
deleted file mode 100644
index cb32283a..0000000
--- a/ash/shell_port_mash.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_SHELL_PORT_MASH_H_
-#define ASH_SHELL_PORT_MASH_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "ash/shell_port.h"
-#include "base/macros.h"
-
-namespace views {
-class PointerWatcherEventRouter;
-}
-
-namespace ash {
-
-class AcceleratorControllerRegistrar;
-class DisplaySynchronizer;
-class ImmersiveHandlerFactoryMash;
-class WindowManager;
-
-// ShellPort implementation for mash. See ash/README.md for more.
-// NOTE: this is also used for OopAsh.
-class ShellPortMash : public ShellPort {
- public:
-  ShellPortMash(WindowManager* window_manager,
-                views::PointerWatcherEventRouter* pointer_watcher_event_router);
-  ~ShellPortMash() override;
-
-  static ShellPortMash* Get();
-
-  // Called when the window server has changed the mouse enabled state.
-  void OnCursorTouchVisibleChanged(bool enabled);
-
-  // ShellPort:
-  void Shutdown() override;
-  Config GetAshConfig() const override;
-  std::unique_ptr<display::TouchTransformSetter> CreateTouchTransformDelegate()
-      override;
-  void LockCursor() override;
-  void UnlockCursor() override;
-  void ShowCursor() override;
-  void HideCursor() override;
-  void SetCursorSize(ui::CursorSize cursor_size) override;
-  void SetGlobalOverrideCursor(base::Optional<ui::CursorData> cursor) override;
-  bool IsMouseEventsEnabled() override;
-  void SetCursorTouchVisible(bool enabled) override;
-  std::unique_ptr<WindowResizer> CreateDragWindowResizer(
-      std::unique_ptr<WindowResizer> next_window_resizer,
-      wm::WindowState* window_state) override;
-  std::unique_ptr<WindowCycleEventFilter> CreateWindowCycleEventFilter()
-      override;
-  std::unique_ptr<wm::TabletModeEventHandler> CreateTabletModeEventHandler()
-      override;
-  std::unique_ptr<WorkspaceEventHandler> CreateWorkspaceEventHandler(
-      aura::Window* workspace_window) override;
-  std::unique_ptr<KeyboardUI> CreateKeyboardUI() override;
-  void AddPointerWatcher(views::PointerWatcher* watcher,
-                         views::PointerWatcherEventTypes events) override;
-  void RemovePointerWatcher(views::PointerWatcher* watcher) override;
-  bool IsTouchDown() override;
-  void ToggleIgnoreExternalKeyboard() override;
-  void CreatePointerWatcherAdapter() override;
-  std::unique_ptr<AshWindowTreeHost> CreateAshWindowTreeHost(
-      const AshWindowTreeHostInitParams& init_params) override;
-  void OnCreatedRootWindowContainers(
-      RootWindowController* root_window_controller) override;
-  void UpdateSystemModalAndBlockingContainers() override;
-  void OnHostsInitialized() override;
-  std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
-      override;
-  std::unique_ptr<AcceleratorController> CreateAcceleratorController() override;
-  void AddVideoDetectorObserver(
-      viz::mojom::VideoDetectorObserverPtr observer) override;
-
- private:
-  WindowManager* window_manager_;
-  std::unique_ptr<DisplaySynchronizer> display_synchronizer_;
-  views::PointerWatcherEventRouter* pointer_watcher_event_router_ = nullptr;
-  std::unique_ptr<AcceleratorControllerRegistrar>
-      accelerator_controller_registrar_;
-  std::unique_ptr<ImmersiveHandlerFactoryMash> immersive_handler_factory_;
-
-  bool cursor_touch_visible_ = true;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellPortMash);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SHELL_PORT_MASH_H_
diff --git a/ash/system/model/system_tray_model.cc b/ash/system/model/system_tray_model.cc
index 0ec26911..bf9bc4a 100644
--- a/ash/system/model/system_tray_model.cc
+++ b/ash/system/model/system_tray_model.cc
@@ -78,8 +78,9 @@
 
 void SystemTrayModel::ShowUpdateIcon(mojom::UpdateSeverity severity,
                                      bool factory_reset_required,
+                                     bool rollback,
                                      mojom::UpdateType update_type) {
-  update_model()->SetUpdateAvailable(severity, factory_reset_required,
+  update_model()->SetUpdateAvailable(severity, factory_reset_required, rollback,
                                      update_type);
 }
 
diff --git a/ash/system/model/system_tray_model.h b/ash/system/model/system_tray_model.h
index ba14516..e0acc3b 100644
--- a/ash/system/model/system_tray_model.h
+++ b/ash/system/model/system_tray_model.h
@@ -38,6 +38,7 @@
   void SetPerformanceTracingIconVisible(bool visible) override;
   void ShowUpdateIcon(mojom::UpdateSeverity severity,
                       bool factory_reset_required,
+                      bool rollback,
                       mojom::UpdateType update_type) override;
   void SetUpdateOverCellularAvailableIconVisible(bool visible) override;
   void ShowVolumeSliderBubble() override;
diff --git a/ash/system/model/update_model.cc b/ash/system/model/update_model.cc
index caf6c33..2f30e6dc 100644
--- a/ash/system/model/update_model.cc
+++ b/ash/system/model/update_model.cc
@@ -19,10 +19,12 @@
 
 void UpdateModel::SetUpdateAvailable(mojom::UpdateSeverity severity,
                                      bool factory_reset_required,
+                                     bool rollback,
                                      mojom::UpdateType update_type) {
   update_required_ = true;
   severity_ = severity;
   factory_reset_required_ = factory_reset_required;
+  rollback_ = rollback;
   update_type_ = update_type;
   NotifyUpdateAvailable();
 }
diff --git a/ash/system/model/update_model.h b/ash/system/model/update_model.h
index b725544..b8557e5 100644
--- a/ash/system/model/update_model.h
+++ b/ash/system/model/update_model.h
@@ -28,11 +28,12 @@
   void RemoveObserver(UpdateObserver* observer);
 
   // Store the state that a software update is available. The state persists
-  // until reboot. Based on |severity| and |factory_reset_required|, the
-  // observer views can indicate the severity of the update to users by changing
-  // the icon, color, and tooltip.
+  // until reboot. Based on |severity|, |factory_reset_required| and |rollback|,
+  // the observer views can indicate the severity of the update to users by
+  // changing the icon, color, and tooltip.
   void SetUpdateAvailable(mojom::UpdateSeverity severity,
                           bool factory_reset_required,
+                          bool rollback,
                           mojom::UpdateType update_type);
 
   // If |available| is true, a software update is available but user's agreement
@@ -45,6 +46,7 @@
 
   bool update_required() const { return update_required_; }
   bool factory_reset_required() const { return factory_reset_required_; }
+  bool rollback() const { return rollback_; }
   mojom::UpdateType update_type() const { return update_type_; }
   bool update_over_cellular_available() const {
     return update_over_cellular_available_;
@@ -56,6 +58,7 @@
   bool update_required_ = false;
   mojom::UpdateSeverity severity_ = mojom::UpdateSeverity::NONE;
   bool factory_reset_required_ = false;
+  bool rollback_ = false;
   mojom::UpdateType update_type_ = mojom::UpdateType::SYSTEM;
   bool update_over_cellular_available_ = false;
 
diff --git a/ash/system/update/tray_update_unittest.cc b/ash/system/update/tray_update_unittest.cc
index 742bc13..99ed20c9 100644
--- a/ash/system/update/tray_update_unittest.cc
+++ b/ash/system/update/tray_update_unittest.cc
@@ -34,7 +34,7 @@
 
   // Simulate an update.
   Shell::Get()->system_tray_model()->ShowUpdateIcon(
-      mojom::UpdateSeverity::LOW, false, mojom::UpdateType::SYSTEM);
+      mojom::UpdateSeverity::LOW, false, false, mojom::UpdateType::SYSTEM);
 
   // Tray item is now visible.
   EXPECT_TRUE(tray_update->tray_view()->visible());
@@ -58,7 +58,7 @@
 
   // Simulate an update.
   Shell::Get()->system_tray_model()->ShowUpdateIcon(
-      mojom::UpdateSeverity::LOW, false, mojom::UpdateType::FLASH);
+      mojom::UpdateSeverity::LOW, false, false, mojom::UpdateType::FLASH);
 
   // Tray item is now visible.
   EXPECT_TRUE(tray_update->tray_view()->visible());
diff --git a/ash/system/update/update_notification_controller.cc b/ash/system/update/update_notification_controller.cc
index 00d5e4e..c0c4ac4e 100644
--- a/ash/system/update/update_notification_controller.cc
+++ b/ash/system/update/update_notification_controller.cc
@@ -45,6 +45,10 @@
     return;
   }
 
+  message_center::SystemNotificationWarningLevel warning_level =
+      model_->rollback()
+          ? message_center::SystemNotificationWarningLevel::WARNING
+          : message_center::SystemNotificationWarningLevel::NORMAL;
   std::unique_ptr<Notification> notification =
       Notification::CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
@@ -57,15 +61,18 @@
               base::BindRepeating(
                   &UpdateNotificationController::HandleNotificationClick,
                   weak_ptr_factory_.GetWeakPtr())),
-          kSystemMenuUpdateIcon,
-          message_center::SystemNotificationWarningLevel::NORMAL);
+          kSystemMenuUpdateIcon, warning_level);
   notification->set_pinned(true);
 
   if (model_->update_required()) {
     std::vector<message_center::ButtonInfo> notification_actions;
-    message_center::ButtonInfo button_info = message_center::ButtonInfo(
-        l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON));
-    notification_actions.push_back(button_info);
+    if (model_->rollback()) {
+      notification_actions.push_back(message_center::ButtonInfo(
+          l10n_util::GetStringUTF16(IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON)));
+    } else {
+      notification_actions.push_back(message_center::ButtonInfo(
+          l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON)));
+    }
     notification->set_buttons(notification_actions);
   }
 
@@ -79,6 +86,9 @@
 base::string16 UpdateNotificationController::GetNotificationMessage() const {
   base::string16 system_app_name =
       l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_SYSTEM_APP_NAME);
+  if (model_->rollback()) {
+    return l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK);
+  }
   if (model_->factory_reset_required()) {
     return l10n_util::GetStringFUTF16(IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH,
                                       system_app_name);
@@ -94,8 +104,9 @@
         IDS_UPDATE_NOTIFICATION_TITLE_FLASH_PLAYER);
   }
 #endif
-
-  return l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_TITLE);
+  return model_->rollback()
+             ? l10n_util::GetStringUTF16(IDS_ROLLBACK_NOTIFICATION_TITLE)
+             : l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_TITLE);
 }
 
 void UpdateNotificationController::HandleNotificationClick(
diff --git a/ash/system/update/update_notification_controller_unittest.cc b/ash/system/update/update_notification_controller_unittest.cc
index 25d6cde6..2ae8427 100644
--- a/ash/system/update/update_notification_controller_unittest.cc
+++ b/ash/system/update/update_notification_controller_unittest.cc
@@ -85,7 +85,7 @@
 
   // Simulate an update.
   Shell::Get()->system_tray_model()->ShowUpdateIcon(
-      mojom::UpdateSeverity::LOW, false, mojom::UpdateType::SYSTEM);
+      mojom::UpdateSeverity::LOW, false, false, mojom::UpdateType::SYSTEM);
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
@@ -103,7 +103,7 @@
 
   // Simulate an update.
   Shell::Get()->system_tray_model()->ShowUpdateIcon(
-      mojom::UpdateSeverity::LOW, false, mojom::UpdateType::FLASH);
+      mojom::UpdateSeverity::LOW, false, false, mojom::UpdateType::FLASH);
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
@@ -150,7 +150,7 @@
 
   // Simulate an update that requires factory reset.
   Shell::Get()->system_tray_model()->ShowUpdateIcon(
-      mojom::UpdateSeverity::LOW, true, mojom::UpdateType::SYSTEM);
+      mojom::UpdateSeverity::LOW, true, false, mojom::UpdateType::SYSTEM);
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
@@ -162,4 +162,23 @@
   EXPECT_EQ("Restart to update", GetNotificationButton(0));
 }
 
+TEST_F(UpdateNotificationControllerTest, VisibilityAfterRollback) {
+  // The system starts with no update pending, so the notification isn't
+  // visible.
+  EXPECT_FALSE(HasNotification());
+
+  // Simulate a rollback.
+  Shell::Get()->system_tray_model()->ShowUpdateIcon(
+      mojom::UpdateSeverity::LOW, false, true, mojom::UpdateType::SYSTEM);
+
+  // The notification is now visible.
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ("Device will be rolled back", GetNotificationTitle());
+  EXPECT_EQ(
+      "Your administrator is rolling back your device. All data will"
+      " be deleted when the device is restarted.",
+      GetNotificationMessage());
+  EXPECT_EQ("Restart and reset", GetNotificationButton(0));
+}
+
 }  // namespace ash
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 6cc777b..bfb6b27 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -29,8 +29,6 @@
 #include "ash/test_screenshot_delegate.h"
 #include "ash/test_shell_delegate.h"
 #include "ash/utility/screenshot_controller.h"
-#include "ash/window_manager.h"
-#include "ash/window_manager_service.h"
 #include "ash/wm/top_level_window_factory.h"
 #include "ash/wm/window_positioner.h"
 #include "ash/ws/window_service_owner.h"
@@ -136,10 +134,6 @@
 
 AshTestBase::AshTestBase()
     : setup_called_(false), teardown_called_(false), start_session_(true) {
-  if (AshTestHelper::config() != Config::CLASSIC) {
-    CHECK(aura::Env::GetInstance());
-    aura::Env::GetInstance()->AddObserver(this);
-  }
   ash_test_environment_ = AshTestEnvironment::Create();
 
   // Must initialize |ash_test_helper_| here because some tests rely on
@@ -152,8 +146,6 @@
       << "You have overridden SetUp but never called AshTestBase::SetUp";
   CHECK(teardown_called_)
       << "You have overridden TearDown but never called AshTestBase::TearDown";
-  if (AshTestHelper::config() != Config::CLASSIC)
-    aura::Env::GetInstance()->RemoveObserver(this);
 }
 
 void AshTestBase::SetUp() {
@@ -288,12 +280,6 @@
 
   const ui::mojom::WindowType mus_window_type =
       MusWindowTypeFromWindowType(type);
-  if (AshTestHelper::config() == Config::MASH_DEPRECATED) {
-    // For mash route creation through the window manager. This better simulates
-    // what happens when a client creates a top level window.
-    return CreateTestWindowMash(mus_window_type, shell_window_id, &properties);
-  }
-
   properties[ui::mojom::WindowManager::kWindowType_InitProperty] =
       mojo::ConvertTo<std::vector<uint8_t>>(
           static_cast<int32_t>(mus_window_type));
@@ -310,11 +296,6 @@
 std::unique_ptr<aura::Window> AshTestBase::CreateToplevelTestWindow(
     const gfx::Rect& bounds_in_screen,
     int shell_window_id) {
-  if (AshTestHelper::config() == Config::MASH_DEPRECATED) {
-    return CreateTestWindow(bounds_in_screen, aura::client::WINDOW_TYPE_NORMAL,
-                            shell_window_id);
-  }
-
   aura::test::TestWindowDelegate* delegate =
       aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate();
   return base::WrapUnique<aura::Window>(
@@ -558,20 +539,6 @@
   return window_tree_.get();
 }
 
-std::unique_ptr<aura::Window> AshTestBase::CreateTestWindowMash(
-    ui::mojom::WindowType window_type,
-    int shell_window_id,
-    std::map<std::string, std::vector<uint8_t>>* properties) {
-  WindowManager* window_manager =
-      ash_test_helper_->window_manager_service()->window_manager();
-  aura::Window* window = CreateAndParentTopLevelWindow(
-      window_manager, window_type, window_manager->property_converter(),
-      properties);
-  window->set_id(shell_window_id);
-  window->Show();
-  return base::WrapUnique<aura::Window>(window);
-}
-
 void AshTestBase::CreateWindowTreeIfNecessary() {
   if (window_tree_client_)
     return;
@@ -586,21 +553,4 @@
       std::make_unique<ui::ws2::WindowTreeTestHelper>(window_tree_.get());
 }
 
-void AshTestBase::OnWindowInitialized(aura::Window* window) {}
-
-void AshTestBase::OnHostInitialized(aura::WindowTreeHost* host) {
-  // AshTestBase outlives all the WindowTreeHosts. So RemoveObserver() is not
-  // necessary.
-  host->AddObserver(this);
-  OnHostResized(host);
-}
-
-void AshTestBase::OnHostResized(aura::WindowTreeHost* host) {
-  // The local surface id comes from the window server. However, there is no
-  // window server in tests. So a fake id is assigned so that the layer
-  // compositor can submit compositor frames.
-  viz::LocalSurfaceId id(1, base::UnguessableToken::Create());
-  host->compositor()->SetLocalSurfaceId(id);
-}
-
 }  // namespace ash
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index fde47dc..3c5274c 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -17,8 +17,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/aura/client/window_types.h"
-#include "ui/aura/env_observer.h"
-#include "ui/aura/window_tree_host_observer.h"
 #include "ui/display/display.h"
 
 namespace aura {
@@ -40,9 +38,6 @@
 }
 
 namespace ui {
-namespace mojom {
-enum class WindowType;
-}
 namespace test {
 class EventGenerator;
 }
@@ -69,9 +64,7 @@
 class TestSessionControllerClient;
 class UnifiedSystemTray;
 
-class AshTestBase : public testing::Test,
-                    public aura::EnvObserver,
-                    public aura::WindowTreeHostObserver {
+class AshTestBase : public testing::Test {
  public:
   AshTestBase();
   ~AshTestBase() override;
@@ -246,20 +239,8 @@
   ui::ws2::WindowTree* GetWindowTree();
 
  private:
-  std::unique_ptr<aura::Window> CreateTestWindowMash(
-      ui::mojom::WindowType window_type,
-      int shell_window_id,
-      std::map<std::string, std::vector<uint8_t>>* properties);
-
   void CreateWindowTreeIfNecessary();
 
-  // aura::EnvObserver:
-  void OnWindowInitialized(aura::Window* window) override;
-  void OnHostInitialized(aura::WindowTreeHost* host) override;
-
-  // aura::WindowTreeHostObserver:
-  void OnHostResized(aura::WindowTreeHost* host) override;
-
   bool setup_called_;
   bool teardown_called_;
   // |SetUp()| doesn't activate session if this is set to false.
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 4d9f157..b68e4c3 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -13,19 +13,15 @@
 #include "ash/display/display_configuration_controller_test_api.h"
 #include "ash/display/screen_ash.h"
 #include "ash/public/cpp/ash_switches.h"
-#include "ash/public/cpp/config.h"
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shell_init_params.h"
 #include "ash/shell_port.h"
 #include "ash/shell_port_classic.h"
-#include "ash/shell_port_mash.h"
 #include "ash/system/screen_layout_observer.h"
 #include "ash/test/ash_test_environment.h"
 #include "ash/test/ash_test_views_delegate.h"
 #include "ash/test_shell_delegate.h"
-#include "ash/window_manager.h"
-#include "ash/window_manager_service.h"
 #include "ash/ws/window_service_owner.h"
 #include "base/guid.h"
 #include "base/run_loop.h"
@@ -47,10 +43,8 @@
 #include "services/ui/ws2/window_service.h"
 #include "ui/aura/env.h"
 #include "ui/aura/input_state_lookup.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/test/env_test_helper.h"
 #include "ui/aura/test/event_generator_delegate_aura.h"
-#include "ui/aura/test/mus/window_tree_client_private.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/platform_window_defaults.h"
@@ -152,9 +146,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestConnector);
 };
 
-// static
-Config AshTestHelper::config_ = Config::CLASSIC;
-
 AshTestHelper::AshTestHelper(AshTestEnvironment* ash_test_environment)
     : ash_test_environment_(ash_test_environment),
       command_line_(std::make_unique<base::test::ScopedCommandLine>()) {
@@ -191,11 +182,7 @@
   }
 
   display::ResetDisplayIdForTest();
-  if (config_ != Config::CLASSIC)
-    aura::test::EnvTestHelper().SetAlwaysUseLastMouseLocation(true);
-  // WindowManager creates WMState for mash.
-  if (config_ == Config::CLASSIC)
-    wm_state_ = std::make_unique<::wm::WMState>();
+  wm_state_ = std::make_unique<::wm::WMState>();
   test_views_delegate_ = ash_test_environment_->CreateViewsDelegate();
 
   // Disable animations during tests.
@@ -207,34 +194,30 @@
   if (!test_shell_delegate_)
     test_shell_delegate_ = new TestShellDelegate;
 
-  if (config_ == Config::CLASSIC) {
-    // All of this initialization is done in WindowManagerService for mash.
-
-    if (!chromeos::DBusThreadManager::IsInitialized()) {
-      chromeos::DBusThreadManager::Initialize(
-          chromeos::DBusThreadManager::kShared);
-      dbus_thread_manager_initialized_ = true;
-    }
-
-    if (!bluez::BluezDBusManager::IsInitialized()) {
-      bluez::BluezDBusManager::Initialize(
-          chromeos::DBusThreadManager::Get()->GetSystemBus(),
-          chromeos::DBusThreadManager::Get()->IsUsingFakes());
-      bluez_dbus_manager_initialized_ = true;
-    }
-
-    if (!chromeos::PowerPolicyController::IsInitialized()) {
-      chromeos::PowerPolicyController::Initialize(
-          chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
-      power_policy_controller_initialized_ = true;
-    }
-
-    // Create CrasAudioHandler for testing since g_browser_process is not
-    // created in AshTestBase tests.
-    chromeos::CrasAudioHandler::InitializeForTesting();
-    chromeos::SystemSaltGetter::Initialize();
+  if (!chromeos::DBusThreadManager::IsInitialized()) {
+    chromeos::DBusThreadManager::Initialize(
+        chromeos::DBusThreadManager::kShared);
+    dbus_thread_manager_initialized_ = true;
   }
 
+  if (!bluez::BluezDBusManager::IsInitialized()) {
+    bluez::BluezDBusManager::Initialize(
+        chromeos::DBusThreadManager::Get()->GetSystemBus(),
+        chromeos::DBusThreadManager::Get()->IsUsingFakes());
+    bluez_dbus_manager_initialized_ = true;
+  }
+
+  if (!chromeos::PowerPolicyController::IsInitialized()) {
+    chromeos::PowerPolicyController::Initialize(
+        chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
+    power_policy_controller_initialized_ = true;
+  }
+
+  // Create CrasAudioHandler for testing since g_browser_process is not
+  // created in AshTestBase tests.
+  chromeos::CrasAudioHandler::InitializeForTesting();
+  chromeos::SystemSaltGetter::Initialize();
+
   ash_test_environment_->SetUp();
   // Reset the global state for the cursor manager. This includes the
   // last cursor visibility state, etc.
@@ -245,10 +228,7 @@
   ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
 
-  if (config_ != Config::CLASSIC)
-    CreateMashWindowManager();
-  else
-    CreateShell();
+  CreateShell();
 
   aura::test::EnvTestHelper().SetInputStateLookup(
       std::unique_ptr<aura::InputStateLookup>());
@@ -287,28 +267,21 @@
 
   app_list_test_helper_ = std::make_unique<AppListTestHelper>();
 
-  if (config_ == Config::CLASSIC)
-    CreateWindowService();
+  CreateWindowService();
 }
 
 void AshTestHelper::TearDown() {
   app_list_test_helper_.reset();
 
-  window_manager_service_.reset();
-
-  // WindowManger owns the Shell in mash.
-  if (config_ == Config::CLASSIC)
-    Shell::DeleteInstance();
+  Shell::DeleteInstance();
 
   // Suspend the tear down until all resources are returned via
   // CompositorFrameSinkClient::ReclaimResources()
   base::RunLoop().RunUntilIdle();
   ash_test_environment_->TearDown();
 
-  if (config_ == Config::CLASSIC) {
-    chromeos::SystemSaltGetter::Shutdown();
-    chromeos::CrasAudioHandler::Shutdown();
-  }
+  chromeos::SystemSaltGetter::Shutdown();
+  chromeos::CrasAudioHandler::Shutdown();
 
   if (power_policy_controller_initialized_) {
     chromeos::PowerPolicyController::Shutdown();
@@ -326,8 +299,7 @@
     dbus_thread_manager_initialized_ = false;
   }
 
-  if (config_ == Config::CLASSIC)
-    ui::TerminateContextFactoryForTests();
+  ui::TerminateContextFactoryForTests();
 
   ui::ShutdownInputMethodForTesting();
   zero_duration_mode_.reset();
@@ -340,8 +312,7 @@
   display::Display::ResetForceDeviceScaleFactorForTesting();
   env_window_tree_client_setter_.reset();
 
-  // WindowManager owns the CaptureController for mus/mash.
-  CHECK(config_ != Config::CLASSIC || !::wm::CaptureController::Get());
+  CHECK(!::wm::CaptureController::Get());
 }
 
 PrefService* AshTestHelper::GetLocalStatePrefService() {
@@ -373,39 +344,7 @@
   // state.
 }
 
-void AshTestHelper::CreateMashWindowManager() {
-  CHECK_EQ(config_, Config::MASH_DEPRECATED);
-  const bool show_primary_root_on_connect = false;
-  window_manager_service_ =
-      std::make_unique<WindowManagerService>(show_primary_root_on_connect);
-
-  window_manager_service_->window_manager_.reset(
-      new WindowManager(nullptr, show_primary_root_on_connect));
-  window_manager_service_->window_manager()->shell_delegate_.reset(
-      test_shell_delegate_);
-
-  window_tree_client_setup_.InitForWindowManager(
-      window_manager_service_->window_manager_.get(),
-      window_manager_service_->window_manager_.get());
-  env_window_tree_client_setter_ =
-      std::make_unique<aura::test::EnvWindowTreeClientSetter>(
-          window_tree_client_setup_.window_tree_client());
-  // Classic ash does not start the NetworkHandler in tests, so don't start it
-  // for mash either. The NetworkHandler may cause subtle side effects (such as
-  // additional tray items) that can make for flaky tests.
-  const bool init_network_handler = false;
-  window_manager_service_->InitWindowManager(
-      window_tree_client_setup_.OwnWindowTreeClient(), init_network_handler);
-
-  aura::WindowTreeClient* window_tree_client =
-      window_manager_service_->window_manager()->window_tree_client();
-  window_tree_client_private_ =
-      std::make_unique<aura::WindowTreeClientPrivate>(window_tree_client);
-  window_tree_client_private_->CallOnConnect();
-}
-
 void AshTestHelper::CreateShell() {
-  CHECK(config_ == Config::CLASSIC);
   ui::ContextFactory* context_factory = nullptr;
   ui::ContextFactoryPrivate* context_factory_private = nullptr;
   bool enable_pixel_output = false;
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index e215fb1..6c90d1ba 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -13,13 +13,11 @@
 #include "ash/session/test_session_controller_client.h"
 #include "base/macros.h"
 #include "base/test/scoped_command_line.h"
-#include "ui/aura/test/mus/test_window_tree_client_setup.h"
 
 class PrefService;
 
 namespace aura {
 class Window;
-class WindowTreeClientPrivate;
 namespace test {
 class EnvWindowTreeClientSetter;
 }
@@ -29,12 +27,6 @@
 class Display;
 }
 
-namespace mash {
-namespace test {
-class MashTestSuite;
-}
-}
-
 namespace ui {
 class ScopedAnimationDurationScaleMode;
 }
@@ -50,9 +42,6 @@
 class AshTestViewsDelegate;
 class TestConnector;
 class TestShellDelegate;
-class WindowManagerService;
-
-enum class Config;
 
 // A helper class that does common initialization required for Ash. Creates a
 // root window and an ash::Shell instance with a test delegate.
@@ -61,10 +50,6 @@
   explicit AshTestHelper(AshTestEnvironment* ash_test_environment);
   ~AshTestHelper();
 
-  // Returns the configuration that tests are run in. See ash::Config enum for
-  // details.
-  static Config config() { return config_; }
-
   // Creates the ash::Shell and performs associated initialization.  Set
   // |start_session| to true if the user should log in before the test is run.
   // Set |provide_local_state| to true to inject local-state PrefService into
@@ -93,14 +78,6 @@
 
   display::Display GetSecondaryDisplay();
 
-  // Null in classic ash.
-  WindowManagerService* window_manager_service() {
-    return window_manager_service_.get();
-  }
-  aura::TestWindowTreeClientSetup* window_tree_client_setup() {
-    return &window_tree_client_setup_;
-  }
-
   TestSessionControllerClient* test_session_controller_client() {
     return session_controller_client_.get();
   }
@@ -116,22 +93,13 @@
   void reset_commandline() { command_line_.reset(); }
 
  private:
-  // These TestSuites need to manipulate |config_|.
-  friend class AshTestSuite;
-  friend class mash::test::MashTestSuite;
-
   // Forces creation of the WindowService. The WindowService is normally created
   // on demand, this force the creation.
   void CreateWindowService();
 
-  // Called when running in mash to create the WindowManager.
-  void CreateMashWindowManager();
-
   // Called when running in ash to create Shell.
   void CreateShell();
 
-  static Config config_;
-
   std::unique_ptr<aura::test::EnvWindowTreeClientSetter>
       env_window_tree_client_setter_;
   AshTestEnvironment* ash_test_environment_;  // Not owned.
@@ -148,10 +116,6 @@
   // Check if PowerPolicyController was initialized here.
   bool power_policy_controller_initialized_ = false;
 
-  aura::TestWindowTreeClientSetup window_tree_client_setup_;
-  std::unique_ptr<WindowManagerService> window_manager_service_;
-  std::unique_ptr<aura::WindowTreeClientPrivate> window_tree_client_private_;
-
   std::unique_ptr<TestSessionControllerClient> session_controller_client_;
 
   std::unique_ptr<base::test::ScopedCommandLine> command_line_;
diff --git a/ash/test/ash_test_suite.cc b/ash/test/ash_test_suite.cc
index 2f738ac..1a30804 100644
--- a/ash/test/ash_test_suite.cc
+++ b/ash/test/ash_test_suite.cc
@@ -4,19 +4,14 @@
 
 #include "ash/test/ash_test_suite.h"
 
-#include "ash/public/cpp/config.h"
 #include "ash/test/ash_test_environment.h"
 #include "ash/test/ash_test_helper.h"
-#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/i18n/rtl.h"
 #include "base/path_service.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/test/aura_test_context_factory.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/compositor/test/context_factories_for_test.h"
@@ -60,18 +55,8 @@
         ash_test_resources_200, ui::SCALE_FACTOR_200P);
   }
 
-  const bool is_mash = base::FeatureList::IsEnabled(features::kMashDeprecated);
-  AshTestHelper::config_ = is_mash ? Config::MASH_DEPRECATED : Config::CLASSIC;
-
   base::DiscardableMemoryAllocator::SetInstance(&discardable_memory_allocator_);
-  env_ = aura::Env::CreateInstance(is_mash ? aura::Env::Mode::MUS
-                                           : aura::Env::Mode::LOCAL);
-
-  if (is_mash) {
-    context_factory_ = std::make_unique<aura::test::AuraTestContextFactory>();
-    env_->set_context_factory(context_factory_.get());
-    env_->set_context_factory_private(nullptr);
-  }
+  env_ = aura::Env::CreateInstance();
 }
 
 void AshTestSuite::Shutdown() {
diff --git a/ash/test/ash_test_suite.h b/ash/test/ash_test_suite.h
index 06ced79..33619a0b 100644
--- a/ash/test/ash_test_suite.h
+++ b/ash/test/ash_test_suite.h
@@ -12,10 +12,6 @@
 #include "base/test/test_suite.h"
 #include "ui/aura/env.h"
 
-namespace ui {
-class ContextFactory;
-}
-
 namespace ash {
 
 class AshTestSuite : public base::TestSuite {
@@ -33,10 +29,6 @@
 
   base::TestDiscardableMemoryAllocator discardable_memory_allocator_;
 
-  // Only used when running in mus/mash, and is set as the context_factory
-  // on aura::Env.
-  std::unique_ptr<ui::ContextFactory> context_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(AshTestSuite);
 };
 
diff --git a/ash/window_manager.cc b/ash/window_manager.cc
deleted file mode 100644
index a27003d..0000000
--- a/ash/window_manager.cc
+++ /dev/null
@@ -1,479 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/window_manager.h"
-
-#include <stdint.h>
-
-#include <limits>
-#include <memory>
-#include <utility>
-
-#include "ash/accelerators/accelerator_handler.h"
-#include "ash/accelerators/accelerator_ids.h"
-#include "ash/display/window_tree_host_manager.h"
-#include "ash/drag_drop/drag_image_view.h"
-#include "ash/event_matcher_util.h"
-#include "ash/host/ash_window_tree_host.h"
-#include "ash/public/cpp/window_properties.h"
-#include "ash/public/cpp/window_state_type.h"
-#include "ash/public/interfaces/window_actions.mojom.h"
-#include "ash/root_window_controller.h"
-#include "ash/root_window_settings.h"
-#include "ash/session/session_controller.h"
-#include "ash/shell.h"
-#include "ash/shell_delegate_mash.h"
-#include "ash/shell_init_params.h"
-#include "ash/shell_port_mash.h"
-#include "ash/wm/ash_focus_rules.h"
-#include "ash/wm/move_event_handler.h"
-#include "ash/wm/non_client_frame_controller.h"
-#include "ash/wm/property_util.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller.h"
-#include "ash/wm/top_level_window_factory.h"
-#include "ash/wm/window_properties.h"
-#include "ash/wm/window_state.h"
-#include "components/exo/file_helper.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/ui/common/accelerator_util.h"
-#include "services/ui/common/types.h"
-#include "services/ui/public/cpp/input_devices/input_device_client.h"
-#include "services/ui/public/cpp/property_type_converters.h"
-#include "services/ui/public/interfaces/constants.mojom.h"
-#include "services/ui/public/interfaces/window_manager.mojom.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/window_parenting_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/mus/capture_synchronizer.h"
-#include "ui/aura/mus/property_converter.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
-#include "ui/aura/window.h"
-#include "ui/base/class_property.h"
-#include "ui/base/hit_test.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/display/display_observer.h"
-#include "ui/events/mojo/event.mojom.h"
-#include "ui/views/mus/pointer_watcher_event_router.h"
-#include "ui/wm/core/capture_controller.h"
-#include "ui/wm/core/window_animations.h"
-#include "ui/wm/core/wm_state.h"
-#include "ui/wm/public/activation_client.h"
-
-namespace ash {
-
-struct WindowManager::DragState {
-  // An image representation of the contents of the current drag and drop
-  // clipboard.
-  std::unique_ptr<ash::DragImageView> view;
-
-  // The cursor offset of the dragged item.
-  gfx::Vector2d image_offset;
-};
-
-// TODO: need to register OSExchangeDataProviderMus. http://crbug.com/665077.
-WindowManager::WindowManager(service_manager::Connector* connector,
-                             bool show_primary_host_on_connect)
-    : connector_(connector),
-      show_primary_host_on_connect_(show_primary_host_on_connect),
-      wm_state_(std::make_unique<::wm::WMState>()),
-      property_converter_(std::make_unique<aura::PropertyConverter>()) {
-  DCHECK(!features::IsAshInBrowserProcess());
-  RegisterWindowProperties(property_converter_.get());
-}
-
-WindowManager::~WindowManager() {
-  Shutdown();
-  ash::Shell::set_window_tree_client(nullptr);
-  ash::Shell::set_window_manager_client(nullptr);
-}
-
-void WindowManager::Init(
-    std::unique_ptr<aura::WindowTreeClient> window_tree_client,
-    std::unique_ptr<base::Value> initial_display_prefs) {
-  input_device_client_ = std::make_unique<ui::InputDeviceClient>();
-
-  // |connector_| can be nullptr in tests.
-  if (connector_) {
-    ui::mojom::InputDeviceServerPtr server;
-    connector_->BindInterface(ui::mojom::kServiceName, &server);
-    input_device_client_->Connect(std::move(server));
-  }
-
-  DCHECK(window_manager_client_);
-  DCHECK(!window_tree_client_);
-  window_tree_client_ = std::move(window_tree_client);
-
-  DCHECK_EQ(nullptr, ash::Shell::window_tree_client());
-  ash::Shell::set_window_tree_client(window_tree_client_.get());
-
-  pointer_watcher_event_router_ =
-      std::make_unique<views::PointerWatcherEventRouter>(
-          window_tree_client_.get());
-
-  // Notify PointerWatcherEventRouter and CaptureSynchronizer that the capture
-  // client has been set.
-  aura::client::CaptureClient* capture_client = wm_state_->capture_controller();
-  pointer_watcher_event_router_->AttachToCaptureClient(capture_client);
-  window_tree_client_->capture_synchronizer()->AttachToCaptureClient(
-      capture_client);
-
-  initial_display_prefs_ = std::move(initial_display_prefs);
-
-  InitCursorOnKeyList();
-}
-
-bool WindowManager::GetNextAcceleratorNamespaceId(uint16_t* id) {
-  if (accelerator_handlers_.size() == std::numeric_limits<uint16_t>::max())
-    return false;
-  while (accelerator_handlers_.count(next_accelerator_namespace_id_) > 0)
-    ++next_accelerator_namespace_id_;
-  *id = next_accelerator_namespace_id_;
-  ++next_accelerator_namespace_id_;
-  return true;
-}
-
-void WindowManager::AddAcceleratorHandler(uint16_t id_namespace,
-                                          AcceleratorHandler* handler) {
-  DCHECK_EQ(0u, accelerator_handlers_.count(id_namespace));
-  accelerator_handlers_[id_namespace] = handler;
-}
-
-void WindowManager::RemoveAcceleratorHandler(uint16_t id_namespace) {
-  accelerator_handlers_.erase(id_namespace);
-}
-
-display::mojom::DisplayController* WindowManager::GetDisplayController() {
-  return display_controller_ ? display_controller_.get() : nullptr;
-}
-
-void WindowManager::CreateShell() {
-  DCHECK(!created_shell_);
-  created_shell_ = true;
-  ShellInitParams init_params;
-  init_params.shell_port = std::make_unique<ShellPortMash>(
-      this, pointer_watcher_event_router_.get());
-  init_params.delegate = shell_delegate_
-                             ? std::move(shell_delegate_)
-                             : std::make_unique<ShellDelegateMash>(connector_);
-  init_params.initial_display_prefs = std::move(initial_display_prefs_);
-  Shell::CreateInstance(std::move(init_params));
-}
-
-void WindowManager::InitCursorOnKeyList() {
-  DCHECK(window_manager_client_);
-  // In Mash, we build a list of keys and send them to the window
-  // server. This controls which keys *don't* hide the cursors.
-
-  // TODO(erg): This needs to also check the case of the accessibility
-  // keyboard being shown, since clicking a key on the keyboard shouldn't
-  // hide the cursor.
-  std::vector<ui::mojom::EventMatcherPtr> cursor_key_list;
-  cursor_key_list.push_back(BuildKeyReleaseMatcher());
-  cursor_key_list.push_back(BuildAltMatcher());
-  cursor_key_list.push_back(BuildControlMatcher());
-
-  BuildKeyMatcherRange(ui::mojom::KeyboardCode::F1,
-                       ui::mojom::KeyboardCode::F24, &cursor_key_list);
-  BuildKeyMatcherRange(ui::mojom::KeyboardCode::BROWSER_BACK,
-                       ui::mojom::KeyboardCode::MEDIA_LAUNCH_APP2,
-                       &cursor_key_list);
-  BuildKeyMatcherList(
-      {ui::mojom::KeyboardCode::SHIFT, ui::mojom::KeyboardCode::CONTROL,
-       ui::mojom::KeyboardCode::MENU,
-       ui::mojom::KeyboardCode::LWIN,  // Search key == VKEY_LWIN.
-       ui::mojom::KeyboardCode::WLAN, ui::mojom::KeyboardCode::POWER,
-       ui::mojom::KeyboardCode::BRIGHTNESS_DOWN,
-       ui::mojom::KeyboardCode::BRIGHTNESS_UP,
-       ui::mojom::KeyboardCode::KBD_BRIGHTNESS_DOWN,
-       ui::mojom::KeyboardCode::KBD_BRIGHTNESS_UP},
-      &cursor_key_list);
-
-  window_manager_client_->SetKeyEventsThatDontHideCursor(
-      std::move(cursor_key_list));
-}
-
-void WindowManager::InstallFrameDecorationValues() {
-  ui::mojom::FrameDecorationValuesPtr frame_decoration_values =
-      ui::mojom::FrameDecorationValues::New();
-  const gfx::Insets client_area_insets =
-      NonClientFrameController::GetPreferredClientAreaInsets();
-  frame_decoration_values->normal_client_area_insets = client_area_insets;
-  frame_decoration_values->maximized_client_area_insets = client_area_insets;
-  frame_decoration_values->max_title_bar_button_width =
-      NonClientFrameController::GetMaxTitleBarButtonWidth();
-  window_manager_client_->SetFrameDecorationValues(
-      std::move(frame_decoration_values));
-}
-
-void WindowManager::Shutdown() {
-  if (!window_tree_client_)
-    return;
-
-  aura::client::CaptureClient* capture_client = wm_state_->capture_controller();
-  pointer_watcher_event_router_->DetachFromCaptureClient(capture_client);
-  window_tree_client_->capture_synchronizer()->DetachFromCaptureClient(
-      capture_client);
-
-  Shell::DeleteInstance();
-
-  pointer_watcher_event_router_.reset();
-
-  window_tree_client_.reset();
-  window_manager_client_ = nullptr;
-}
-
-void WindowManager::OnEmbed(
-    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
-  // WindowManager should never see this, instead OnWmNewDisplay() is called.
-  NOTREACHED();
-}
-
-void WindowManager::OnEmbedRootDestroyed(
-    aura::WindowTreeHostMus* window_tree_host) {
-  // WindowManager should never see this.
-  NOTREACHED();
-}
-
-void WindowManager::OnLostConnection(aura::WindowTreeClient* client) {
-  DCHECK_EQ(client, window_tree_client_.get());
-  Shutdown();
-  // TODO(sky): this case should trigger shutting down WindowManagerService too.
-}
-
-void WindowManager::OnPointerEventObserved(const ui::PointerEvent& event,
-                                           int64_t display_id,
-                                           aura::Window* target) {
-  pointer_watcher_event_router_->OnPointerEventObserved(event, display_id,
-                                                        target);
-}
-
-aura::PropertyConverter* WindowManager::GetPropertyConverter() {
-  return property_converter_.get();
-}
-
-void WindowManager::SetWindowManagerClient(aura::WindowManagerClient* client) {
-  window_manager_client_ = client;
-  ash::Shell::set_window_manager_client(client);
-}
-
-void WindowManager::OnWmConnected() {
-  // InstallFrameDecorationValues() must be called before the shell is created,
-  // otherwise Mus attempts to notify clients with no frame decorations, which
-  // triggers validation errors.
-  InstallFrameDecorationValues();
-  CreateShell();
-  if (show_primary_host_on_connect_)
-    Shell::GetPrimaryRootWindow()->GetHost()->Show();
-
-  // TODO(hirono): wire up the file helper. http://crbug.com/768395
-  Shell::Get()->InitWaylandServer(nullptr);
-}
-
-void WindowManager::OnWmAcceleratedWidgetAvailableForDisplay(
-    int64_t display_id,
-    gfx::AcceleratedWidget widget) {
-  WindowTreeHostManager* manager = Shell::Get()->window_tree_host_manager();
-  AshWindowTreeHost* host =
-      manager->GetAshWindowTreeHostForDisplayId(display_id);
-  // The display may have been destroyed before getting this async callback.
-  if (host && host->AsWindowTreeHost()) {
-    static_cast<aura::WindowTreeHostMus*>(host->AsWindowTreeHost())
-        ->OverrideAcceleratedWidget(widget);
-  }
-}
-
-void WindowManager::OnWmSetBounds(aura::Window* window,
-                                  const gfx::Rect& bounds) {
-  // TODO(sky): this indirectly sets bounds, which is against what
-  // OnWmSetBounds() recommends doing. Remove that restriction, or fix this.
-  window->SetBounds(bounds);
-}
-
-bool WindowManager::OnWmSetProperty(
-    aura::Window* window,
-    const std::string& name,
-    std::unique_ptr<std::vector<uint8_t>>* new_data) {
-  if (property_converter_->IsTransportNameRegistered(name))
-    return true;
-  DVLOG(1) << "unknown property changed, ignoring " << name;
-  return false;
-}
-
-void WindowManager::OnWmSetModalType(aura::Window* window, ui::ModalType type) {
-  ui::ModalType old_type = window->GetProperty(aura::client::kModalKey);
-  if (type == old_type)
-    return;
-
-  window->SetProperty(aura::client::kModalKey, type);
-  // Assume the client has positioned the window in the right container and
-  // don't attempt to change the parent. This is currently true for Chrome
-  // code, but likely there should be checks. Adding checks is complicated by
-  // the fact that assumptions in GetSystemModalContainer() are not always
-  // valid for Chrome code. In particular Chrome code may create system modal
-  // dialogs without a transient parent that Chrome wants shown on the lock
-  // screen.
-}
-
-void WindowManager::OnWmSetCanFocus(aura::Window* window, bool can_focus) {
-  NonClientFrameController* non_client_frame_controller =
-      NonClientFrameController::Get(window);
-  if (non_client_frame_controller)
-    non_client_frame_controller->set_can_activate(can_focus);
-}
-
-aura::Window* WindowManager::OnWmCreateTopLevelWindow(
-    ui::mojom::WindowType window_type,
-    std::map<std::string, std::vector<uint8_t>>* properties) {
-  if (window_type == ui::mojom::WindowType::UNKNOWN) {
-    LOG(WARNING) << "Request to create top level of unknown type, failing";
-    return nullptr;
-  }
-
-  return CreateAndParentTopLevelWindow(this, window_type,
-                                       property_converter_.get(), properties);
-}
-
-void WindowManager::OnWmClientJankinessChanged(
-    const std::set<aura::Window*>& client_windows,
-    bool janky) {
-  for (auto* window : client_windows)
-    window->SetProperty(kWindowIsJanky, janky);
-}
-
-void WindowManager::OnWmBuildDragImage(const gfx::Point& screen_location,
-                                       const gfx::ImageSkia& drag_image,
-                                       const gfx::Vector2d& drag_image_offset,
-                                       ui::mojom::PointerKind source) {
-  if (drag_image.isNull())
-    return;
-
-  // TODO(erg): Get the right display for this drag image. Right now, none of
-  // the drag drop code is multidisplay aware.
-  aura::Window* root_window = Shell::GetPrimaryRootWindow();
-
-  ui::DragDropTypes::DragEventSource ui_source =
-      source == ui::mojom::PointerKind::MOUSE
-          ? ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
-          : ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
-  std::unique_ptr<DragImageView> drag_view =
-      std::make_unique<DragImageView>(root_window, ui_source);
-  drag_view->SetImage(drag_image);
-  gfx::Size size = drag_view->GetPreferredSize();
-  gfx::Rect drag_image_bounds(screen_location - drag_image_offset, size);
-  drag_view->SetBoundsInScreen(drag_image_bounds);
-  drag_view->SetWidgetVisible(true);
-
-  drag_state_ = std::make_unique<DragState>();
-  drag_state_->view = std::move(drag_view);
-  drag_state_->image_offset = drag_image_offset;
-}
-
-void WindowManager::OnWmMoveDragImage(const gfx::Point& screen_location) {
-  if (drag_state_) {
-    drag_state_->view->SetScreenPosition(screen_location -
-                                         drag_state_->image_offset);
-  }
-}
-
-void WindowManager::OnWmDestroyDragImage() {
-  drag_state_.reset();
-}
-
-void WindowManager::OnWmWillCreateDisplay(const display::Display& display) {
-  // Ash connects such that |automatically_create_display_roots| is false, which
-  // means this should never be hit.
-  NOTREACHED();
-}
-
-void WindowManager::OnWmNewDisplay(
-    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
-    const display::Display& display) {
-  // Ash connects such that |automatically_create_display_roots| is false, which
-  // means this should never be hit.
-  NOTREACHED();
-}
-
-void WindowManager::OnWmDisplayRemoved(
-    aura::WindowTreeHostMus* window_tree_host) {
-  // Ash connects such that |automatically_create_display_roots| is false, which
-  // means this should never be hit.
-  NOTREACHED();
-}
-
-void WindowManager::OnWmDisplayModified(const display::Display& display) {
-  // TODO(sky): this shouldn't be called as we're passing false for
-  // |automatically_create_display_roots|, but it currently is. Update mus.
-}
-
-void WindowManager::OnWmPerformMoveLoop(
-    aura::Window* window,
-    ui::mojom::MoveLoopSource source,
-    const gfx::Point& cursor_location,
-    const base::Callback<void(bool)>& on_done) {
-  MoveEventHandler* handler = MoveEventHandler::GetForWindow(window);
-  if (!handler) {
-    on_done.Run(false);
-    return;
-  }
-
-  DCHECK(!handler->IsDragInProgress());
-  ::wm::WindowMoveSource aura_source =
-      source == ui::mojom::MoveLoopSource::MOUSE
-          ? ::wm::WINDOW_MOVE_SOURCE_MOUSE
-          : ::wm::WINDOW_MOVE_SOURCE_TOUCH;
-  handler->AttemptToStartDrag(cursor_location, HTCAPTION, aura_source, on_done);
-}
-
-void WindowManager::OnWmCancelMoveLoop(aura::Window* window) {
-  MoveEventHandler* handler = MoveEventHandler::GetForWindow(window);
-  if (handler)
-    handler->RevertDrag();
-}
-
-ui::mojom::EventResult WindowManager::OnAccelerator(
-    uint32_t id,
-    const ui::Event& event,
-    base::flat_map<std::string, std::vector<uint8_t>>* properties) {
-  auto iter = accelerator_handlers_.find(GetAcceleratorNamespaceId(id));
-  if (iter == accelerator_handlers_.end())
-    return ui::mojom::EventResult::HANDLED;
-
-  return iter->second->OnAccelerator(id, event, properties);
-}
-
-void WindowManager::OnCursorTouchVisibleChanged(bool enabled) {
-  ShellPortMash::Get()->OnCursorTouchVisibleChanged(enabled);
-}
-
-void WindowManager::OnWmSetClientArea(
-    aura::Window* window,
-    const gfx::Insets& insets,
-    const std::vector<gfx::Rect>& additional_client_areas) {
-  NonClientFrameController* non_client_frame_controller =
-      NonClientFrameController::Get(window);
-  if (!non_client_frame_controller)
-    return;
-  non_client_frame_controller->SetClientArea(insets);
-}
-
-bool WindowManager::IsWindowActive(aura::Window* window) {
-  return Shell::Get()->activation_client()->GetActiveWindow() == window;
-}
-
-void WindowManager::OnWmDeactivateWindow(aura::Window* window) {
-  Shell::Get()->activation_client()->DeactivateWindow(window);
-}
-
-void WindowManager::OnWmPerformAction(aura::Window* window,
-                                      const std::string& action) {
-  if (action == mojom::kAddWindowToTabletMode)
-    ash::Shell::Get()->tablet_mode_controller()->AddWindow(window);
-}
-
-void WindowManager::OnEventBlockedByModalWindow(aura::Window* window) {
-  AnimateWindow(window, ::wm::WINDOW_ANIMATION_TYPE_BOUNCE);
-}
-
-}  // namespace ash
diff --git a/ash/window_manager.h b/ash/window_manager.h
deleted file mode 100644
index 48962a5..0000000
--- a/ash/window_manager.h
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_WINDOW_MANAGER_H_
-#define ASH_WINDOW_MANAGER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "ash/ash_export.h"
-#include "ash/root_window_controller.h"
-#include "ash/shell_delegate.h"
-#include "base/macros.h"
-#include "services/ui/common/types.h"
-#include "services/ui/public/interfaces/display/display_controller.mojom.h"
-#include "services/ui/public/interfaces/window_manager.mojom.h"
-#include "ui/aura/mus/window_manager_delegate.h"
-#include "ui/aura/mus/window_tree_client_delegate.h"
-
-namespace display {
-class Display;
-}
-
-namespace service_manager {
-class Connector;
-}
-
-namespace ui {
-class InputDeviceClient;
-}
-
-namespace views {
-class PointerWatcherEventRouter;
-}
-
-namespace wm {
-class WMState;
-}
-
-namespace ash {
-class AcceleratorHandler;
-class AshTestHelper;
-
-enum class Config;
-
-// WindowManager serves as the WindowManagerDelegate and
-// WindowTreeClientDelegate for mash. WindowManager takes ownership of
-// the WindowTreeClient. This is used in not in classic.
-class ASH_EXPORT WindowManager : public aura::WindowManagerDelegate,
-                                 public aura::WindowTreeClientDelegate {
- public:
-  // Set |show_primary_host_on_connect| to true if the initial display should
-  // be made visible.  Generally tests should use false, other places use true.
-  WindowManager(service_manager::Connector* connector,
-                bool show_primary_host_on_connect);
-  ~WindowManager() override;
-
-  // |initial_display_prefs| contains a dictionary of initial display prefs to
-  // pass to Shell::Init for synchronous initial display configuraiton.
-  void Init(std::unique_ptr<aura::WindowTreeClient> window_tree_client,
-            std::unique_ptr<base::Value> initial_display_prefs);
-
-  aura::WindowTreeClient* window_tree_client() {
-    return window_tree_client_.get();
-  }
-
-  aura::WindowManagerClient* window_manager_client() {
-    return window_manager_client_;
-  }
-
-  service_manager::Connector* connector() { return connector_; }
-
-  aura::PropertyConverter* property_converter() {
-    return property_converter_.get();
-  }
-
-  // Returns the next accelerator namespace id by value in |id|. Returns true
-  // if there is another slot available, false if all slots are taken up.
-  bool GetNextAcceleratorNamespaceId(uint16_t* id);
-  void AddAcceleratorHandler(uint16_t id_namespace,
-                             AcceleratorHandler* handler);
-  void RemoveAcceleratorHandler(uint16_t id_namespace);
-
-  // Returns the DisplayController interface if available. Will be null if no
-  // service_manager::Connector was available, for example in some tests.
-  display::mojom::DisplayController* GetDisplayController();
-
- private:
-  friend class ash::AshTestHelper;
-
-  // Creates the Shell. This is done after the connection to mus is established.
-  void CreateShell();
-
-  // If Mash, tells the window server about keys we don't want to hide the
-  // cursor on.
-  void InitCursorOnKeyList();
-
-  // Sets the frame decoration values on the server.
-  void InstallFrameDecorationValues();
-
-  void Shutdown();
-
-  // WindowTreeClientDelegate:
-  void OnEmbed(
-      std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) override;
-  void OnEmbedRootDestroyed(aura::WindowTreeHostMus* window_tree_host) override;
-  void OnLostConnection(aura::WindowTreeClient* client) override;
-  void OnPointerEventObserved(const ui::PointerEvent& event,
-                              int64_t display_id,
-                              aura::Window* target) override;
-  aura::PropertyConverter* GetPropertyConverter() override;
-
-  // WindowManagerDelegate:
-  void SetWindowManagerClient(aura::WindowManagerClient* client) override;
-  void OnWmConnected() override;
-  void OnWmAcceleratedWidgetAvailableForDisplay(
-      int64_t display_id,
-      gfx::AcceleratedWidget widget) override;
-  void OnWmSetBounds(aura::Window* window, const gfx::Rect& bounds) override;
-  bool OnWmSetProperty(
-      aura::Window* window,
-      const std::string& name,
-      std::unique_ptr<std::vector<uint8_t>>* new_data) override;
-  void OnWmSetModalType(aura::Window* window, ui::ModalType type) override;
-  void OnWmSetCanFocus(aura::Window* window, bool can_focus) override;
-  aura::Window* OnWmCreateTopLevelWindow(
-      ui::mojom::WindowType window_type,
-      std::map<std::string, std::vector<uint8_t>>* properties) override;
-  void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
-                                  bool not_responding) override;
-  void OnWmBuildDragImage(const gfx::Point& screen_location,
-                          const gfx::ImageSkia& drag_image,
-                          const gfx::Vector2d& drag_image_offset,
-                          ui::mojom::PointerKind source) override;
-  void OnWmMoveDragImage(const gfx::Point& screen_location) override;
-  void OnWmDestroyDragImage() override;
-  void OnWmWillCreateDisplay(const display::Display& display) override;
-  void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
-                      const display::Display& display) override;
-  void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override;
-  void OnWmDisplayModified(const display::Display& display) override;
-  void OnWmPerformMoveLoop(aura::Window* window,
-                           ui::mojom::MoveLoopSource source,
-                           const gfx::Point& cursor_location,
-                           const base::Callback<void(bool)>& on_done) override;
-  void OnWmCancelMoveLoop(aura::Window* window) override;
-  ui::mojom::EventResult OnAccelerator(
-      uint32_t id,
-      const ui::Event& event,
-      base::flat_map<std::string, std::vector<uint8_t>>* properties) override;
-  void OnCursorTouchVisibleChanged(bool enabled) override;
-  void OnWmSetClientArea(
-      aura::Window* window,
-      const gfx::Insets& insets,
-      const std::vector<gfx::Rect>& additional_client_areas) override;
-  bool IsWindowActive(aura::Window* window) override;
-  void OnWmDeactivateWindow(aura::Window* window) override;
-  void OnWmPerformAction(aura::Window* window,
-                         const std::string& action) override;
-  void OnEventBlockedByModalWindow(aura::Window* window) override;
-
-  service_manager::Connector* connector_;
-  display::mojom::DisplayControllerPtr display_controller_;
-
-  const bool show_primary_host_on_connect_;
-
-  std::unique_ptr<::wm::WMState> wm_state_;
-  std::unique_ptr<aura::PropertyConverter> property_converter_;
-
-  std::unique_ptr<aura::WindowTreeClient> window_tree_client_;
-
-  aura::WindowManagerClient* window_manager_client_ = nullptr;
-
-  std::unique_ptr<views::PointerWatcherEventRouter>
-      pointer_watcher_event_router_;
-
-  bool created_shell_ = false;
-
-  std::map<uint16_t, AcceleratorHandler*> accelerator_handlers_;
-  uint16_t next_accelerator_namespace_id_ = 0u;
-
-  // The ShellDelegate to install. This may be null, in which case
-  // ShellDelegateMash is used.
-  // NOTE: AshTestHelper may set |shell_delegate_| directly.
-  std::unique_ptr<ShellDelegate> shell_delegate_;
-
-  std::unique_ptr<base::Value> initial_display_prefs_;
-
-  // State that is only valid during a drag.
-  struct DragState;
-  std::unique_ptr<DragState> drag_state_;
-
-  std::unique_ptr<ui::InputDeviceClient> input_device_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowManager);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WINDOW_MANAGER_H_
diff --git a/ash/window_manager_common_unittests.cc b/ash/window_manager_common_unittests.cc
deleted file mode 100644
index 89c5cbb..0000000
--- a/ash/window_manager_common_unittests.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/public/cpp/config.h"
-#include "ash/shell.h"
-#include "ash/test/ash_test_base.h"
-#include "ash/test/ash_test_helper.h"
-#include "ui/aura/test/mus/test_window_manager_client.h"
-#include "ui/aura/test/mus/test_window_tree.h"
-#include "ui/aura/test/mus/test_window_tree_client_setup.h"
-#include "ui/aura/window.h"
-
-namespace ash {
-
-using WindowManagerCommonTest = AshTestBase;
-
-// TODO(jamescook): Move into one of the existing WindowManager test suites.
-TEST_F(WindowManagerCommonTest, Focus) {
-  if (Shell::GetAshConfig() == Config::CLASSIC)
-    return;
-
-  // Ensure that activation parents have been added, an ancestor of |window|
-  // must support activation for the focus attempt below to succeed.
-  aura::TestWindowManagerClient* test_window_manager_client =
-      ash_test_helper()
-          ->window_tree_client_setup()
-          ->test_window_manager_client();
-  EXPECT_LT(0u,
-            test_window_manager_client->GetChangeCountForType(
-                aura::WindowManagerClientChangeType::ADD_ACTIVATION_PARENT));
-
-  // Ensure a call to Window::Focus() makes it way to the WindowTree.
-  std::unique_ptr<aura::Window> window = CreateTestWindow();
-  aura::TestWindowTree* test_window_tree =
-      ash_test_helper()->window_tree_client_setup()->window_tree();
-  const size_t initial_focus_count = test_window_tree->GetChangeCountForType(
-      aura::WindowTreeChangeType::FOCUS);
-  window->Focus();
-  EXPECT_TRUE(window->HasFocus());
-  EXPECT_EQ(initial_focus_count + 1, test_window_tree->GetChangeCountForType(
-                                         aura::WindowTreeChangeType::FOCUS));
-}
-
-}  // namespace ash
diff --git a/ash/window_manager_service.cc b/ash/window_manager_service.cc
deleted file mode 100644
index 6b081fc9b..0000000
--- a/ash/window_manager_service.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/window_manager_service.h"
-
-#include <memory>
-#include <utility>
-
-#include "ash/mojo_interface_factory.h"
-#include "ash/network_connect_delegate_mus.h"
-#include "ash/shell.h"
-#include "ash/system/power/power_status.h"
-#include "ash/window_manager.h"
-#include "base/bind.h"
-#include "base/process/process_handle.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/power_policy_controller.h"
-#include "chromeos/network/network_connect.h"
-#include "chromeos/network/network_handler.h"
-#include "chromeos/system/fake_statistics_provider.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/dbus/bluez_dbus_manager.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/service_context.h"
-#include "services/ui/common/accelerator_util.h"
-#include "services/ui/common/image_cursors_set.h"
-#include "services/ui/public/interfaces/constants.mojom.h"
-#include "services/ui/service.h"
-#include "ui/aura/env.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/events/event.h"
-#include "ui/views/mus/aura_init.h"
-
-namespace ash {
-
-WindowManagerService::WindowManagerService(bool show_primary_host_on_connect)
-    : show_primary_host_on_connect_(show_primary_host_on_connect),
-      image_cursors_set_(std::make_unique<ui::ImageCursorsSet>()) {}
-
-WindowManagerService::~WindowManagerService() {
-  // Verify that we created a WindowManager before attempting to tear everything
-  // down. In some fast running tests OnStart() may never have been called.
-  if (window_manager_) {
-    // Destroy the WindowManager while still valid. This way we ensure
-    // OnWillDestroyRootWindowController() is called (if it hasn't been
-    // already).
-    window_manager_.reset();
-
-    statistics_provider_.reset();
-    ShutdownComponents();
-  }
-  if (ui_thread_) {
-    ui_thread_->task_runner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            &WindowManagerService::DestroyUiServiceOnBackgroundThread,
-            base::Unretained(this)));
-  }
-  ui_thread_.reset();
-}
-
-service_manager::Connector* WindowManagerService::GetConnector() {
-  return context() ? context()->connector() : nullptr;
-}
-
-void WindowManagerService::InitWindowManager(
-    std::unique_ptr<aura::WindowTreeClient> window_tree_client,
-    bool init_network_handler) {
-  // Tests may have already set the WindowTreeClient.
-  if (!aura::Env::GetInstance()->HasWindowTreeClient())
-    aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client.get());
-  InitializeComponents(init_network_handler);
-
-  // TODO(jamescook): Refactor StatisticsProvider so we can get just the data
-  // we need in ash. Right now StatisticsProviderImpl launches the crossystem
-  // binary to get system data, which we don't want to do twice on startup.
-  statistics_provider_.reset(
-      new chromeos::system::ScopedFakeStatisticsProvider());
-  statistics_provider_->SetMachineStatistic("initial_locale", "en-US");
-  statistics_provider_->SetMachineStatistic("keyboard_layout", "");
-
-  window_manager_->Init(std::move(window_tree_client),
-                        /*initial_display_prefs=*/nullptr);
-}
-
-void WindowManagerService::InitializeComponents(bool init_network_handler) {
-  // Must occur after mojo::ApplicationRunner has initialized AtExitManager, but
-  // before WindowManager::Init(). Tests might initialize their own instance.
-  if (!chromeos::DBusThreadManager::IsInitialized()) {
-    chromeos::DBusThreadManager::Initialize(
-        chromeos::DBusThreadManager::kShared);
-    dbus_thread_manager_initialized_ = true;
-  }
-  chromeos::PowerPolicyController::Initialize(
-      chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
-
-  // See ChromeBrowserMainPartsChromeos for ordering details.
-  bluez::BluezDBusManager::Initialize(
-      chromeos::DBusThreadManager::Get()->GetSystemBus(),
-      chromeos::DBusThreadManager::Get()->IsUsingFakes());
-  if (init_network_handler && !chromeos::NetworkHandler::IsInitialized()) {
-    chromeos::NetworkHandler::Initialize();
-    network_handler_initialized_ = true;
-  }
-  network_connect_delegate_.reset(new NetworkConnectDelegateMus());
-  chromeos::NetworkConnect::Initialize(network_connect_delegate_.get());
-  // TODO(jamescook): Initialize real audio handler.
-  chromeos::CrasAudioHandler::InitializeForTesting();
-  chromeos::SystemSaltGetter::Initialize();
-}
-
-void WindowManagerService::ShutdownComponents() {
-  // NOTE: PowerStatus is shutdown by Shell.
-  chromeos::SystemSaltGetter::Shutdown();
-  chromeos::CrasAudioHandler::Shutdown();
-  chromeos::NetworkConnect::Shutdown();
-  network_connect_delegate_.reset();
-  // We may not have started the NetworkHandler.
-  if (network_handler_initialized_)
-    chromeos::NetworkHandler::Shutdown();
-  device::BluetoothAdapterFactory::Shutdown();
-  bluez::BluezDBusManager::Shutdown();
-  chromeos::PowerPolicyController::Shutdown();
-  if (dbus_thread_manager_initialized_)
-    chromeos::DBusThreadManager::Shutdown();
-}
-
-void WindowManagerService::BindServiceFactory(
-    service_manager::mojom::ServiceFactoryRequest request) {
-  service_factory_bindings_.AddBinding(this, std::move(request));
-}
-
-void WindowManagerService::CreateUiServiceOnBackgroundThread(
-    scoped_refptr<base::SingleThreadTaskRunner> resource_runner,
-    service_manager::mojom::ServiceRequest service_request) {
-  ui::Service::InitParams params;
-  params.running_standalone = false;
-  params.resource_runner = resource_runner;
-  params.image_cursors_set_weak_ptr = image_cursors_set_->GetWeakPtr();
-  params.should_host_viz = true;
-  std::unique_ptr<ui::Service> service = std::make_unique<ui::Service>(params);
-  ui_service_context_ = std::make_unique<service_manager::ServiceContext>(
-      std::move(service), std::move(service_request));
-}
-
-void WindowManagerService::DestroyUiServiceOnBackgroundThread() {
-  ui_service_context_.reset();
-}
-
-void WindowManagerService::CreateService(
-    service_manager::mojom::ServiceRequest service_request,
-    const std::string& name,
-    service_manager::mojom::PIDReceiverPtr pid_receiver) {
-  DCHECK_EQ(name, ui::mojom::kServiceName);
-  ui_thread_ = std::make_unique<base::Thread>("UI Service");
-  // The image cursors must be set by the time this is called.
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_UI;
-  options.priority = base::ThreadPriority::DISPLAY;
-  ui_thread_->StartWithOptions(options);
-  ui_thread_->task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&WindowManagerService::CreateUiServiceOnBackgroundThread,
-                     base::Unretained(this),
-                     base::ThreadTaskRunnerHandle::Get(),
-                     std::move(service_request)));
-  pid_receiver->SetPID(base::GetCurrentProcId());
-}
-
-void WindowManagerService::OnStart() {
-  mojo_interface_factory::RegisterInterfaces(
-      &registry_, base::ThreadTaskRunnerHandle::Get());
-
-  registry_.AddInterface(base::BindRepeating(
-      &WindowManagerService::BindServiceFactory, base::Unretained(this)));
-
-  views::AuraInit::InitParams params;
-  params.connector = context()->connector();
-  params.identity = context()->identity();
-  params.resource_file = "ash_service_resources.pak";
-  params.resource_file_200 = "ash_service_resources_200.pak";
-  params.mode = views::AuraInit::Mode::AURA_MUS_WINDOW_MANAGER;
-  params.register_path_provider = running_standalone_;
-  aura_init_ = views::AuraInit::Create(params);
-  if (!aura_init_) {
-    context()->QuitNow();
-    return;
-  }
-  window_manager_ = std::make_unique<WindowManager>(
-      context()->connector(), show_primary_host_on_connect_);
-
-  const bool automatically_create_display_roots = false;
-  std::unique_ptr<aura::WindowTreeClient> window_tree_client =
-      aura::WindowTreeClient::CreateForWindowManager(
-          context()->connector(), window_manager_.get(), window_manager_.get(),
-          automatically_create_display_roots);
-
-  const bool init_network_handler = true;
-  InitWindowManager(std::move(window_tree_client), init_network_handler);
-}
-
-void WindowManagerService::OnBindInterface(
-    const service_manager::BindSourceInfo& source_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
-}
-
-}  // namespace ash
diff --git a/ash/window_manager_service.h b/ash/window_manager_service.h
deleted file mode 100644
index d08a593..0000000
--- a/ash/window_manager_service.h
+++ /dev/null
@@ -1,139 +0,0 @@
-
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_WINDOW_MANAGER_SERVICE_H_
-#define ASH_WINDOW_MANAGER_SERVICE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-
-#include "ash/ash_export.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/mojom/service_factory.mojom.h"
-#include "services/ui/common/types.h"
-
-namespace aura {
-class WindowTreeClient;
-}
-
-namespace base {
-class Thread;
-}
-
-namespace chromeos {
-namespace system {
-class ScopedFakeStatisticsProvider;
-}
-}  // namespace chromeos
-
-namespace service_manager {
-class Connector;
-}
-
-namespace views {
-class AuraInit;
-}
-
-namespace ui {
-class ImageCursorsSet;
-}
-
-namespace ash {
-class AshTestHelper;
-class NetworkConnectDelegateMus;
-class WindowManager;
-
-// Hosts the window manager and the ash system user interface for mash. This is
-// also responsible for creating the UI Service. This is only used for --mash.
-class ASH_EXPORT WindowManagerService
-    : public service_manager::Service,
-      public service_manager::mojom::ServiceFactory {
- public:
-  // See WindowManager's constructor for details of
-  // |show_primary_host_on_connect|.
-  explicit WindowManagerService(bool show_primary_host_on_connect);
-  ~WindowManagerService() override;
-
-  WindowManager* window_manager() { return window_manager_.get(); }
-
-  service_manager::Connector* GetConnector();
-
-  void set_running_standalone(bool value) { running_standalone_ = value; }
-
- private:
-  friend class ash::AshTestHelper;
-
-  // If |init_network_handler| is true, chromeos::NetworkHandler is initialized.
-  void InitWindowManager(
-      std::unique_ptr<aura::WindowTreeClient> window_tree_client,
-      bool init_network_handler);
-
-  // Initializes lower-level OS-specific components (e.g. D-Bus services).
-  void InitializeComponents(bool init_network_handler);
-  void ShutdownComponents();
-
-  void BindServiceFactory(
-      service_manager::mojom::ServiceFactoryRequest request);
-
-  void CreateUiServiceOnBackgroundThread(
-      scoped_refptr<base::SingleThreadTaskRunner> resource_runner,
-      service_manager::mojom::ServiceRequest service_request);
-  void DestroyUiServiceOnBackgroundThread();
-
-  // service_manager::mojom::ServiceFactory:
-  void CreateService(
-      service_manager::mojom::ServiceRequest service_request,
-      const std::string& name,
-      service_manager::mojom::PIDReceiverPtr pid_receiver) override;
-
-  // service_manager::Service:
-  void OnStart() override;
-  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-
-  const bool show_primary_host_on_connect_;
-  bool running_standalone_ = false;
-
-  std::unique_ptr<views::AuraInit> aura_init_;
-
-  std::unique_ptr<WindowManager> window_manager_;
-
-  std::unique_ptr<NetworkConnectDelegateMus> network_connect_delegate_;
-  std::unique_ptr<chromeos::system::ScopedFakeStatisticsProvider>
-      statistics_provider_;
-
-  mojo::BindingSet<service_manager::mojom::ServiceFactory>
-      service_factory_bindings_;
-
-  service_manager::BinderRegistry registry_;
-
-  // Whether this class initialized NetworkHandler and needs to clean it up.
-  bool network_handler_initialized_ = false;
-
-  // Whether this class initialized DBusThreadManager and needs to clean it up.
-  bool dbus_thread_manager_initialized_ = false;
-
-  // Thread the UI Service runs on.
-  std::unique_ptr<base::Thread> ui_thread_;
-
-  // The ServiceContext created for the UI service. This is created (and
-  // shutdown) on |ui_thread_|.
-  std::unique_ptr<service_manager::ServiceContext> ui_service_context_;
-
-  std::unique_ptr<ui::ImageCursorsSet> image_cursors_set_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowManagerService);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WINDOW_MANAGER_SERVICE_H_
diff --git a/ash/wm/move_event_handler.cc b/ash/wm/move_event_handler.cc
deleted file mode 100644
index 70df6dc9..0000000
--- a/ash/wm/move_event_handler.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/wm/move_event_handler.h"
-
-#include "ash/wm/window_util.h"
-#include "ash/wm/workspace/workspace_event_handler_mash.h"
-#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
-#include "ui/aura/mus/window_manager_delegate.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/base/class_property.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/hit_test.h"
-#include "ui/events/event.h"
-
-DEFINE_UI_CLASS_PROPERTY_TYPE(ash::MoveEventHandler*);
-
-namespace {
-
-// Key used for storing identifier sent to clients for windows.
-DEFINE_UI_CLASS_PROPERTY_KEY(ash::MoveEventHandler*,
-                             kWmMoveEventHandler,
-                             nullptr);
-
-}  // namespace
-
-namespace ash {
-namespace {
-
-ui::CursorType CursorForWindowComponent(int window_component) {
-  switch (window_component) {
-    case HTBOTTOM:
-      return ui::CursorType::kSouthResize;
-    case HTBOTTOMLEFT:
-      return ui::CursorType::kSouthWestResize;
-    case HTBOTTOMRIGHT:
-      return ui::CursorType::kSouthEastResize;
-    case HTLEFT:
-      return ui::CursorType::kWestResize;
-    case HTRIGHT:
-      return ui::CursorType::kEastResize;
-    case HTTOP:
-      return ui::CursorType::kNorthResize;
-    case HTTOPLEFT:
-      return ui::CursorType::kNorthWestResize;
-    case HTTOPRIGHT:
-      return ui::CursorType::kNorthEastResize;
-    default:
-      return ui::CursorType::kNull;
-  }
-}
-
-void OnMoveLoopCompleted(const base::Callback<void(bool success)>& end_closure,
-                         wm::WmToplevelWindowEventHandler::DragResult result) {
-  end_closure.Run(result ==
-                  wm::WmToplevelWindowEventHandler::DragResult::SUCCESS);
-}
-
-}  // namespace
-
-MoveEventHandler::MoveEventHandler(
-    aura::WindowManagerClient* window_manager_client,
-    aura::Window* window)
-    : window_(window), window_manager_client_(window_manager_client) {
-  window->AddObserver(this);
-  window->AddPreTargetHandler(this);
-
-  window->SetProperty(kWmMoveEventHandler, this);
-}
-
-MoveEventHandler::~MoveEventHandler() {
-  Detach();
-}
-
-// static
-MoveEventHandler* MoveEventHandler::GetForWindow(aura::Window* window) {
-  return window->GetProperty(kWmMoveEventHandler);
-}
-
-void MoveEventHandler::AttemptToStartDrag(
-    const gfx::Point& point_in_parent,
-    int window_component,
-    ::wm::WindowMoveSource source,
-    const base::Callback<void(bool success)>& end_closure) {
-  toplevel_window_event_handler_.AttemptToStartDrag(
-      window_, point_in_parent, window_component, source,
-      base::Bind(&OnMoveLoopCompleted, end_closure));
-}
-
-bool MoveEventHandler::IsDragInProgress() {
-  return toplevel_window_event_handler_.is_drag_in_progress();
-}
-
-void MoveEventHandler::RevertDrag() {
-  toplevel_window_event_handler_.RevertDrag();
-}
-
-void MoveEventHandler::Detach() {
-  if (!window_)
-    return;
-
-  window_->RemoveObserver(this);
-  window_->RemovePreTargetHandler(this);
-  window_->ClearProperty(kWmMoveEventHandler);
-  window_ = nullptr;
-}
-
-WorkspaceEventHandlerMash* MoveEventHandler::GetWorkspaceEventHandlerMash() {
-  if (!window_->parent())
-    return nullptr;
-
-  return WorkspaceEventHandlerMash::Get(window_->parent());
-}
-
-void MoveEventHandler::OnMouseEvent(ui::MouseEvent* event) {
-  toplevel_window_event_handler_.OnMouseEvent(event, window_);
-  if (!toplevel_window_event_handler_.is_drag_in_progress() &&
-      window_manager_client_ &&
-      (event->type() == ui::ET_POINTER_MOVED ||
-       event->type() == ui::ET_MOUSE_MOVED)) {
-    const int hit_test_location =
-        wm::GetNonClientComponent(window_, event->location());
-    window_manager_client_->SetNonClientCursor(
-        window_, ui::CursorData(CursorForWindowComponent(hit_test_location)));
-  }
-
-  WorkspaceEventHandlerMash* workspace_event_handler =
-      GetWorkspaceEventHandlerMash();
-  if (workspace_event_handler)
-    workspace_event_handler->OnMouseEvent(event, window_);
-}
-
-void MoveEventHandler::OnGestureEvent(ui::GestureEvent* event) {
-  toplevel_window_event_handler_.OnGestureEvent(event, window_);
-
-  WorkspaceEventHandlerMash* workspace_event_handler =
-      GetWorkspaceEventHandlerMash();
-  if (workspace_event_handler)
-    workspace_event_handler->OnGestureEvent(event, window_);
-}
-
-void MoveEventHandler::OnCancelMode(ui::CancelModeEvent* event) {
-  toplevel_window_event_handler_.RevertDrag();
-}
-
-void MoveEventHandler::OnWindowDestroying(aura::Window* window) {
-  DCHECK_EQ(window_, window);
-  Detach();
-}
-
-}  // namespace ash
diff --git a/ash/wm/move_event_handler.h b/ash/wm/move_event_handler.h
deleted file mode 100644
index 2980fc6..0000000
--- a/ash/wm/move_event_handler.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_WM_MOVE_EVENT_HANDLER_H_
-#define ASH_WM_MOVE_EVENT_HANDLER_H_
-
-#include <memory>
-
-#include "ash/wm/wm_toplevel_window_event_handler.h"
-#include "base/macros.h"
-#include "ui/aura/window_observer.h"
-#include "ui/events/event_handler.h"
-
-namespace aura {
-class Window;
-class WindowManagerClient;
-}  // namespace aura
-
-namespace ui {
-class CancelModeEvent;
-}
-
-namespace ash {
-
-class WorkspaceEventHandlerMash;
-
-// EventHandler attached to windows that may be dragged and/or resized. This
-// forwards to WmToplevelWindowEventHandler to handle the actual drag/resize.
-//
-// TODO(sky): rename this class to better reflect that it handles redirecting
-// events in addition to drag.
-class MoveEventHandler : public ui::EventHandler, public aura::WindowObserver {
- public:
-  MoveEventHandler(aura::WindowManagerClient* window_manager_client,
-                   aura::Window* window);
-  ~MoveEventHandler() override;
-
-  // Retrieves the MoveEventHandler for an existing aura::Window.
-  static MoveEventHandler* GetForWindow(aura::Window* window);
-
-  // Attempts to start a drag if one is not already in progress. This passes
-  // the call to the underlying WmToplevelWindowEventHandler. After the drag
-  // completes, |end_closure| will be called to return whether the drag was
-  // successfully completed.
-  void AttemptToStartDrag(
-      const gfx::Point& point_in_parent,
-      int window_component,
-      ::wm::WindowMoveSource source,
-      const base::Callback<void(bool success)>& end_closure);
-
-  // Returns whether we're in a drag.
-  bool IsDragInProgress();
-
-  // Reverts a manually started drag started with AttemptToStartDrag().
-  void RevertDrag();
-
- private:
-  // Removes observer and EventHandler.
-  void Detach();
-
-  // Returns the WorkspaceEventHandlerMash, or null if the window is not in a
-  // workspace.
-  WorkspaceEventHandlerMash* GetWorkspaceEventHandlerMash();
-
-  // Overridden from ui::EventHandler:
-  void OnMouseEvent(ui::MouseEvent* event) override;
-  void OnGestureEvent(ui::GestureEvent* event) override;
-  void OnCancelMode(ui::CancelModeEvent* event) override;
-
-  // Overridden from aura::WindowObserver:
-  void OnWindowDestroying(aura::Window* window) override;
-
-  aura::Window* window_;
-  aura::WindowManagerClient* window_manager_client_;
-  wm::WmToplevelWindowEventHandler toplevel_window_event_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(MoveEventHandler);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_MOVE_EVENT_HANDLER_H_
diff --git a/ash/wm/non_client_frame_controller.cc b/ash/wm/non_client_frame_controller.cc
index eefd286..d1e8402 100644
--- a/ash/wm/non_client_frame_controller.cc
+++ b/ash/wm/non_client_frame_controller.cc
@@ -17,7 +17,6 @@
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
-#include "ash/wm/move_event_handler.h"
 #include "ash/wm/panels/panel_frame_view.h"
 #include "ash/wm/property_util.h"
 #include "ash/wm/window_properties.h"
@@ -34,7 +33,6 @@
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/mus/property_utils.h"
-#include "ui/aura/mus/window_manager_delegate.h"
 #include "ui/aura/mus/window_port_mus.h"
 #include "ui/aura/window.h"
 #include "ui/base/class_property.h"
@@ -175,7 +173,6 @@
 class WmNativeWidgetAura : public views::NativeWidgetAura {
  public:
   WmNativeWidgetAura(views::internal::NativeWidgetDelegate* delegate,
-                     aura::WindowManagerClient* window_manager_client,
                      bool remove_standard_frame,
                      bool enable_immersive,
                      mojom::WindowStyle window_style)
@@ -186,8 +183,7 @@
             true /* is_parallel_widget_in_window_manager */),
         remove_standard_frame_(remove_standard_frame),
         enable_immersive_(enable_immersive),
-        window_style_(window_style),
-        window_manager_client_(window_manager_client) {}
+        window_style_(window_style) {}
   ~WmNativeWidgetAura() override = default;
 
   void SetHeaderHeight(int height) {
@@ -199,10 +195,6 @@
 
   // views::NativeWidgetAura:
   views::NonClientFrameView* CreateNonClientFrameView() override {
-    if (window_manager_client_) {
-      move_event_handler_ = std::make_unique<MoveEventHandler>(
-          window_manager_client_, GetNativeView());
-    }
     // TODO(sky): investigate why we have this. Seems this should be the same
     // as not specifying client area insets.
     if (remove_standard_frame_)
@@ -239,12 +231,6 @@
   const bool enable_immersive_;
   const mojom::WindowStyle window_style_;
 
-  // TODO: this is no longer necessary once --mash is removed,
-  // https://crbug.com/842365.
-  std::unique_ptr<MoveEventHandler> move_event_handler_;
-
-  aura::WindowManagerClient* window_manager_client_;
-
   std::unique_ptr<ImmersiveFullscreenControllerDelegateMus> immersive_delegate_;
 
   // Not used for panels or if |remove_standard_frame_| is true. This is owned
@@ -296,13 +282,8 @@
     // pass the request to the remote client and return false (to cancel the
     // close). If the remote client wants the window to close, it will close it
     // in a way that does not reenter this code path.
-    if (frame_controller_->window_manager_client()) {
-      frame_controller_->window_manager_client()->RequestClose(
-          frame_controller_->window());
-    } else {
-      Shell::Get()->window_service_owner()->window_service()->RequestClose(
-          frame_controller_->window());
-    }
+    Shell::Get()->window_service_owner()->window_service()->RequestClose(
+        frame_controller_->window());
     return false;
   }
 
@@ -323,11 +304,8 @@
     const gfx::Rect& bounds,
     ui::mojom::WindowType window_type,
     aura::PropertyConverter* property_converter,
-    std::map<std::string, std::vector<uint8_t>>* properties,
-    aura::WindowManagerClient* window_manager_client)
-    : window_manager_client_(window_manager_client),
-      widget_(new views::Widget),
-      window_(nullptr) {
+    std::map<std::string, std::vector<uint8_t>>* properties)
+    : widget_(new views::Widget), window_(nullptr) {
   // To simplify things this code creates a Widget. While a Widget is created
   // we need to ensure we don't inadvertently change random properties of the
   // underlying ui::Window. For example, showing the Widget shouldn't change
@@ -347,7 +325,7 @@
   params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
   params.layer_type = ui::LAYER_SOLID_COLOR;
   WmNativeWidgetAura* native_widget = new WmNativeWidgetAura(
-      widget_, window_manager_client_, ShouldRemoveStandardFrame(*properties),
+      widget_, ShouldRemoveStandardFrame(*properties),
       ShouldEnableImmersive(*properties), GetWindowStyle(*properties));
   window_ = native_widget->GetNativeView();
   window_->SetProperty(aura::client::kEmbedType,
diff --git a/ash/wm/non_client_frame_controller.h b/ash/wm/non_client_frame_controller.h
index 5dbeac08..6752a1c4 100644
--- a/ash/wm/non_client_frame_controller.h
+++ b/ash/wm/non_client_frame_controller.h
@@ -23,7 +23,6 @@
 namespace aura {
 class PropertyConverter;
 class Window;
-class WindowManagerClient;
 }  // namespace aura
 
 namespace gfx {
@@ -58,8 +57,7 @@
       const gfx::Rect& bounds,
       ui::mojom::WindowType window_type,
       aura::PropertyConverter* property_converter,
-      std::map<std::string, std::vector<uint8_t>>* properties,
-      aura::WindowManagerClient* window_manager_client);
+      std::map<std::string, std::vector<uint8_t>>* properties);
 
   // Returns the NonClientFrameController for the specified window, null if
   // one was not created.
@@ -74,10 +72,6 @@
 
   aura::Window* window() { return window_; }
 
-  aura::WindowManagerClient* window_manager_client() {
-    return window_manager_client_;
-  }
-
   void SetClientArea(const gfx::Insets& insets);
 
   // Stores |cursor| as this window's active cursor. It does not actually update
@@ -112,8 +106,6 @@
  private:
   ~NonClientFrameController() override;
 
-  aura::WindowManagerClient* window_manager_client_;
-
   views::Widget* widget_;
   views::View* contents_view_ = nullptr;
 
diff --git a/ash/wm/non_client_frame_controller_unittest.cc b/ash/wm/non_client_frame_controller_unittest.cc
index 5fe5357..b687f8b 100644
--- a/ash/wm/non_client_frame_controller_unittest.cc
+++ b/ash/wm/non_client_frame_controller_unittest.cc
@@ -9,8 +9,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/window_manager.h"
-#include "ash/window_manager_service.h"
 #include "ash/wm/top_level_window_factory.h"
 #include "base/strings/utf_string_conversions.h"
 #include "cc/base/math_util.h"
@@ -118,11 +116,9 @@
     return;  // TODO: decide if this test should be made to work with ws2.
 
   std::map<std::string, std::vector<uint8_t>> properties;
-  auto* window_manager =
-      ash_test_helper()->window_manager_service()->window_manager();
   std::unique_ptr<aura::Window> window(CreateAndParentTopLevelWindow(
-      window_manager, ui::mojom::WindowType::WINDOW,
-      window_manager->property_converter(), &properties));
+      ui::mojom::WindowType::WINDOW,
+      /* property_converter */ nullptr, &properties));
   ASSERT_TRUE(window);
 
   NonClientFrameController* controller =
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index ecdf705..465b454 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -101,10 +101,6 @@
   return wm::GetWindowState(window)->IsMaximizedOrFullscreenOrPinned();
 }
 
-bool IsNewOverviewAnimationsEnabled() {
-  return base::FeatureList::IsEnabled(features::kNewOverviewAnimations);
-}
-
 bool IsOverviewSwipeToCloseEnabled() {
   return base::FeatureList::IsEnabled(features::kOverviewSwipeToClose);
 }
diff --git a/ash/wm/overview/overview_utils.h b/ash/wm/overview/overview_utils.h
index 4ea7ffd..29409af 100644
--- a/ash/wm/overview/overview_utils.h
+++ b/ash/wm/overview/overview_utils.h
@@ -29,11 +29,6 @@
 // Returns true if |window| can cover available workspace.
 bool CanCoverAvailableWorkspace(aura::Window* window);
 
-// Returns true if overview mode should use the new animations.
-// TODO(wutao): Remove this function when the old overview mode animations
-// become obsolete. See https://crbug.com/801465.
-bool IsNewOverviewAnimationsEnabled();
-
 bool IsOverviewSwipeToCloseEnabled();
 
 // Fades |widget| to opacity zero with animation settings depending on
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc
index 1fae34a..716f089 100644
--- a/ash/wm/overview/window_grid.cc
+++ b/ash/wm/overview/window_grid.cc
@@ -31,6 +31,7 @@
 #include "ash/wm/overview/window_selector.h"
 #include "ash/wm/overview/window_selector_delegate.h"
 #include "ash/wm/overview/window_selector_item.h"
+#include "ash/wm/splitview/split_view_drag_indicators.h"
 #include "ash/wm/window_state.h"
 #include "base/i18n/string_search.h"
 #include "base/numerics/ranges.h"
@@ -583,7 +584,8 @@
 }
 
 void WindowGrid::OnWindowDragContinued(aura::Window* dragged_window,
-                                       const gfx::Point& location_in_screen) {
+                                       const gfx::Point& location_in_screen,
+                                       IndicatorState indicator_state) {
   DCHECK_EQ(dragged_window->GetRootWindow(), root_window_);
   // Find the window selector item that contains |location_in_screen|.
   auto iter = std::find_if(
@@ -594,6 +596,25 @@
 
   aura::Window* target_window =
       (iter != window_list_.end()) ? (*iter)->GetWindow() : nullptr;
+
+  if (indicator_state == IndicatorState::kPreviewAreaLeft ||
+      indicator_state == IndicatorState::kPreviewAreaRight) {
+    // If the dragged window is currently dragged into preview window area,
+    // clear the selection widget.
+    if (SelectedWindow()) {
+      SelectedWindow()->set_selected(false);
+      selection_widget_.reset();
+    }
+
+    // Also clear ash::kIsDeferredTabDraggingTargetWindowKey key on the target
+    // window selector item so that it can't merge into this window selector
+    // item if the dragged window is currently in preview window area.
+    if (target_window && !IsNewSelectorItemWindow(target_window))
+      target_window->ClearProperty(ash::kIsDeferredTabDraggingTargetWindowKey);
+
+    return;
+  }
+
   // If |location_in_screen| is contained by one of the eligible window selector
   // item in overview, show the selection widget.
   if (target_window && (IsNewSelectorItemWindow(target_window) ||
diff --git a/ash/wm/overview/window_grid.h b/ash/wm/overview/window_grid.h
index f06ade9..178f77d1 100644
--- a/ash/wm/overview/window_grid.h
+++ b/ash/wm/overview/window_grid.h
@@ -128,7 +128,8 @@
   // WindowGrid.
   void OnWindowDragStarted(aura::Window* dragged_window);
   void OnWindowDragContinued(aura::Window* dragged_window,
-                             const gfx::Point& location_in_screen);
+                             const gfx::Point& location_in_screen,
+                             IndicatorState indicator_state);
   void OnWindowDragEnded(aura::Window* dragged_window,
                          const gfx::Point& location_in_screen);
 
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index e477615..30782acb 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -290,15 +290,12 @@
     // as we don't want to cause any window updates until all windows in
     // overview are observed. See http://crbug.com/384495.
     for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
-      if (IsNewOverviewAnimationsEnabled()) {
         window_grid->SetWindowListAnimationStates(/*selected_item=*/nullptr,
                                                   OverviewTransition::kEnter);
-      }
       window_grid->PrepareForOverview();
       window_grid->PositionWindows(/*animate=*/true);
       // Reset |should_animate_when_entering_| in order to animate during
       // overview mode, such as dragging animations.
-      if (IsNewOverviewAnimationsEnabled())
         window_grid->ResetWindowListAnimationStates();
     }
 
@@ -343,7 +340,6 @@
 
   size_t remaining_items = 0;
   for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
-    if (IsNewOverviewAnimationsEnabled()) {
       // During shutdown, do not animate all windows in overview if we need to
       // animate the snapped window.
       if (split_view_controller->IsSplitViewModeActive() &&
@@ -363,7 +359,6 @@
                 : nullptr,
             OverviewTransition::kExit);
       }
-    }
     for (const auto& window_selector_item : window_grid->window_list())
       window_selector_item->RestoreWindow(/*reset_transform=*/true);
     remaining_items += window_grid->size();
@@ -619,16 +614,16 @@
   target_grid->OnWindowDragStarted(dragged_window);
 }
 
-void WindowSelector::OnWindowDragContinued(
-    aura::Window* dragged_window,
-    const gfx::Point& location_in_screen) {
+void WindowSelector::OnWindowDragContinued(aura::Window* dragged_window,
+                                           const gfx::Point& location_in_screen,
+                                           IndicatorState indicator_state) {
   WindowGrid* target_grid =
       GetGridWithRootWindow(dragged_window->GetRootWindow());
   if (!target_grid)
     return;
-  target_grid->OnWindowDragContinued(dragged_window, location_in_screen);
+  target_grid->OnWindowDragContinued(dragged_window, location_in_screen,
+                                     indicator_state);
 }
-
 void WindowSelector::OnWindowDragEnded(aura::Window* dragged_window,
                                        const gfx::Point& location_in_screen) {
   WindowGrid* target_grid =
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 79d09a5..8b995f21 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -138,7 +138,8 @@
   // TODO(xdai): Currently it doesn't work for multi-display scenario.
   void OnWindowDragStarted(aura::Window* dragged_window);
   void OnWindowDragContinued(aura::Window* dragged_window,
-                             const gfx::Point& location_in_screen);
+                             const gfx::Point& location_in_screen,
+                             IndicatorState indicator_state);
   void OnWindowDragEnded(aura::Window* dragged_window,
                          const gfx::Point& location_in_screen);
 
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 21b808d..6679ec377 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -1140,20 +1140,14 @@
 }
 
 bool WindowSelectorItem::ShouldAnimateWhenEntering() const {
-  if (!IsNewOverviewAnimationsEnabled())
-    return true;
   return should_animate_when_entering_;
 }
 
 bool WindowSelectorItem::ShouldAnimateWhenExiting() const {
-  if (!IsNewOverviewAnimationsEnabled())
-    return true;
   return should_animate_when_exiting_;
 }
 
 bool WindowSelectorItem::ShouldBeObservedWhenExiting() const {
-  if (!IsNewOverviewAnimationsEnabled())
-    return false;
   return should_be_observed_when_exiting_;
 }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
index 34ef6a62..459e0b9c 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -34,26 +34,6 @@
              : nullptr;
 }
 
-// Returns the window selector item in overview that contains the specified
-// location. Returns nullptr if there is no such window selector item.
-WindowSelectorItem* GetWindowSelectorItemContains(
-    const gfx::Point& location_in_screen) {
-  if (!Shell::Get()->window_selector_controller()->IsSelecting())
-    return nullptr;
-
-  WindowGrid* current_grid = GetWindowSelector()->GetGridWithRootWindow(
-      wm::GetRootWindowAt(location_in_screen));
-  if (!current_grid)
-    return nullptr;
-
-  const auto& windows = current_grid->window_list();
-  for (const auto& window_selector_item : windows) {
-    if (window_selector_item->target_bounds().Contains(location_in_screen))
-      return window_selector_item.get();
-  }
-  return nullptr;
-}
-
 }  // namespace
 
 TabletModeWindowDragDelegate::TabletModeWindowDragDelegate()
@@ -92,11 +72,13 @@
   UpdateForDraggedWindow(location_in_screen);
 
   // Update drag indicators and preview window if necessary.
-  split_view_drag_indicators_->SetIndicatorState(
-      GetIndicatorState(location_in_screen), location_in_screen);
+  IndicatorState indicator_state = GetIndicatorState(location_in_screen);
+  split_view_drag_indicators_->SetIndicatorState(indicator_state,
+                                                 location_in_screen);
+
   if (GetWindowSelector()) {
-    GetWindowSelector()->OnWindowDragContinued(dragged_window_,
-                                               location_in_screen);
+    GetWindowSelector()->OnWindowDragContinued(
+        dragged_window_, location_in_screen, indicator_state);
   }
 }
 
@@ -209,17 +191,9 @@
   const bool can_snap = split_view_controller_->CanSnap(dragged_window_);
   if (snap_position != SplitViewController::NONE &&
       !split_view_controller_->IsSplitViewModeActive() && can_snap) {
-    // Show the preview window if |location_in_screen| is not contained by an
-    // eligible target window item to merge the dragged window.
-    WindowSelectorItem* item =
-        GetWindowSelectorItemContains(location_in_screen);
-    if (!item || !item->GetWindow()->GetProperty(
-                     ash::kIsDeferredTabDraggingTargetWindowKey)) {
-      return snap_position == SplitViewController::LEFT
-                 ? IndicatorState::kPreviewAreaLeft
-                 : IndicatorState::kPreviewAreaRight;
-    }
-    return IndicatorState::kNone;
+    return snap_position == SplitViewController::LEFT
+               ? IndicatorState::kPreviewAreaLeft
+               : IndicatorState::kPreviewAreaRight;
   }
 
   // Do not show the drag indicators if split view mode is active.
@@ -239,7 +213,7 @@
   // active at the moment, do not show the drag indicators.
   if (location_in_screen.y() >=
           GetMaximizeVerticalThreshold(work_area_bounds) &&
-      GetSnapPosition(location_in_screen) == SplitViewController::NONE &&
+      snap_position == SplitViewController::NONE &&
       !Shell::Get()->window_selector_controller()->IsSelecting()) {
     return IndicatorState::kNone;
   }
diff --git a/ash/wm/top_level_window_factory.cc b/ash/wm/top_level_window_factory.cc
index 99ff6a1..ed3fa4f 100644
--- a/ash/wm/top_level_window_factory.cc
+++ b/ash/wm/top_level_window_factory.cc
@@ -10,7 +10,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/root_window_settings.h"
 #include "ash/shell.h"
-#include "ash/window_manager.h"
 #include "ash/wm/container_finder.h"
 #include "ash/wm/non_client_frame_controller.h"
 #include "ash/wm/property_util.h"
@@ -24,7 +23,6 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/mus/property_utils.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -126,7 +124,6 @@
 // Does the real work of CreateAndParentTopLevelWindow() once the appropriate
 // RootWindowController was found.
 aura::Window* CreateAndParentTopLevelWindowInRoot(
-    aura::WindowManagerClient* window_manager_client,
     RootWindowController* root_window_controller,
     ui::mojom::WindowType window_type,
     aura::PropertyConverter* property_converter,
@@ -154,7 +151,7 @@
     NonClientFrameController* non_client_frame_controller =
         new NonClientFrameController(container_window, context, bounds,
                                      window_type, property_converter,
-                                     properties, window_manager_client);
+                                     properties);
     return non_client_frame_controller->window();
   }
 
@@ -202,7 +199,6 @@
 }  // namespace
 
 aura::Window* CreateAndParentTopLevelWindow(
-    WindowManager* window_manager,
     ui::mojom::WindowType window_type,
     aura::PropertyConverter* property_converter,
     std::map<std::string, std::vector<uint8_t>>* properties) {
@@ -212,7 +208,6 @@
   RootWindowController* root_window_controller =
       GetRootWindowControllerForNewTopLevelWindow(properties);
   aura::Window* window = CreateAndParentTopLevelWindowInRoot(
-      window_manager ? window_manager->window_manager_client() : nullptr,
       root_window_controller, window_type, property_converter, properties);
   DisconnectedAppHandler::Create(window);
 
@@ -231,9 +226,6 @@
       properties->find(ui::mojom::WindowManager::kFocusable_InitProperty);
   if (focusable_iter != properties->end()) {
     bool can_focus = mojo::ConvertTo<bool>(focusable_iter->second);
-    // TODO(crbug.com/842301): Add support for window-service as a library.
-    if (window_manager)
-      window_manager->window_tree_client()->SetCanFocus(window, can_focus);
     NonClientFrameController* non_client_frame_controller =
         NonClientFrameController::Get(window);
     window->SetProperty(ui::ws2::kCanFocus, can_focus);
diff --git a/ash/wm/top_level_window_factory.h b/ash/wm/top_level_window_factory.h
index 30f8043b..95492ef8 100644
--- a/ash/wm/top_level_window_factory.h
+++ b/ash/wm/top_level_window_factory.h
@@ -26,14 +26,10 @@
 
 namespace ash {
 
-class WindowManager;
-
 // Creates and parents a new top-level window and returns it. The returned
 // aura::Window is owned by its parent. A value of null is returned if invalid
 // poarameters are supplied.
-// TODO(ws): Refine this for the Window Service as-a-library (no WindowManager).
 ASH_EXPORT aura::Window* CreateAndParentTopLevelWindow(
-    WindowManager* window_manager,
     ui::mojom::WindowType window_type,
     aura::PropertyConverter* property_converter,
     std::map<std::string, std::vector<uint8_t>>* properties);
diff --git a/ash/wm/top_level_window_factory_unittest.cc b/ash/wm/top_level_window_factory_unittest.cc
index 059235d..775b151 100644
--- a/ash/wm/top_level_window_factory_unittest.cc
+++ b/ash/wm/top_level_window_factory_unittest.cc
@@ -13,8 +13,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/window_manager.h"
-#include "ash/window_manager_service.h"
 #include "ash/wm/window_properties.h"
 #include "mojo/public/cpp/bindings/map.h"
 #include "services/ui/public/cpp/property_type_converters.h"
diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h
index 1ecb3189..d1b1a36 100644
--- a/ash/wm/window_properties.h
+++ b/ash/wm/window_properties.h
@@ -20,6 +20,10 @@
 }  // namespace wm
 
 // Used with kWidgetCreationType to indicate source of the widget creation.
+//
+// TODO: investigate removing this. If it's still needed, we can likely ask
+// the window service if it has a remote client for the window rather than using
+// a property. https://crbug.com/865616
 enum class WidgetCreationType {
   // The widget was created internally, and not at the request of a client.
   // For example, overview mode creates a number of widgets. These widgets are
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 11b0ae9..36f11195 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -21,12 +21,11 @@
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
+#include "ash/ws/window_service_owner.h"
+#include "services/ui/ws2/window_service.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/focus_client.h"
-#include "ui/aura/mus/window_manager_delegate.h"
-#include "ui/aura/mus/window_port_mus.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -62,6 +61,14 @@
   return true;
 }
 
+// Asks the remote client that owns |window| to close it. Returns true if there
+// was a remote client for |window|, false otherwise.
+bool AskRemoteClientToCloseWindow(aura::Window* window) {
+  ui::ws2::WindowService* window_service =
+      Shell::Get()->window_service_owner()->window_service();
+  return window_service && window_service->RequestClose(window);
+}
+
 }  // namespace
 
 // TODO(beng): replace many of these functions with the corewm versions.
@@ -193,27 +200,17 @@
 }
 
 void CloseWidgetForWindow(aura::Window* window) {
-  if (Shell::GetAshConfig() == Config::MASH_DEPRECATED &&
-      window->GetProperty(kWidgetCreationTypeKey) ==
-          WidgetCreationType::FOR_CLIENT) {
-    // NOTE: in the FOR_CLIENT case there is not necessarily a widget associated
-    // with the window. Mash only creates widgets for top level windows if mash
-    // renders the non-client frame.
-    DCHECK(Shell::window_manager_client());
-    Shell::window_manager_client()->RequestClose(window);
+  if (AskRemoteClientToCloseWindow(window))
     return;
-  }
+
   views::Widget* widget = GetInternalWidgetForWindow(window);
   DCHECK(widget);
   widget->Close();
 }
 
+// TODO(sky): investigate removing this entirely. https://crbug.com/842365
 void AddLimitedPreTargetHandlerForWindow(ui::EventHandler* handler,
                                          aura::Window* window) {
-  // In mus AddPreTargetHandler() only works for windows created by this client.
-  DCHECK(Shell::GetAshConfig() != Config::MASH_DEPRECATED ||
-         Shell::window_tree_client()->WasCreatedByThisClient(
-             aura::WindowMus::Get(window)));
   window->AddPreTargetHandler(handler);
 }
 
diff --git a/ash/wm/workspace/workspace_event_handler_classic.h b/ash/wm/workspace/workspace_event_handler_classic.h
index 9889b644..9e77d09 100644
--- a/ash/wm/workspace/workspace_event_handler_classic.h
+++ b/ash/wm/workspace/workspace_event_handler_classic.h
@@ -16,6 +16,7 @@
 
 namespace ash {
 
+// TODO: fold this back into WorkspaceEventHandler. https://crbug.com/842365
 class ASH_EXPORT WorkspaceEventHandlerClassic : public ui::EventHandler,
                                                 public WorkspaceEventHandler {
  public:
diff --git a/ash/wm/workspace/workspace_event_handler_mash.cc b/ash/wm/workspace/workspace_event_handler_mash.cc
deleted file mode 100644
index f2e4e3a..0000000
--- a/ash/wm/workspace/workspace_event_handler_mash.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/wm/workspace/workspace_event_handler_mash.h"
-
-#include "ui/aura/window.h"
-#include "ui/base/class_property.h"
-
-DEFINE_UI_CLASS_PROPERTY_TYPE(ash::WorkspaceEventHandlerMash*);
-
-namespace {
-
-DEFINE_UI_CLASS_PROPERTY_KEY(ash::WorkspaceEventHandlerMash*,
-                             kWorkspaceEventHandlerProperty,
-                             nullptr);
-
-}  // namespace
-
-namespace ash {
-
-WorkspaceEventHandlerMash::WorkspaceEventHandlerMash(
-    aura::Window* workspace_window)
-    : workspace_window_(workspace_window) {
-  workspace_window_->SetProperty(kWorkspaceEventHandlerProperty, this);
-}
-
-WorkspaceEventHandlerMash::~WorkspaceEventHandlerMash() {
-  workspace_window_->ClearProperty(kWorkspaceEventHandlerProperty);
-}
-
-// static
-WorkspaceEventHandlerMash* WorkspaceEventHandlerMash::Get(
-    aura::Window* window) {
-  return window->GetProperty(kWorkspaceEventHandlerProperty);
-}
-
-}  // namespace ash
diff --git a/ash/wm/workspace/workspace_event_handler_mash.h b/ash/wm/workspace/workspace_event_handler_mash.h
deleted file mode 100644
index 6d02e0d0..0000000
--- a/ash/wm/workspace/workspace_event_handler_mash.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_MASH_H_
-#define ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_MASH_H_
-
-#include "ash/wm/workspace/workspace_event_handler.h"
-#include "base/macros.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ash {
-
-// TODO(sky): investigate if can use aura version.
-class WorkspaceEventHandlerMash : public WorkspaceEventHandler {
- public:
-  explicit WorkspaceEventHandlerMash(aura::Window* workspace_window);
-  ~WorkspaceEventHandlerMash() override;
-
-  // Returns the WorkspaceEventHandlerMash associated with |window|, or null
-  // if |window| is not the workspace window.
-  static WorkspaceEventHandlerMash* Get(aura::Window* window);
-
-  // Returns the window associated with the workspace.
-  aura::Window* workspace_window() { return workspace_window_; }
-
- private:
-  aura::Window* workspace_window_;
-
-  DISALLOW_COPY_AND_ASSIGN(WorkspaceEventHandlerMash);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_MASH_H_
diff --git a/ash/ws/window_service_delegate_impl.cc b/ash/ws/window_service_delegate_impl.cc
index 697eabe0..9b2231a4 100644
--- a/ash/ws/window_service_delegate_impl.cc
+++ b/ash/ws/window_service_delegate_impl.cc
@@ -83,9 +83,8 @@
   ui::mojom::WindowType window_type =
       aura::GetWindowTypeFromProperties(property_map);
 
-  auto* window =
-      CreateAndParentTopLevelWindow(nullptr /* window_manager */, window_type,
-                                    property_converter, &property_map);
+  auto* window = CreateAndParentTopLevelWindow(window_type, property_converter,
+                                               &property_map);
   return base::WrapUnique<aura::Window>(window);
 }
 
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 88c290f..e57194ec 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -32,11 +32,6 @@
 #define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
                                      __pragma(warning(disable:n))
 
-// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level.  The level
-// remains in effect until popped by MSVC_POP_WARNING().  Use 0 to disable all
-// warnings.
-#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
-
 // Pop effects of innermost MSVC_PUSH_* macro.
 #define MSVC_POP_WARNING() __pragma(warning(pop))
 
@@ -48,7 +43,6 @@
 #define _Printf_format_string_
 #define MSVC_SUPPRESS_WARNING(n)
 #define MSVC_PUSH_DISABLE_WARNING(n)
-#define MSVC_PUSH_WARNING_LEVEL(n)
 #define MSVC_POP_WARNING()
 #define MSVC_DISABLE_OPTIMIZE()
 #define MSVC_ENABLE_OPTIMIZE()
diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
index 24cfa5a..8c2ad90 100644
--- a/base/debug/activity_tracker.cc
+++ b/base/debug/activity_tracker.cc
@@ -1358,6 +1358,10 @@
 }
 
 ThreadActivityTracker* GlobalActivityTracker::CreateTrackerForCurrentThread() {
+  // It is not safe to use TLS once TLS has been destroyed.
+  if (base::ThreadLocalStorage::HasBeenDestroyed())
+    return nullptr;
+
   DCHECK(!this_thread_tracker_.Get());
 
   PersistentMemoryAllocator::Reference mem_reference;
diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h
index 5647d86..96e3126 100644
--- a/base/debug/activity_tracker.h
+++ b/base/debug/activity_tracker.h
@@ -861,12 +861,6 @@
       if (!global_tracker)
         return nullptr;
 
-      // It is not safe to use TLS once TLS has been destroyed. This can happen
-      // if code that runs late during thread destruction tries to use a
-      // base::Lock. See https://crbug.com/864589.
-      if (base::ThreadLocalStorage::HasBeenDestroyed())
-        return nullptr;
-
       if (lock_allowed)
         return global_tracker->GetOrCreateTrackerForCurrentThread();
       else
@@ -955,6 +949,10 @@
   // is no significant lookup time required to find the one for the calling
   // thread. Ownership remains with the global tracker.
   ThreadActivityTracker* GetTrackerForCurrentThread() {
+    // It is not safe to use TLS once TLS has been destroyed.
+    if (base::ThreadLocalStorage::HasBeenDestroyed())
+      return nullptr;
+
     return reinterpret_cast<ThreadActivityTracker*>(this_thread_tracker_.Get());
   }
 
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 4571c72..3723960a 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -454,6 +454,10 @@
   pump_->ScheduleWork();
 }
 
+TimeTicks MessageLoop::CapAtOneDay(TimeTicks next_run_time) {
+  return std::min(next_run_time, recent_time_ + TimeDelta::FromDays(1));
+}
+
 bool MessageLoop::DoWork() {
   if (!task_execution_allowed_)
     return false;
@@ -502,7 +506,7 @@
   if (next_run_time > recent_time_) {
     recent_time_ = TimeTicks::Now();  // Get a better view of Now();
     if (next_run_time > recent_time_) {
-      *next_delayed_work_time = next_run_time;
+      *next_delayed_work_time = CapAtOneDay(next_run_time);
       return false;
     }
   }
@@ -510,8 +514,8 @@
   PendingTask pending_task = incoming_task_queue_->delayed_tasks().Pop();
 
   if (incoming_task_queue_->delayed_tasks().HasTasks()) {
-    *next_delayed_work_time =
-        incoming_task_queue_->delayed_tasks().Peek().delayed_run_time;
+    *next_delayed_work_time = CapAtOneDay(
+        incoming_task_queue_->delayed_tasks().Peek().delayed_run_time);
   }
 
   return DeferOrRunPendingTask(std::move(pending_task));
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 60103336..7c31a12 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -263,6 +263,14 @@
   // responsible for synchronizing ScheduleWork() calls.
   void ScheduleWork();
 
+  // Returns |next_run_time| capped at 1 day from |recent_time_|. This is used
+  // to mitigate https://crbug.com/850450 where some platforms are unhappy with
+  // delays > 100,000,000 seconds. In practice, a diagnosis metric showed that
+  // no sleep > 1 hour ever completes (always interrupted by an earlier
+  // MessageLoop event) and 99% of completed sleeps are the ones scheduled for
+  // <= 1 second. Details @ https://crrev.com/c/1142589.
+  TimeTicks CapAtOneDay(TimeTicks next_run_time);
+
   // MessagePump::Delegate methods:
   bool DoWork() override;
   bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index b525536..ea94f4f 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -116,8 +116,7 @@
   if (!surface_range_.IsValid())
     return;
 
-  auto* primary = CreateSurfaceDrawQuad(render_pass, surface_range_.end(),
-                                        surface_range_.start());
+  auto* primary = CreateSurfaceDrawQuad(render_pass, surface_range_);
   if (primary && surface_range_.end() != surface_range_.start()) {
     // Add the primary surface ID as a dependency.
     append_quads_data->activation_dependencies.push_back(surface_range_.end());
@@ -141,9 +140,8 @@
 
 viz::SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad(
     viz::RenderPass* render_pass,
-    const viz::SurfaceId& primary_surface_id,
-    const base::Optional<viz::SurfaceId>& fallback_surface_id) {
-  DCHECK(primary_surface_id.is_valid());
+    const viz::SurfaceRange& surface_range) {
+  DCHECK(surface_range.end().is_valid());
 
   float device_scale_factor = layer_tree_impl()->device_scale_factor();
 
@@ -168,9 +166,9 @@
 
   auto* surface_draw_quad =
       render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
-  surface_draw_quad->SetNew(
-      shared_quad_state, quad_rect, visible_quad_rect, primary_surface_id,
-      fallback_surface_id, background_color(), stretch_content_to_fill_bounds_);
+  surface_draw_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
+                            surface_range, background_color(),
+                            stretch_content_to_fill_bounds_);
 
   return surface_draw_quad;
 }
diff --git a/cc/layers/surface_layer_impl.h b/cc/layers/surface_layer_impl.h
index 8addaaa..e09d631 100644
--- a/cc/layers/surface_layer_impl.h
+++ b/cc/layers/surface_layer_impl.h
@@ -71,8 +71,7 @@
  private:
   viz::SurfaceDrawQuad* CreateSurfaceDrawQuad(
       viz::RenderPass* render_pass,
-      const viz::SurfaceId& surface_id,
-      const base::Optional<viz::SurfaceId>& fallback_surface_id);
+      const viz::SurfaceRange& surface_range);
 
   void GetDebugBorderProperties(SkColor* color, float* width) const override;
   void AppendRainbowDebugBorder(viz::RenderPass* render_pass);
diff --git a/cc/layers/surface_layer_impl_unittest.cc b/cc/layers/surface_layer_impl_unittest.cc
index c51be4b..c0fc9e7 100644
--- a/cc/layers/surface_layer_impl_unittest.cc
+++ b/cc/layers/surface_layer_impl_unittest.cc
@@ -157,17 +157,17 @@
       viz::SurfaceDrawQuad::MaterialCast(render_pass->quad_list.ElementAt(2));
   ASSERT_TRUE(surface_draw_quad3);
 
-  EXPECT_EQ(surface_id1, surface_draw_quad1->primary_surface_id);
+  EXPECT_EQ(surface_id1, surface_draw_quad1->surface_range.end());
   EXPECT_EQ(SK_ColorBLUE, surface_draw_quad1->default_background_color);
-  EXPECT_EQ(surface_id2, surface_draw_quad1->fallback_surface_id);
+  EXPECT_EQ(surface_id2, surface_draw_quad1->surface_range.start());
 
-  EXPECT_EQ(surface_id1, surface_draw_quad2->primary_surface_id);
+  EXPECT_EQ(surface_id1, surface_draw_quad2->surface_range.end());
   EXPECT_EQ(SK_ColorBLUE, surface_draw_quad2->default_background_color);
-  EXPECT_EQ(base::nullopt, surface_draw_quad2->fallback_surface_id);
+  EXPECT_EQ(base::nullopt, surface_draw_quad2->surface_range.start());
 
-  EXPECT_EQ(surface_id1, surface_draw_quad3->primary_surface_id);
+  EXPECT_EQ(surface_id1, surface_draw_quad3->surface_range.end());
   EXPECT_EQ(SK_ColorBLUE, surface_draw_quad3->default_background_color);
-  EXPECT_EQ(surface_id2, surface_draw_quad3->fallback_surface_id);
+  EXPECT_EQ(surface_id2, surface_draw_quad3->surface_range.start());
 }
 
 // This test verifies that if one SurfaceLayerImpl has a deadline
@@ -256,8 +256,8 @@
       viz::SurfaceDrawQuad::MaterialCast(render_pass->quad_list.ElementAt(0));
   ASSERT_TRUE(surface_draw_quad1);
 
-  EXPECT_EQ(surface_id1, surface_draw_quad1->primary_surface_id);
-  EXPECT_EQ(surface_id1, surface_draw_quad1->fallback_surface_id);
+  EXPECT_EQ(surface_id1, surface_draw_quad1->surface_range.end());
+  EXPECT_EQ(surface_id1, surface_draw_quad1->surface_range.start());
   EXPECT_EQ(SK_ColorBLUE, surface_draw_quad1->default_background_color);
 }
 
diff --git a/cc/trees/element_id.h b/cc/trees/element_id.h
index 1b581ba88..ad88cc6 100644
--- a/cc/trees/element_id.h
+++ b/cc/trees/element_id.h
@@ -47,7 +47,7 @@
 // targets. A Layer's element id can change over the Layer's lifetime because
 // non-default ElementIds are only set during an animation's lifetime.
 struct CC_EXPORT ElementId {
-  explicit ElementId(int id) : id_(id) {}
+  explicit ElementId(ElementIdType id) : id_(id) {}
   ElementId() : ElementId(kInvalidElementId) {}
 
   bool operator==(const ElementId& o) const;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java
index 31c06894..3fd859a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java
@@ -106,7 +106,7 @@
         public void runActions() {
             Context context = ContextUtils.getApplicationContext();
             OmahaBase.onForegroundSessionStart(context);
-            DelayedInvalidationsController.getInstance().notifyPendingInvalidations(context);
+            DelayedInvalidationsController.getInstance().notifyPendingInvalidations();
         }
 
         public long getDelayToRun() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
index 2f98be01..c7202f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -53,7 +53,6 @@
     private final DownloadSharedPreferenceHelper mDownloadSharedPreferenceHelper =
             DownloadSharedPreferenceHelper.getInstance();
 
-    private final Context mApplicationContext;
     private final DownloadNotificationService2 mDownloadNotificationService;
     private final Handler mHandler = new Handler();
     private final Runnable mStopSelfRunnable = new Runnable() {
@@ -64,7 +63,6 @@
     };
 
     public DownloadBroadcastManager() {
-        mApplicationContext = ContextUtils.getApplicationContext();
         mDownloadNotificationService = DownloadNotificationService2.getInstance();
     }
 
@@ -109,9 +107,7 @@
      * Cancel any download resumption tasks and reset the number of resumption attempts available.
      */
     void cancelQueuedResumptions() {
-        DownloadResumptionScheduler
-                .getDownloadResumptionScheduler(ContextUtils.getApplicationContext())
-                .cancel();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().cancel();
         // Reset number of attempts left if the action is triggered by user.
         clearResumptionAttemptLeft();
     }
@@ -142,7 +138,8 @@
                 // If user manually resumes a download, update the network type if it
                 // is not metered previously.
                 boolean canDownloadWhileMetered = entry.canDownloadWhileMetered
-                        || DownloadManagerService.isActiveNetworkMetered(mApplicationContext);
+                        || DownloadManagerService.isActiveNetworkMetered(
+                                   ContextUtils.getApplicationContext());
                 // Update the SharedPreference entry.
                 mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
                         new DownloadSharedPreferenceEntry(entry.id, entry.notificationId,
@@ -191,9 +188,8 @@
         };
 
         try {
-            ChromeBrowserInitializer.getInstance(mApplicationContext).handlePreNativeStartup(parts);
-            ChromeBrowserInitializer.getInstance(mApplicationContext)
-                    .handlePostNativeStartup(true, parts);
+            ChromeBrowserInitializer.getInstance().handlePreNativeStartup(parts);
+            ChromeBrowserInitializer.getInstance().handlePostNativeStartup(true, parts);
         } catch (ProcessInitException e) {
             Log.e(TAG, "Unable to load native library.", e);
             ChromeApplication.reportStartupErrorAndExit(e);
@@ -209,7 +205,7 @@
         // Handle actions that do not require a specific entry or service delegate.
         switch (action) {
             case ACTION_NOTIFICATION_CLICKED:
-                openDownload(mApplicationContext, intent, id);
+                openDownload(ContextUtils.getApplicationContext(), intent, id);
                 return;
 
             case ACTION_DOWNLOAD_OPEN:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 8efcdee8..c069662 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -150,7 +150,6 @@
     private final long mUpdateDelayInMillis;
 
     private final Handler mHandler;
-    private final Context mContext;
 
     /** Generic interface for notifying external UI components about downloads and their states. */
     public interface DownloadObserver extends DownloadSharedPreferenceHelper.Observer {
@@ -234,17 +233,16 @@
      */
     public static DownloadManagerService getDownloadManagerService() {
         ThreadUtils.assertOnUiThread();
-        Context appContext = ContextUtils.getApplicationContext();
         if (sDownloadManagerService == null) {
             // TODO(crbug.com/765327): Remove temporary fix after flag is no longer being used.
             DownloadNotifier downloadNotifier =
                     (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
                                     .isStartupSuccessfullyCompleted()
                             || !ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOADS_FOREGROUND))
-                    ? new SystemDownloadNotifier(appContext)
-                    : new SystemDownloadNotifier2(appContext);
+                    ? new SystemDownloadNotifier()
+                    : new SystemDownloadNotifier2();
             sDownloadManagerService = new DownloadManagerService(
-                    appContext, downloadNotifier, new Handler(), UPDATE_DELAY_MILLIS);
+                    downloadNotifier, new Handler(), UPDATE_DELAY_MILLIS);
         }
         return sDownloadManagerService;
     }
@@ -273,19 +271,19 @@
     }
 
     @VisibleForTesting
-    protected DownloadManagerService(Context context, DownloadNotifier downloadNotifier,
-            Handler handler, long updateDelayInMillis) {
-        mContext = context;
+    protected DownloadManagerService(
+            DownloadNotifier downloadNotifier, Handler handler, long updateDelayInMillis) {
+        Context applicationContext = ContextUtils.getApplicationContext();
         mSharedPrefs = ContextUtils.getAppSharedPreferences();
         // Clean up unused shared prefs. TODO(qinmin): remove this after M61.
         mSharedPrefs.edit().remove(PREF_IS_DOWNLOAD_HOME_ENABLED).apply();
         mDownloadNotifier = downloadNotifier;
         mUpdateDelayInMillis = updateDelayInMillis;
         mHandler = handler;
-        mDownloadSnackbarController = new DownloadSnackbarController(context);
-        mDownloadManagerDelegate = new DownloadManagerDelegate(mContext);
+        mDownloadSnackbarController = new DownloadSnackbarController();
+        mDownloadManagerDelegate = new DownloadManagerDelegate(applicationContext);
         mOMADownloadHandler = new OMADownloadHandler(
-                context, mDownloadManagerDelegate, mDownloadSnackbarController);
+                applicationContext, mDownloadManagerDelegate, mDownloadSnackbarController);
         // Note that this technically leaks the native object, however, DownloadManagerService
         // is a singleton that lives forever and there's no clean shutdown of Chrome on Android.
         init();
@@ -317,8 +315,8 @@
     /**
      * Pre-load shared prefs to avoid being blocked on the disk access async task in the future.
      */
-    public static void warmUpSharedPrefs(Context context) {
-        getAutoRetryCountSharedPreference(context);
+    public static void warmUpSharedPrefs() {
+        getAutoRetryCountSharedPreference();
     }
 
     public DownloadNotifier getDownloadNotifier() {
@@ -383,10 +381,12 @@
         if (progress == null) return;
         if (!isAutoResumable || sIsNetworkListenerDisabled) return;
         ConnectivityManager cm =
-                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+                (ConnectivityManager) ContextUtils.getApplicationContext().getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
         NetworkInfo info = cm.getActiveNetworkInfo();
         if (info == null || !info.isConnected()) return;
-        if (progress.mCanDownloadWhileMetered || !isActiveNetworkMetered(mContext)) {
+        if (progress.mCanDownloadWhileMetered
+                || !isActiveNetworkMetered(ContextUtils.getApplicationContext())) {
             // Normally the download will automatically resume when network is reconnected.
             // However, if there are multiple network connections and the interruption is caused
             // by switching between active networks, onConnectionTypeChanged() will not get called.
@@ -541,8 +541,10 @@
             @Override
             public Pair<Long, Boolean> doInBackground(Void... params) {
                 boolean success = addCompletedDownload(item);
-                boolean canResolve = success ? (isOMADownloadDescription(item.getDownloadInfo())
-                        || canResolveDownloadItem(mContext, item, isSupportedMimeType)) : false;
+                boolean canResolve = success
+                        && (isOMADownloadDescription(item.getDownloadInfo())
+                                   || canResolveDownloadItem(ContextUtils.getApplicationContext(),
+                                              item, isSupportedMimeType));
                 return Pair.create(item.getSystemDownloadId(), canResolve);
             }
 
@@ -665,8 +667,9 @@
         if (progress == null) {
             if (!downloadItem.getDownloadInfo().isPaused()) {
                 long startTime = System.currentTimeMillis();
-                progress = new DownloadProgress(
-                        startTime, isActiveNetworkMetered(mContext), downloadItem, downloadStatus);
+                progress = new DownloadProgress(startTime,
+                        isActiveNetworkMetered(ContextUtils.getApplicationContext()), downloadItem,
+                        downloadStatus);
                 progress.mIsUpdated = true;
                 progress.mIsSupportedMimeType = isSupportedMimeType;
                 mDownloadProgressMap.put(id, progress);
@@ -776,7 +779,7 @@
             return;
         }
 
-        DownloadUtils.showDownloadStartToast(mContext);
+        DownloadUtils.showDownloadStartToast(ContextUtils.getApplicationContext());
         addUmaStatsEntry(new DownloadUmaStatsEntry(
                 String.valueOf(downloadId), downloadItem.getStartTime(), 0, false, true, 0, 0));
     }
@@ -862,7 +865,7 @@
     /** See {@link #openDownloadedContent(Context, String, boolean, boolean, String, long)}. */
     protected void openDownloadedContent(final DownloadInfo downloadInfo, final long downloadId,
             @DownloadOpenSource int source) {
-        openDownloadedContent(mContext, downloadInfo.getFilePath(),
+        openDownloadedContent(ContextUtils.getApplicationContext(), downloadInfo.getFilePath(),
                 isSupportedMimeType(downloadInfo.getMimeType()), downloadInfo.isOffTheRecord(),
                 downloadInfo.getDownloadGuid(), downloadId, downloadInfo.getOriginalUrl(),
                 downloadInfo.getReferrer(), source);
@@ -934,7 +937,8 @@
                     failureMessage,
                     reason == DownloadManager.ERROR_FILE_ALREADY_EXISTS);
         } else {
-            Toast.makeText(mContext, failureMessage, Toast.LENGTH_SHORT).show();
+            Toast.makeText(ContextUtils.getApplicationContext(), failureMessage, Toast.LENGTH_SHORT)
+                    .show();
         }
     }
 
@@ -991,14 +995,15 @@
             // can start. If the previous connection type is metered, manually resuming on an
             // unmetered network should not affect the original connection type.
             if (!progress.mCanDownloadWhileMetered) {
-                progress.mCanDownloadWhileMetered = isActiveNetworkMetered(mContext);
+                progress.mCanDownloadWhileMetered =
+                        isActiveNetworkMetered(ContextUtils.getApplicationContext());
             }
             incrementDownloadRetryCount(item.getId(), true);
             clearDownloadRetryCount(item.getId(), true);
         } else {
             // TODO(qinmin): Consolidate this logic with the logic in notification service that
             // throttles browser restarts.
-            SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference(mContext);
+            SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference();
             int count = sharedPrefs.getInt(item.getId(), 0);
             if (count >= getAutoResumptionLimit()) {
                 removeAutoResumableDownload(item.getId());
@@ -1329,7 +1334,7 @@
     public void onConnectionTypeChanged(int connectionType) {
         if (mAutoResumableDownloadIds.isEmpty()) return;
         if (connectionType == ConnectionType.CONNECTION_NONE) return;
-        boolean isMetered = isActiveNetworkMetered(mContext);
+        boolean isMetered = isActiveNetworkMetered(ContextUtils.getApplicationContext());
         // Make a copy of |mAutoResumableDownloadIds| as scheduleDownloadResumption() may delete
         // elements inside the array.
         List<String> copies = new ArrayList<String>(mAutoResumableDownloadIds);
@@ -1479,20 +1484,21 @@
      */
     @Override
     public void broadcastDownloadAction(DownloadItem downloadItem, String action) {
+        Context appContext = ContextUtils.getApplicationContext();
         if (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
                         .isStartupSuccessfullyCompleted()
                 || !ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOADS_FOREGROUND)) {
-            Intent intent = DownloadNotificationService.buildActionIntent(mContext, action,
+            Intent intent = DownloadNotificationService.buildActionIntent(appContext, action,
                     LegacyHelpers.buildLegacyContentId(false, downloadItem.getId()),
                     downloadItem.getDownloadInfo().isOffTheRecord());
             addCancelExtra(intent, downloadItem);
-            mContext.sendBroadcast(intent);
+            appContext.sendBroadcast(intent);
         } else {
-            Intent intent = DownloadNotificationFactory.buildActionIntent(mContext, action,
+            Intent intent = DownloadNotificationFactory.buildActionIntent(appContext, action,
                     LegacyHelpers.buildLegacyContentId(false, downloadItem.getId()),
                     downloadItem.getDownloadInfo().isOffTheRecord());
             addCancelExtra(intent, downloadItem);
-            mContext.startService(intent);
+            appContext.startService(intent);
         }
     }
 
@@ -1690,7 +1696,8 @@
                 boolean isSupportedMimeType =
                         isSupportedMimeType(downloadItem.getDownloadInfo().getMimeType());
                 boolean canResolve = isOMADownloadDescription(downloadItem.getDownloadInfo())
-                        || canResolveDownloadItem(mContext, downloadItem, isSupportedMimeType);
+                        || canResolveDownloadItem(ContextUtils.getApplicationContext(),
+                                   downloadItem, isSupportedMimeType);
                 return canResolve && shouldOpenAfterDownload(downloadItem.getDownloadInfo());
             }
 
@@ -1732,30 +1739,31 @@
      * @param reason Reason of failure reported by android DownloadManager.
      */
     private String getDownloadFailureMessage(String fileName, int reason) {
+        Context appContext = ContextUtils.getApplicationContext();
         switch (reason) {
             case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_file_already_exists, fileName);
             case DownloadManager.ERROR_FILE_ERROR:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_file_system_error, fileName);
             case DownloadManager.ERROR_INSUFFICIENT_SPACE:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_insufficient_space, fileName);
             case DownloadManager.ERROR_CANNOT_RESUME:
             case DownloadManager.ERROR_HTTP_DATA_ERROR:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_network_failures, fileName);
             case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
             case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_server_issues, fileName);
             case DownloadManager.ERROR_DEVICE_NOT_FOUND:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_storage_not_found, fileName);
             case DownloadManager.ERROR_UNKNOWN:
             default:
-                return mContext.getString(
+                return appContext.getString(
                         R.string.download_failed_reason_unknown_error, fileName);
         }
     }
@@ -1764,8 +1772,9 @@
      * Returns the SharedPreferences for download retry count.
      * @return The SharedPreferences to use.
      */
-    private static SharedPreferences getAutoRetryCountSharedPreference(Context context) {
-        return context.getSharedPreferences(DOWNLOAD_RETRY_COUNT_FILE_NAME, Context.MODE_PRIVATE);
+    private static SharedPreferences getAutoRetryCountSharedPreference() {
+        return ContextUtils.getApplicationContext().getSharedPreferences(
+                DOWNLOAD_RETRY_COUNT_FILE_NAME, Context.MODE_PRIVATE);
     }
 
     /**
@@ -1788,7 +1797,7 @@
      * @param sharedPreferenceName Name of the SharedPreference entry.
      */
     private void incrementDownloadRetrySharedPreferenceCount(String sharedPreferenceName) {
-        SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference(mContext);
+        SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference();
         int count = sharedPrefs.getInt(sharedPreferenceName, 0);
         SharedPreferences.Editor editor = sharedPrefs.edit();
         count++;
@@ -1818,7 +1827,7 @@
      * @param isAutoRetryOnly Whether to clear the auto retry count only.
      */
     private void clearDownloadRetryCount(String downloadGuid, boolean isAutoRetryOnly) {
-        SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference(mContext);
+        SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference();
         String name = getDownloadRetryCountSharedPrefName(downloadGuid, !isAutoRetryOnly, false);
         int count = Math.min(sharedPrefs.getInt(name, 0), 200);
         assert count >= 0;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index e3bc9eb..47d3bfc4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -142,7 +142,6 @@
 
     private NotificationManager mNotificationManager;
     private SharedPreferences mSharedPrefs;
-    private Context mContext;
     private int mNextNotificationId;
     private int mNumAutoResumptionAttemptLeft;
     private Bitmap mDownloadSuccessLargeIcon;
@@ -410,9 +409,9 @@
 
     @Override
     public void onCreate() {
-        mContext = ContextUtils.getApplicationContext();
         mNotificationManager =
-                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
+                        Context.NOTIFICATION_SERVICE);
         mSharedPrefs = ContextUtils.getAppSharedPreferences();
         mNumAutoResumptionAttemptLeft =
                 mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT, MAX_RESUMPTION_ATTEMPT_LEFT);
@@ -457,7 +456,7 @@
             hideSummaryNotificationIfNecessary(-1);
         } else if (isDownloadOperationIntent(intent)) {
             handleDownloadOperation(intent);
-            DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).cancel();
+            DownloadResumptionScheduler.getDownloadResumptionScheduler().cancel();
             // Limit the number of auto resumption attempts in case Chrome falls into a vicious
             // cycle.
             if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) {
@@ -514,8 +513,8 @@
     void startForegroundInternal() {
         Log.w(TAG, "startForegroundInternal");
         if (!useForegroundService()) return;
-        Notification notification =
-                buildSummaryNotification(getApplicationContext(), mNotificationManager);
+        Notification notification = buildSummaryNotification(
+                ContextUtils.getApplicationContext(), mNotificationManager);
         startForeground(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY, notification);
     }
 
@@ -526,7 +525,7 @@
 
     private void rescheduleDownloads() {
         if (mNumAutoResumptionAttemptLeft <= 0) return;
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
     }
 
     @VisibleForTesting
@@ -771,14 +770,16 @@
         boolean indeterminate = (progress.isIndeterminate() || isDownloadPending);
         String contentText = null;
         if (isDownloadPending) {
-            contentText = mContext.getResources().getString(R.string.download_notification_pending);
+            contentText = ContextUtils.getApplicationContext().getResources().getString(
+                    R.string.download_notification_pending);
         } else if (indeterminate || timeRemainingInMillis < 0) {
             // TODO(dimich): Enable the byte count back in M59. See bug 704049 for more info and
             // details of what was temporarily reverted (for M58).
-            contentText = mContext.getResources().getString(R.string.download_started);
+            contentText = ContextUtils.getApplicationContext().getResources().getString(
+                    R.string.download_started);
         } else {
             contentText = DownloadUtils.getTimeOrFilesLeftString(
-                    mContext, progress, timeRemainingInMillis);
+                    ContextUtils.getApplicationContext(), progress, timeRemainingInMillis);
         }
         int resId = isDownloadPending ? R.drawable.ic_download_pending
                                       : android.R.drawable.stat_sys_download;
@@ -804,23 +805,27 @@
 
         if (!isTransient) {
             // Clicking on an in-progress download sends the user to see all their downloads.
-            Intent downloadHomeIntent =
-                    buildActionIntent(mContext, ACTION_NOTIFICATION_CLICKED, null, isOffTheRecord);
-            builder.setContentIntent(PendingIntent.getBroadcast(mContext, notificationId,
-                    downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+            Intent downloadHomeIntent = buildActionIntent(ContextUtils.getApplicationContext(),
+                    ACTION_NOTIFICATION_CLICKED, null, isOffTheRecord);
+            builder.setContentIntent(
+                    PendingIntent.getBroadcast(ContextUtils.getApplicationContext(), notificationId,
+                            downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
         }
         builder.setAutoCancel(false);
         if (icon != null) builder.setLargeIcon(icon);
 
-        Intent pauseIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_PAUSE, id, isOffTheRecord);
+        Intent pauseIntent = buildActionIntent(
+                ContextUtils.getApplicationContext(), ACTION_DOWNLOAD_PAUSE, id, isOffTheRecord);
         builder.addAction(R.drawable.ic_pause_white_24dp,
-                mContext.getResources().getString(R.string.download_notification_pause_button),
+                ContextUtils.getApplicationContext().getResources().getString(
+                        R.string.download_notification_pause_button),
                 buildPendingIntent(pauseIntent, notificationId));
 
-        Intent cancelIntent =
-                buildActionIntent(mContext, ACTION_DOWNLOAD_CANCEL, id, isOffTheRecord);
+        Intent cancelIntent = buildActionIntent(
+                ContextUtils.getApplicationContext(), ACTION_DOWNLOAD_CANCEL, id, isOffTheRecord);
         builder.addAction(R.drawable.btn_close_white,
-                mContext.getResources().getString(R.string.download_notification_cancel_button),
+                ContextUtils.getApplicationContext().getResources().getString(
+                        R.string.download_notification_cancel_button),
                 buildPendingIntent(cancelIntent, notificationId));
 
         updateNotification(notificationId, builder.build(), id,
@@ -846,7 +851,8 @@
         // the summary will take care of that for us.
         stopTrackingInProgressDownload(id, hasDownloadNotificationsInternal(notificationId));
         if (!hideSummaryNotificationIfNecessary(notificationId)) {
-            updateSummaryIcon(mContext, mNotificationManager, notificationId, null);
+            updateSummaryIcon(ContextUtils.getApplicationContext(), mNotificationManager,
+                    notificationId, null);
         }
     }
 
@@ -900,31 +906,34 @@
             return;
         }
 
-        String contentText =
-                mContext.getResources().getString(R.string.download_notification_paused);
+        String contentText = ContextUtils.getApplicationContext().getResources().getString(
+                R.string.download_notification_paused);
         ChromeNotificationBuilder builder =
                 buildNotification(R.drawable.ic_download_pause, fileName, contentText);
         int notificationId = entry == null ? getNotificationId(id) : entry.notificationId;
         if (!isTransient) {
             // Clicking on an in-progress download sends the user to see all their downloads.
-            Intent downloadHomeIntent =
-                    buildActionIntent(mContext, ACTION_NOTIFICATION_CLICKED, null, false);
-            builder.setContentIntent(PendingIntent.getBroadcast(mContext, notificationId,
-                    downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+            Intent downloadHomeIntent = buildActionIntent(
+                    ContextUtils.getApplicationContext(), ACTION_NOTIFICATION_CLICKED, null, false);
+            builder.setContentIntent(
+                    PendingIntent.getBroadcast(ContextUtils.getApplicationContext(), notificationId,
+                            downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
         }
         builder.setAutoCancel(false);
         if (icon != null) builder.setLargeIcon(icon);
 
-        Intent resumeIntent =
-                buildActionIntent(mContext, ACTION_DOWNLOAD_RESUME, id, isOffTheRecord);
+        Intent resumeIntent = buildActionIntent(
+                ContextUtils.getApplicationContext(), ACTION_DOWNLOAD_RESUME, id, isOffTheRecord);
         builder.addAction(R.drawable.ic_file_download_white_24dp,
-                mContext.getResources().getString(R.string.download_notification_resume_button),
+                ContextUtils.getApplicationContext().getResources().getString(
+                        R.string.download_notification_resume_button),
                 buildPendingIntent(resumeIntent, notificationId));
 
-        Intent cancelIntent =
-                buildActionIntent(mContext, ACTION_DOWNLOAD_CANCEL, id, isOffTheRecord);
+        Intent cancelIntent = buildActionIntent(
+                ContextUtils.getApplicationContext(), ACTION_DOWNLOAD_CANCEL, id, isOffTheRecord);
         builder.addAction(R.drawable.btn_close_white,
-                mContext.getResources().getString(R.string.download_notification_cancel_button),
+                ContextUtils.getApplicationContext().getResources().getString(
+                        R.string.download_notification_cancel_button),
                 buildPendingIntent(cancelIntent, notificationId));
         PendingIntent deleteIntent = isTransient ? buildPendingIntent(cancelIntent, notificationId)
                                                  : buildSummaryIconIntent(notificationId);
@@ -956,9 +965,11 @@
             boolean isOpenable, Bitmap icon, String originalUrl, String referrer) {
         int notificationId = getNotificationId(id);
         ChromeNotificationBuilder builder = buildNotification(R.drawable.offline_pin, fileName,
-                mContext.getResources().getString(R.string.download_notification_completed));
-        ComponentName component = new ComponentName(
-                mContext.getPackageName(), DownloadBroadcastReceiver.class.getName());
+                ContextUtils.getApplicationContext().getResources().getString(
+                        R.string.download_notification_completed));
+        ComponentName component =
+                new ComponentName(ContextUtils.getApplicationContext().getPackageName(),
+                        DownloadBroadcastReceiver.class.getName());
 
         if (isOpenable) {
             Intent intent = null;
@@ -975,16 +986,18 @@
                 MediaViewerUtils.setOriginalUrlAndReferralExtraToIntent(
                         intent, originalUrl, referrer);
             } else {
-                intent = buildActionIntent(mContext, ACTION_DOWNLOAD_OPEN, id, false);
+                intent = buildActionIntent(
+                        ContextUtils.getApplicationContext(), ACTION_DOWNLOAD_OPEN, id, false);
             }
 
             intent.setComponent(component);
-            builder.setContentIntent(PendingIntent.getBroadcast(
-                    mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+            builder.setContentIntent(
+                    PendingIntent.getBroadcast(ContextUtils.getApplicationContext(), notificationId,
+                            intent, PendingIntent.FLAG_UPDATE_CURRENT));
         }
         if (icon == null && mDownloadSuccessLargeIcon == null) {
-            Bitmap bitmap =
-                    BitmapFactory.decodeResource(mContext.getResources(), R.drawable.offline_pin);
+            Bitmap bitmap = BitmapFactory.decodeResource(
+                    ContextUtils.getApplicationContext().getResources(), R.drawable.offline_pin);
             mDownloadSuccessLargeIcon = getLargeNotificationIcon(bitmap);
         }
         builder.setDeleteIntent(buildSummaryIconIntent(notificationId));
@@ -1014,7 +1027,8 @@
         int notificationId = getNotificationId(id);
         ChromeNotificationBuilder builder =
                 buildNotification(android.R.drawable.stat_sys_download_done, fileName,
-                        mContext.getResources().getString(R.string.download_notification_failed));
+                        ContextUtils.getApplicationContext().getResources().getString(
+                                R.string.download_notification_failed));
         if (icon != null) builder.setLargeIcon(icon);
         builder.setDeleteIntent(buildSummaryIconIntent(notificationId));
         updateNotification(notificationId, builder.build(), id, null);
@@ -1027,12 +1041,13 @@
      * @param notificationId ID of the notification.
      */
     private PendingIntent buildPendingIntent(Intent intent, int notificationId) {
-        return PendingIntent.getBroadcast(
-                mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        return PendingIntent.getBroadcast(ContextUtils.getApplicationContext(), notificationId,
+                intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     private PendingIntent buildSummaryIconIntent(int notificationId) {
-        Intent intent = new Intent(mContext, DownloadBroadcastReceiver.class);
+        Intent intent =
+                new Intent(ContextUtils.getApplicationContext(), DownloadBroadcastReceiver.class);
         intent.setAction(ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON);
         return buildPendingIntent(intent, notificationId);
     }
@@ -1084,7 +1099,7 @@
     }
 
     private Bitmap getLargeNotificationIcon(Bitmap bitmap) {
-        Resources resources = mContext.getResources();
+        Resources resources = ContextUtils.getApplicationContext().getResources();
         int height = (int) resources.getDimension(android.R.dimen.notification_large_icon_height);
         int width = (int) resources.getDimension(android.R.dimen.notification_large_icon_width);
         final OvalShape circle = new OvalShape();
@@ -1128,7 +1143,7 @@
         // Process updating the summary notification first.  This has no impact on a specific
         // download.
         if (ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON.equals(intent.getAction())) {
-            updateSummaryIcon(mContext, mNotificationManager, -1, null);
+            updateSummaryIcon(ContextUtils.getApplicationContext(), mNotificationManager, -1, null);
             hideSummaryNotificationIfNecessary(-1);
             return;
         }
@@ -1161,7 +1176,8 @@
             // If user manually resumes a download, update the network type if it
             // is not metered previously.
             boolean canDownloadWhileMetered = entry.canDownloadWhileMetered
-                    || DownloadManagerService.isActiveNetworkMetered(mContext);
+                    || DownloadManagerService.isActiveNetworkMetered(
+                               ContextUtils.getApplicationContext());
             // Update the SharedPreference entry.
             mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
                     new DownloadSharedPreferenceEntry(entry.id, entry.notificationId,
@@ -1221,7 +1237,7 @@
                         OfflineContentAggregatorNotificationBridgeUiFactory.instance().openItem(id);
                     }
                 } else if (ACTION_NOTIFICATION_CLICKED.equals(intent.getAction())) {
-                    openDownload(mContext, intent);
+                    openDownload(ContextUtils.getApplicationContext(), intent);
                 } else {
                     Log.e(TAG, "Unrecognized intent action.", intent);
                 }
@@ -1235,8 +1251,10 @@
             }
         };
         try {
-            ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartup(parts);
-            ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStartup(true, parts);
+            ChromeBrowserInitializer.getInstance(ContextUtils.getApplicationContext())
+                    .handlePreNativeStartup(parts);
+            ChromeBrowserInitializer.getInstance(ContextUtils.getApplicationContext())
+                    .handlePostNativeStartup(true, parts);
         } catch (ProcessInitException e) {
             Log.e(TAG, "Unable to load native library.", e);
             ChromeApplication.reportStartupErrorAndExit(e);
@@ -1344,7 +1362,7 @@
         } else {
             mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
         }
-        updateSummaryIcon(mContext, mNotificationManager, -1,
+        updateSummaryIcon(ContextUtils.getApplicationContext(), mNotificationManager, -1,
                 new Pair<Integer, Notification>(notificationId, notification));
     }
 
@@ -1419,7 +1437,7 @@
         List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
         for (int i = 0; i < entries.size(); ++i) {
             DownloadSharedPreferenceEntry entry = entries.get(i);
-            if (!canResumeDownload(mContext, entry)) continue;
+            if (!canResumeDownload(ContextUtils.getApplicationContext(), entry)) continue;
             if (mDownloadsInProgress.contains(entry.id)) continue;
 
             notifyDownloadPending(entry.id, entry.fileName, entry.isOffTheRecord,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
index ac6ecb7..eecc1037 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
@@ -501,10 +501,8 @@
      * already in progress, do nothing.
      */
     void resumeAllPendingDownloads() {
-        Context context = ContextUtils.getApplicationContext();
-
         // Limit the number of auto resumption attempts in case Chrome falls into a vicious cycle.
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(context).cancel();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().cancel();
         int numAutoResumptionAtemptLeft = getResumptionAttemptLeft();
         if (numAutoResumptionAtemptLeft <= 0) return;
 
@@ -515,7 +513,7 @@
         List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
         for (int i = 0; i < entries.size(); ++i) {
             DownloadSharedPreferenceEntry entry = entries.get(i);
-            if (!canResumeDownload(context, entry)) continue;
+            if (!canResumeDownload(ContextUtils.getApplicationContext(), entry)) continue;
             if (mDownloadsInProgress.contains(entry.id)) continue;
             notifyDownloadPending(entry.id, entry.fileName, entry.isOffTheRecord,
                     entry.canDownloadWhileMetered, entry.isTransient, null, false,
@@ -701,8 +699,6 @@
 
     private void rescheduleDownloads() {
         if (getResumptionAttemptLeft() <= 0) return;
-        DownloadResumptionScheduler
-                .getDownloadResumptionScheduler(ContextUtils.getApplicationContext())
-                .scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java
index 5745da62..ee5e69f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java
@@ -27,7 +27,7 @@
     @Override
     protected void onStartTaskWithNative(
             Context context, TaskParameters taskParameters, final TaskFinishedCallback callback) {
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(context).resume();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().resume();
         new Handler().post(() -> callback.taskFinished(false));
     }
 
@@ -45,6 +45,6 @@
 
     @Override
     public void reschedule(Context context) {
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(context).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
index 6ee0721..51f5bb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
@@ -5,9 +5,9 @@
 package org.chromium.chrome.browser.download;
 
 import android.annotation.SuppressLint;
-import android.content.Context;
 import android.content.Intent;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
 import org.chromium.components.background_task_scheduler.TaskIds;
@@ -21,21 +21,17 @@
  * Class for scheduing download resumption tasks.
  */
 public class DownloadResumptionScheduler {
-    private final Context mContext;
     @SuppressLint("StaticFieldLeak")
     private static DownloadResumptionScheduler sDownloadResumptionScheduler;
 
-    public static DownloadResumptionScheduler getDownloadResumptionScheduler(Context context) {
-        assert context == context.getApplicationContext();
+    public static DownloadResumptionScheduler getDownloadResumptionScheduler() {
         if (sDownloadResumptionScheduler == null) {
-            sDownloadResumptionScheduler = new DownloadResumptionScheduler(context);
+            sDownloadResumptionScheduler = new DownloadResumptionScheduler();
         }
         return sDownloadResumptionScheduler;
     }
 
-    protected DownloadResumptionScheduler(Context context) {
-        mContext = context;
-    }
+    protected DownloadResumptionScheduler() {}
 
     /**
      * Checks the persistence layer and schedules a task to restart the app and resume any downloads
@@ -72,7 +68,8 @@
                                     .setIsPersisted(true)
                                     .build();
 
-            BackgroundTaskSchedulerFactory.getScheduler().schedule(mContext, task);
+            BackgroundTaskSchedulerFactory.getScheduler().schedule(
+                    ContextUtils.getApplicationContext(), task);
         } else {
             cancel();
         }
@@ -83,7 +80,7 @@
      */
     public void cancel() {
         BackgroundTaskSchedulerFactory.getScheduler().cancel(
-                mContext, TaskIds.DOWNLOAD_RESUMPTION_JOB_ID);
+                ContextUtils.getApplicationContext(), TaskIds.DOWNLOAD_RESUMPTION_JOB_ID);
     }
 
     /**
@@ -100,7 +97,8 @@
             // Start the DownloadNotificationService and allow that to manage the download life
             // cycle. Shut down the task right away after starting the service
             DownloadNotificationService.startDownloadNotificationService(
-                    mContext, new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL));
+                    ContextUtils.getApplicationContext(),
+                    new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL));
         }
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
index 81ae4a5..907c72a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
@@ -11,6 +11,7 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.download.items.OfflineContentAggregatorNotificationBridgeUiFactory;
@@ -27,7 +28,6 @@
     public static final int INVALID_NOTIFICATION_ID = -1;
     private static final int SNACKBAR_DURATION_MS = 7000;
     private static final int SNACKBAR_ACCESSIBILITY_DURATION_MS = 15000;
-    private final Context mContext;
 
     private static class ActionDataInfo {
         public final DownloadInfo downloadInfo;
@@ -44,14 +44,10 @@
         }
     }
 
-    public DownloadSnackbarController(Context context) {
-        mContext = context;
-    }
-
     @Override
     public void onAction(Object actionData) {
         if (!(actionData instanceof ActionDataInfo)) {
-            DownloadManagerService.openDownloadsPage(mContext);
+            DownloadManagerService.openDownloadsPage(ContextUtils.getApplicationContext());
             return;
         }
 
@@ -59,8 +55,9 @@
         final ActionDataInfo download = (ActionDataInfo) actionData;
         if (LegacyHelpers.isLegacyDownload(download.downloadInfo.getContentId())) {
             if (download.usesAndroidDownloadManager) {
-                mContext.startActivity(new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
-                                               .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+                ContextUtils.getApplicationContext().startActivity(
+                        new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
+                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
             } else {
                 manager.openDownloadedContent(download.downloadInfo, download.systemDownloadId,
                         DownloadMetrics.DownloadOpenSource.SNACK_BAR);
@@ -92,18 +89,20 @@
     public void onDownloadSucceeded(
             DownloadInfo downloadInfo, int notificationId, long downloadId, boolean canBeResolved,
             boolean usesAndroidDownloadManager) {
+        Context appContext = ContextUtils.getApplicationContext();
         if (FeatureUtilities.isDownloadProgressInfoBarEnabled()) return;
         if (getSnackbarManager() == null) return;
         Snackbar snackbar;
         if (getActivity() instanceof CustomTabActivity) {
             String packageLabel = BuildInfo.getInstance().hostPackageLabel;
-            snackbar = Snackbar.make(mContext.getString(R.string.download_succeeded_message,
-                    downloadInfo.getFileName(), packageLabel),
+            snackbar = Snackbar.make(appContext.getString(R.string.download_succeeded_message,
+                                             downloadInfo.getFileName(), packageLabel),
                     this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED);
         } else {
-            snackbar = Snackbar.make(mContext.getString(R.string.download_succeeded_message_default,
-                    downloadInfo.getFileName()),
-                    this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED);
+            snackbar =
+                    Snackbar.make(appContext.getString(R.string.download_succeeded_message_default,
+                                          downloadInfo.getFileName()),
+                            this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED);
         }
         // TODO(qinmin): Coalesce snackbars if multiple downloads finish at the same time.
         snackbar.setDuration(getSnackbarDurationMs()).setSingleLine(false);
@@ -114,8 +113,7 @@
                     usesAndroidDownloadManager);
         }
         // Show downloads app if the download cannot be resolved to any activity.
-        snackbar.setAction(
-                mContext.getString(R.string.open_downloaded_label), info);
+        snackbar.setAction(appContext.getString(R.string.open_downloaded_label), info);
         getSnackbarManager().showSnackbar(snackbar);
     }
 
@@ -136,7 +134,7 @@
                                     .setDuration(getSnackbarDurationMs());
         if (showAllDownloads) {
             snackbar.setAction(
-                    mContext.getString(R.string.open_downloaded_label),
+                    ContextUtils.getApplicationContext().getString(R.string.open_downloaded_label),
                     null);
         }
         getSnackbarManager().showSnackbar(snackbar);
@@ -149,12 +147,12 @@
     void onDownloadDirectoryNotFound() {
         if (getSnackbarManager() == null) return;
 
-        Snackbar snackbar =
-                Snackbar.make(mContext.getString(R.string.download_location_no_sd_card_snackbar),
-                                this, Snackbar.TYPE_NOTIFICATION,
-                                Snackbar.UMA_MISSING_FILES_NO_SD_CARD)
-                        .setSingleLine(false)
-                        .setDuration(getSnackbarDurationMs());
+        Snackbar snackbar = Snackbar.make(ContextUtils.getApplicationContext().getString(
+                                                  R.string.download_location_no_sd_card_snackbar),
+                                            this, Snackbar.TYPE_NOTIFICATION,
+                                            Snackbar.UMA_MISSING_FILES_NO_SD_CARD)
+                                    .setSingleLine(false)
+                                    .setDuration(getSnackbarDurationMs());
         getSnackbarManager().showSnackbar(snackbar);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
index 896f446..8ac539c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -11,6 +11,7 @@
 import android.os.IBinder;
 import android.support.annotation.IntDef;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
@@ -52,8 +53,6 @@
         int REMOVE_NOTIFICATION = 7;
     }
 
-    private final Context mApplicationContext;
-
     @Nullable
     private DownloadNotificationService mBoundService;
     private Set<String> mActiveDownloads = new HashSet<String>();
@@ -83,14 +82,6 @@
     }
 
     /**
-     * Constructor.
-     * @param context Application context.
-     */
-    public SystemDownloadNotifier(Context context) {
-        mApplicationContext = context.getApplicationContext();
-    }
-
-    /**
      * Object to receive information as the service is started and stopped.
      */
     private final ServiceConnection mConnection = new ServiceConnection() {
@@ -161,15 +152,16 @@
 
     @VisibleForTesting
     void startAndBindService() {
-        DownloadNotificationService.startDownloadNotificationService(mApplicationContext, null);
-        mApplicationContext.bindService(
-                new Intent(mApplicationContext, DownloadNotificationService.class), mConnection,
+        Context applicationContext = ContextUtils.getApplicationContext();
+        DownloadNotificationService.startDownloadNotificationService(applicationContext, null);
+        applicationContext.bindService(
+                new Intent(applicationContext, DownloadNotificationService.class), mConnection,
                 Context.BIND_AUTO_CREATE);
     }
 
     @VisibleForTesting
     void unbindService() {
-        mApplicationContext.unbindService(mConnection);
+        ContextUtils.getApplicationContext().unbindService(mConnection);
     }
 
     @Override
@@ -238,9 +230,11 @@
 
     @Override
     public void resumePendingDownloads() {
-        if (!DownloadNotificationService.isTrackingResumableDownloads(mApplicationContext)) return;
-        updateDownloadNotification(
-                new PendingNotificationInfo(DownloadNotificationType.RESUME_ALL, null), true);
+        if (DownloadNotificationService.isTrackingResumableDownloads(
+                    ContextUtils.getApplicationContext())) {
+            updateDownloadNotification(
+                    new PendingNotificationInfo(DownloadNotificationType.RESUME_ALL, null), true);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
index 8c6172d..d2abfd7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
@@ -4,8 +4,7 @@
 
 package org.chromium.chrome.browser.download;
 
-import android.content.Context;
-
+import org.chromium.base.ContextUtils;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.PendingState;
@@ -16,15 +15,13 @@
  * to the latter to issue calls to show and update notifications.
  */
 public class SystemDownloadNotifier2 implements DownloadNotifier {
-    private final Context mApplicationContext;
     private final DownloadNotificationService2 mDownloadNotificationService;
 
     /**
      * Constructor.
      * @param context Application context.
      */
-    public SystemDownloadNotifier2(Context context) {
-        mApplicationContext = context.getApplicationContext();
+    public SystemDownloadNotifier2() {
         mDownloadNotificationService = DownloadNotificationService2.getInstance();
     }
 
@@ -84,7 +81,9 @@
 
     @Override
     public void resumePendingDownloads() {
-        if (!DownloadNotificationService2.isTrackingResumableDownloads(mApplicationContext)) return;
-        mDownloadNotificationService.resumeAllPendingDownloads();
+        if (DownloadNotificationService2.isTrackingResumableDownloads(
+                    ContextUtils.getApplicationContext())) {
+            mDownloadNotificationService.resumeAllPendingDownloads();
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index f81ebba..fdd193f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -210,7 +210,7 @@
                     ContextUtils.getAppSharedPreferences();
                     DocumentTabModelImpl.warmUpSharedPrefs(mApplication);
                     ActivityAssigner.warmUpSharedPrefs(mApplication);
-                    DownloadManagerService.warmUpSharedPrefs(mApplication);
+                    DownloadManagerService.warmUpSharedPrefs();
                     return null;
                 }
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -218,7 +218,7 @@
             ContextUtils.getAppSharedPreferences();
             DocumentTabModelImpl.warmUpSharedPrefs(mApplication);
             ActivityAssigner.warmUpSharedPrefs(mApplication);
-            DownloadManagerService.warmUpSharedPrefs(mApplication);
+            DownloadManagerService.warmUpSharedPrefs();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
index f0d9f7d2..5698a8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.invalidation;
 
 import android.accounts.Account;
-import android.app.Application;
 import android.content.AbstractThreadedSyncAdapter;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -34,11 +33,8 @@
 public class ChromeBrowserSyncAdapter extends AbstractThreadedSyncAdapter {
     private static final String TAG = "invalidation";
 
-    private final Application mApplication;
-
-    public ChromeBrowserSyncAdapter(Context context, Application application) {
+    public ChromeBrowserSyncAdapter(Context context) {
         super(context, false);
-        mApplication = application;
     }
 
     @Override
@@ -57,7 +53,7 @@
 
         DelayedInvalidationsController controller = DelayedInvalidationsController.getInstance();
         if (!controller.shouldNotifyInvalidation(extras)) {
-            controller.addPendingInvalidation(getContext(), account.name, invalidation);
+            controller.addPendingInvalidation(account.name, invalidation);
             return;
         }
 
@@ -65,8 +61,7 @@
         Semaphore semaphore = new Semaphore(0);
 
         // Configure the BrowserParts with all the data it needs.
-        BrowserParts parts =
-                getBrowserParts(mApplication, account.name, invalidation, syncResult, semaphore);
+        BrowserParts parts = getBrowserParts(account.name, invalidation, syncResult, semaphore);
         startBrowserProcess(parts, syncResult, semaphore);
 
         try {
@@ -109,9 +104,9 @@
         }
     }
 
-    private BrowserParts getBrowserParts(final Context context,
-            final String account, final PendingInvalidation invalidation,
-            final SyncResult syncResult, final Semaphore semaphore) {
+    private BrowserParts getBrowserParts(final String account,
+            final PendingInvalidation invalidation, final SyncResult syncResult,
+            final Semaphore semaphore) {
         return new EmptyBrowserParts() {
             @Override
             public void finishNativeInitialization() {
@@ -125,7 +120,7 @@
             public void onStartupFailure() {
                 // The startup failed, so we defer the invalidation.
                 DelayedInvalidationsController.getInstance().addPendingInvalidation(
-                        context, account, invalidation);
+                        account, invalidation);
                 // Using numIoExceptions so Android will treat this as a soft error.
                 syncResult.stats.numIoExceptions++;
                 semaphore.release();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
index 76149cb..69c0263 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
@@ -10,6 +10,7 @@
 import android.content.Intent;
 import android.os.IBinder;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
 
 /**
@@ -28,7 +29,7 @@
         synchronized (LOCK) {
             if (sSyncAdapter == null) {
                 ProcessInitializationHandler.getInstance().initializePreNative();
-                sSyncAdapter = new ChromeBrowserSyncAdapter(applicationContext, getApplication());
+                sSyncAdapter = new ChromeBrowserSyncAdapter(applicationContext);
             }
         }
         return sSyncAdapter;
@@ -36,6 +37,6 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        return getOrCreateSyncAdapter(getApplicationContext()).getSyncAdapterBinder();
+        return getOrCreateSyncAdapter(ContextUtils.getApplicationContext()).getSyncAdapterBinder();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java
index f246903..546c582 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java
@@ -6,7 +6,6 @@
 
 import android.accounts.Account;
 import android.content.ContentResolver;
-import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.support.v4.util.ObjectsCompat;
@@ -53,7 +52,7 @@
      * Notify any invalidations that were delayed while Chromium was backgrounded.
      * @return whether there were any invalidations pending to be notified.
      */
-    public boolean notifyPendingInvalidations(final Context context) {
+    public boolean notifyPendingInvalidations() {
         SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         String accountName = prefs.getString(DELAYED_ACCOUNT_NAME, null);
         if (accountName == null) {
@@ -62,8 +61,8 @@
         } else {
             Log.d(TAG, "Handling pending invalidations.");
             Account account = AccountManagerFacade.createAccountFromName(accountName);
-            List<Bundle> bundles = popPendingInvalidations(context);
-            notifyInvalidationsOnBackgroundThread(context, account, bundles);
+            List<Bundle> bundles = popPendingInvalidations();
+            notifyInvalidationsOnBackgroundThread(account, bundles);
             return true;
         }
     }
@@ -73,8 +72,7 @@
      * IO operations.
      */
     @VisibleForTesting
-    void notifyInvalidationsOnBackgroundThread(
-            final Context context, final Account account, final List<Bundle> bundles) {
+    void notifyInvalidationsOnBackgroundThread(final Account account, final List<Bundle> bundles) {
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... unused) {
@@ -91,7 +89,7 @@
      * Stores preferences to indicate that an invalidation has arrived, but dropped on the floor.
      */
     @VisibleForTesting
-    void addPendingInvalidation(Context context, String account, PendingInvalidation invalidation) {
+    void addPendingInvalidation(String account, PendingInvalidation invalidation) {
         SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         String oldAccount = prefs.getString(DELAYED_ACCOUNT_NAME, null);
         // Make sure to construct a new set so it can be modified safely. See crbug.com/568369.
@@ -144,11 +142,11 @@
         return true;
     }
 
-    private List<Bundle> popPendingInvalidations(final Context context) {
+    private List<Bundle> popPendingInvalidations() {
         SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         assert prefs.contains(DELAYED_ACCOUNT_NAME);
         Set<String> savedInvalidations = prefs.getStringSet(DELAYED_INVALIDATIONS, null);
-        clearPendingInvalidations(context);
+        clearPendingInvalidations();
         // Absence of specific invalidations indicates invalidate all types.
         if (savedInvalidations == null) return Arrays.asList(new Bundle());
 
@@ -168,7 +166,7 @@
      * If there are any pending invalidations, they will be cleared.
      */
     @VisibleForTesting
-    public void clearPendingInvalidations(Context context) {
+    public void clearPendingInvalidations() {
         SharedPreferences.Editor editor =
                 ContextUtils.getAppSharedPreferences().edit();
         editor.putString(DELAYED_ACCOUNT_NAME, null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
index bcb574c..5093deca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.invalidation;
 
 import android.annotation.SuppressLint;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Handler;
@@ -16,6 +15,7 @@
 import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.AsyncTask;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -132,8 +132,6 @@
     @SuppressLint("StaticFieldLeak")
     private static InvalidationController sInstance;
 
-    private final Context mContext;
-
     /**
      * Whether session sync invalidations can be disabled.
      */
@@ -191,8 +189,8 @@
 
         Intent registerIntent = InvalidationIntentProtocol.createRegisterIntent(
                 ChromeSigninController.get().getSignedInUser(), typesToRegister);
-        registerIntent.setClass(
-                mContext, InvalidationClientService.getRegisteredClass());
+        registerIntent.setClass(ContextUtils.getApplicationContext(),
+                InvalidationClientService.getRegisteredClass());
         startServiceIfPossible(registerIntent);
     }
 
@@ -206,7 +204,8 @@
             @Override
             protected Void doInBackground(Void... arg0) {
                 boolean useGcmUpstream = true;
-                AndroidGcmController.get(mContext).initializeGcm(useGcmUpstream);
+                AndroidGcmController.get(ContextUtils.getApplicationContext())
+                        .initializeGcm(useGcmUpstream);
                 return null;
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -223,8 +222,8 @@
     private void start() {
         mStarted = true;
         mEnableSessionInvalidationsTimer.resume();
-        Intent intent = new Intent(
-                mContext, InvalidationClientService.getRegisteredClass());
+        Intent intent = new Intent(ContextUtils.getApplicationContext(),
+                InvalidationClientService.getRegisteredClass());
         startServiceIfPossible(intent);
     }
 
@@ -234,8 +233,8 @@
     public void stop() {
         mStarted = false;
         mEnableSessionInvalidationsTimer.pause();
-        Intent intent = new Intent(
-                mContext, InvalidationClientService.getRegisteredClass());
+        Intent intent = new Intent(ContextUtils.getApplicationContext(),
+                InvalidationClientService.getRegisteredClass());
         intent.putExtra(InvalidationIntentProtocol.EXTRA_STOP, true);
         startServiceIfPossible(intent);
     }
@@ -245,12 +244,12 @@
         // for O. See crbug.com/680812.
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             try {
-                mContext.startService(intent);
+                ContextUtils.getApplicationContext().startService(intent);
             } catch (IllegalStateException exception) {
                 Log.e(TAG, "Failed to start service from exception: ", exception);
             }
         } else {
-            mContext.startService(intent);
+            ContextUtils.getApplicationContext().startService(intent);
         }
     }
 
@@ -291,15 +290,14 @@
      *
      * Calling this method will create the instance if it does not yet exist.
      */
-    public static InvalidationController get(Context context) {
+    public static InvalidationController get() {
         synchronized (LOCK) {
             if (sInstance == null) {
                 // If the NTP is trying to suggest foreign tabs, then recieving invalidations is
                 // vital, otherwise data is stale and less useful.
                 boolean requireInvalidationsForSuggestions = ChromeFeatureList.isEnabled(
                         ChromeFeatureList.NTP_FOREIGN_SESSIONS_SUGGESTIONS);
-                sInstance =
-                        new InvalidationController(context, !requireInvalidationsForSuggestions);
+                sInstance = new InvalidationController(!requireInvalidationsForSuggestions);
             }
             return sInstance;
         }
@@ -331,10 +329,9 @@
      * Creates an instance using {@code context} to send intents.
      */
     @VisibleForTesting
-    InvalidationController(Context context, boolean canDisableSessionInvalidations) {
-        Context appContext = context.getApplicationContext();
-        if (appContext == null) throw new NullPointerException("Unable to get application context");
-        mContext = appContext;
+    InvalidationController(boolean canDisableSessionInvalidations) {
+        if (ContextUtils.getApplicationContext() == null)
+            throw new NullPointerException("Unable to get application context");
         mCanDisableSessionInvalidations = canDisableSessionInvalidations;
         mSessionInvalidationsEnabled = !mCanDisableSessionInvalidations;
         mEnableSessionInvalidationsTimer = new Timer();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
index 165dbd9..a1b524e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
@@ -117,7 +117,7 @@
         mForeignSessionHelper.triggerSessionSync();
         registerObservers();
 
-        InvalidationController.get(mContext).onRecentTabsPageOpened();
+        InvalidationController.get().onRecentTabsPageOpened();
     }
 
     /**
@@ -147,7 +147,7 @@
         mPrefs.destroy();
         mPrefs = null;
 
-        InvalidationController.get(mContext).onRecentTabsPageClosed();
+        InvalidationController.get().onRecentTabsPageClosed();
     }
 
     private void registerForForeignSessionUpdates() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
index 1d16d18..34acde3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
@@ -490,7 +490,7 @@
         boolean syncEverything = mUseSyncAndAllServices.isChecked();
         mProfileSyncService.setPreferredDataTypes(syncEverything, getSelectedModelTypes());
         // Update the invalidation listener with the set of types we are enabling.
-        InvalidationController invController = InvalidationController.get(getActivity());
+        InvalidationController invController = InvalidationController.get();
         invController.ensureStartedAndUpdateRegisteredTypes();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
index ce96d03..fa83255 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -174,7 +174,7 @@
     @Override
     public void syncStateChanged() {
         ThreadUtils.assertOnUiThread();
-        InvalidationController invalidationController = InvalidationController.get(mContext);
+        InvalidationController invalidationController = InvalidationController.get();
         if (mProfileSyncService.isSyncRequested()) {
             if (!invalidationController.isStarted()) {
                 invalidationController.ensureStartedAndUpdateRegisteredTypes();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
index 1127f8c..7f98a81 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
@@ -365,7 +365,7 @@
         boolean syncEverything = mSyncEverything.isChecked();
         mProfileSyncService.setPreferredDataTypes(syncEverything, getSelectedModelTypes());
         // Update the invalidation listener with the set of types we are enabling.
-        InvalidationController invController = InvalidationController.get(getActivity());
+        InvalidationController invController = InvalidationController.get();
         invController.ensureStartedAndUpdateRegisteredTypes();
     }
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 2845e93b..c1b8c0e 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -488,7 +488,7 @@
         Never saved
       </message>
       <message name="IDS_MANAGE_PASSWORDS_TEXT" desc="Text for link to manage passwords on Account Central.">
-        View and manage saved passwords at <ph name="BEGIN_LINK">&lt;link&gt;</ph>passwords.google.com<ph name="END_LINK">&lt;/link&gt;</ph>
+        View and manage saved passwords in your <ph name="BEGIN_LINK">&lt;link&gt;</ph>Google Account<ph name="END_LINK">&lt;/link&gt;</ph>
       </message>
       <message name="IDS_SAVED_PASSWORDS_NONE_TEXT" desc="Text when there are no saved passwords/exceptions.">
         Saved passwords will appear here.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
index 4f76bf0c..3e68335 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.util.Log;
@@ -23,7 +22,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
@@ -78,11 +76,15 @@
         private final Queue<Pair<MethodID, Object>> mExpectedCalls =
                 new ConcurrentLinkedQueue<Pair<MethodID, Object>>();
 
-        public MockDownloadNotifier(Context context) {
-            super(context);
+        public MockDownloadNotifier() {
             expect(MethodID.CLEAR_PENDING_DOWNLOADS, null);
         }
 
+        /** @deprecated Use constructor with no arguments instead. */
+        public MockDownloadNotifier(Context context) {
+            this();
+        }
+
         public MockDownloadNotifier expect(MethodID method, Object param) {
             mExpectedCalls.clear();
             mExpectedCalls.add(getMethodSignature(method, param));
@@ -169,10 +171,6 @@
         private boolean mSucceeded;
         private boolean mFailed;
 
-        public MockDownloadSnackbarController() {
-            super(null);
-        }
-
         public void waitForSnackbarControllerToFinish(final boolean success) {
             CriteriaHelper.pollInstrumentationThread(
                     new Criteria("Failed while waiting for all calls to complete.") {
@@ -244,9 +242,9 @@
         boolean mResumed;
         DownloadSnackbarController mDownloadSnackbarController;
 
-        public DownloadManagerServiceForTest(Context context, MockDownloadNotifier mockNotifier,
-                long updateDelayInMillis) {
-            super(context, mockNotifier, getTestHandler(), updateDelayInMillis);
+        public DownloadManagerServiceForTest(
+                MockDownloadNotifier mockNotifier, long updateDelayInMillis) {
+            super(mockNotifier, getTestHandler(), updateDelayInMillis);
         }
 
         @Override
@@ -308,16 +306,11 @@
                 .build();
     }
 
-    private Context getTestContext() {
-        return new AdvancedMockContext(InstrumentationRegistry.getTargetContext());
-    }
-
     private void createDownloadManagerService(MockDownloadNotifier notifier, int delayForTest) {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mService =
-                        new DownloadManagerServiceForTest(getTestContext(), notifier, delayForTest);
+                mService = new DownloadManagerServiceForTest(notifier, delayForTest);
             }
         });
     }
@@ -327,7 +320,7 @@
     @Feature({"Download"})
     @RetryOnFailure
     public void testAllDownloadProgressIsCalledForSlowUpdates() throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
         DownloadInfo downloadInfo = getDownloadInfo();
 
@@ -364,7 +357,7 @@
     @MediumTest
     @Feature({"Download"})
     public void testOnlyTwoProgressForFastUpdates() throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         createDownloadManagerService(notifier, LONG_UPDATE_DELAY_FOR_TEST);
         DownloadInfo downloadInfo = getDownloadInfo();
         DownloadInfo update1 =
@@ -398,7 +391,7 @@
     @Feature({"Download"})
     @RetryOnFailure
     public void testDownloadCompletedIsCalled() throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         MockDownloadSnackbarController snackbarController = new MockDownloadSnackbarController();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
         ThreadUtils.runOnUiThreadBlocking(
@@ -427,7 +420,7 @@
     @MediumTest
     @Feature({"Download"})
     public void testDownloadFailedIsCalled() throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         MockDownloadSnackbarController snackbarController = new MockDownloadSnackbarController();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
         ThreadUtils.runOnUiThreadBlocking(
@@ -447,7 +440,7 @@
     @MediumTest
     @Feature({"Download"})
     public void testDownloadPausedIsCalled() throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
         DownloadManagerService.disableNetworkListenerForTest();
         DownloadInfo interrupted =
@@ -462,7 +455,7 @@
     @Feature({"Download"})
     @RetryOnFailure
     public void testMultipleDownloadProgress() {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
 
         DownloadInfo download1 = getDownloadInfo();
@@ -485,7 +478,7 @@
     @Feature({"Download"})
     @RetryOnFailure
     public void testInterruptedDownloadAreAutoResumed() throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
         DownloadManagerService.disableNetworkListenerForTest();
         DownloadInfo interrupted =
@@ -513,7 +506,7 @@
     @DisabledTest // crbug.com/789931
     public void testInterruptedUnmeteredDownloadCannotAutoResumeOnMeteredNetwork()
             throws InterruptedException {
-        MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
+        MockDownloadNotifier notifier = new MockDownloadNotifier();
         createDownloadManagerService(notifier, UPDATE_DELAY_FOR_TEST);
         DownloadManagerService.disableNetworkListenerForTest();
         DownloadInfo interrupted =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
index 2ef756a..2072176 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -49,8 +49,8 @@
     private static class MockDownloadManagerService extends DownloadManagerService {
         final List<DownloadItem> mDownloads = new ArrayList<DownloadItem>();
 
-        public MockDownloadManagerService(Context context) {
-            super(context, null, getTestHandler(), 1000);
+        public MockDownloadManagerService() {
+            super(null, getTestHandler(), 1000);
         }
 
         @Override
@@ -408,8 +408,7 @@
         DownloadNotificationService service = bindNotificationService();
         DownloadManagerService.disableNetworkListenerForTest();
 
-        final MockDownloadManagerService manager = new MockDownloadManagerService(
-                InstrumentationRegistry.getTargetContext().getApplicationContext());
+        final MockDownloadManagerService manager = new MockDownloadManagerService();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
index fbba0c7..8e0e923 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
@@ -9,7 +9,6 @@
 import android.database.Cursor;
 import android.os.Environment;
 import android.os.Handler;
-import android.support.test.InstrumentationRegistry;
 import android.text.TextUtils;
 
 import org.junit.Assert;
@@ -182,9 +181,9 @@
     }
 
     private class TestDownloadManagerService extends DownloadManagerService {
-        public TestDownloadManagerService(Context context, DownloadNotifier downloadNotifier,
-                Handler handler, long updateDelayInMillis) {
-            super(context, downloadNotifier, handler, updateDelayInMillis);
+        public TestDownloadManagerService(
+                DownloadNotifier downloadNotifier, Handler handler, long updateDelayInMillis) {
+            super(downloadNotifier, handler, updateDelayInMillis);
         }
 
         @Override
@@ -217,12 +216,10 @@
 
         cleanUpAllDownloads();
 
-        final Context context = InstrumentationRegistry.getTargetContext().getApplicationContext();
-
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            mSavedDownloadManagerService = DownloadManagerService.setDownloadManagerService(
-                    new TestDownloadManagerService(context, new SystemDownloadNotifier(context),
-                            new Handler(), UPDATE_DELAY_MILLIS));
+            mSavedDownloadManagerService =
+                    DownloadManagerService.setDownloadManagerService(new TestDownloadManagerService(
+                            new SystemDownloadNotifier(), new Handler(), UPDATE_DELAY_MILLIS));
             DownloadController.setDownloadNotificationService(
                     DownloadManagerService.getDownloadManagerService());
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java
index 59778ae..e0bc64d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java
@@ -60,10 +60,6 @@
         public boolean mSucceeded;
         public boolean mFailed;
 
-        public MockDownloadSnackbarController() {
-            super(null);
-        }
-
         public void waitForSnackbarControllerToFinish(final boolean success) {
             CriteriaHelper.pollInstrumentationThread(
                     new Criteria("Failed while waiting for all calls to complete.") {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OWNERS
index 93422c9..83f5f5c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OWNERS
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OWNERS
@@ -1,5 +1,4 @@
 qinmin@chromium.org
-jming@chromium.org
 dtrainor@chromium.org
 
 per-file ChromeHomeDownloadManagerTest.java=twellington@chromium.org
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
index ea2bb92a..fe66eadd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
@@ -6,7 +6,6 @@
 
 import android.accounts.Account;
 import android.app.Activity;
-import android.app.Application;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -62,8 +61,8 @@
         private long mVersion;
         private String mPayload;
 
-        public TestSyncAdapter(Context context, Application application) {
-            super(context, application);
+        public TestSyncAdapter(Context context) {
+            super(context);
         }
 
         @Override
@@ -84,8 +83,7 @@
     @Before
     public void setUp() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
-        mSyncAdapter = new TestSyncAdapter(InstrumentationRegistry.getTargetContext(),
-                mActivityTestRule.getActivity().getApplication());
+        mSyncAdapter = new TestSyncAdapter(InstrumentationRegistry.getTargetContext());
     }
 
     private void performSyncWithBundle(Bundle bundle) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java
index 192c644..3d169a2a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java
@@ -7,9 +7,7 @@
 import android.accounts.Account;
 import android.app.Activity;
 import android.content.ContentResolver;
-import android.content.Context;
 import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.UiThreadTestRule;
@@ -46,7 +44,6 @@
     private static final String PAYLOAD_2 = "payload_2";
 
     private MockDelayedInvalidationsController mController;
-    private Context mContext;
     private Activity mPlaceholderActivity;
 
     @Rule
@@ -63,8 +60,7 @@
         private MockDelayedInvalidationsController() {}
 
         @Override
-        void notifyInvalidationsOnBackgroundThread(
-                Context context, Account account, List<Bundle> bundles) {
+        void notifyInvalidationsOnBackgroundThread(Account account, List<Bundle> bundles) {
             mInvalidated = true;
             mBundles = bundles;
         }
@@ -73,7 +69,6 @@
     @Before
     public void setUp() throws Exception {
         mController = new MockDelayedInvalidationsController();
-        mContext = InstrumentationRegistry.getTargetContext();
 
         mPlaceholderActivity = new Activity();
         setApplicationState(ActivityState.CREATED);
@@ -124,8 +119,8 @@
     @UiThreadTest
     public void testOnlySpecificInvalidationsTriggeredOnResume() throws InterruptedException {
         // First make sure there are no pending invalidations.
-        mController.clearPendingInvalidations(mContext);
-        Assert.assertFalse(mController.notifyPendingInvalidations(mContext));
+        mController.clearPendingInvalidations();
+        Assert.assertFalse(mController.notifyPendingInvalidations());
         Assert.assertFalse(mController.mInvalidated);
 
         // Create some invalidations.
@@ -139,11 +134,11 @@
         Assert.assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
 
         // Add multiple pending invalidations.
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, firstInv);
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, secondInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, firstInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, secondInv);
 
         // Make sure there are pending invalidations.
-        Assert.assertTrue(mController.notifyPendingInvalidations(mContext));
+        Assert.assertTrue(mController.notifyPendingInvalidations());
         Assert.assertTrue(mController.mInvalidated);
 
         // Ensure only specific invalidations are being notified.
@@ -160,8 +155,8 @@
     @UiThreadTest
     public void testAllInvalidationsTriggeredOnResume() throws InterruptedException {
         // First make sure there are no pending invalidations.
-        mController.clearPendingInvalidations(mContext);
-        Assert.assertFalse(mController.notifyPendingInvalidations(mContext));
+        mController.clearPendingInvalidations();
+        Assert.assertFalse(mController.notifyPendingInvalidations());
         Assert.assertFalse(mController.mInvalidated);
 
         // Create some invalidations.
@@ -177,12 +172,12 @@
         Assert.assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
 
         // Add multiple pending invalidations.
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, firstInv);
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, allInvalidations);
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, secondInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, firstInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, allInvalidations);
+        mController.addPendingInvalidation(TEST_ACCOUNT, secondInv);
 
         // Make sure there are pending invalidations.
-        Assert.assertTrue(mController.notifyPendingInvalidations(mContext));
+        Assert.assertTrue(mController.notifyPendingInvalidations());
         Assert.assertTrue(mController.mInvalidated);
 
         // As Invalidation for all ids has been received, it will supersede all other invalidations.
@@ -196,8 +191,8 @@
     @UiThreadTest
     public void testSameObjectInvalidationsGetCombined() throws InterruptedException {
         // First make sure there are no pending invalidations.
-        mController.clearPendingInvalidations(mContext);
-        Assert.assertFalse(mController.notifyPendingInvalidations(mContext));
+        mController.clearPendingInvalidations();
+        Assert.assertFalse(mController.notifyPendingInvalidations());
         Assert.assertFalse(mController.mInvalidated);
 
         // Create invalidations with the same id/src, but different versions and payloads.
@@ -211,11 +206,11 @@
         Assert.assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
 
         // Add multiple pending invalidations.
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, lowerVersionInv);
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, higherVersionInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, lowerVersionInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, higherVersionInv);
 
         // Make sure there are pending invalidations.
-        Assert.assertTrue(mController.notifyPendingInvalidations(mContext));
+        Assert.assertTrue(mController.notifyPendingInvalidations());
         Assert.assertTrue(mController.mInvalidated);
 
         // As Invalidation for all ids has been received, it will supersede all other invalidations.
@@ -229,8 +224,8 @@
     @UiThreadTest
     public void testSameObjectLowerVersionInvalidationGetsDiscarded() throws InterruptedException {
         // First make sure there are no pending invalidations.
-        mController.clearPendingInvalidations(mContext);
-        Assert.assertFalse(mController.notifyPendingInvalidations(mContext));
+        mController.clearPendingInvalidations();
+        Assert.assertFalse(mController.notifyPendingInvalidations());
         Assert.assertFalse(mController.mInvalidated);
 
         // Create invalidations with the same id/src, but different versions and payloads.
@@ -244,11 +239,11 @@
         Assert.assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
 
         // Add multiple pending invalidations.
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, higherVersionInv);
-        mController.addPendingInvalidation(mContext, TEST_ACCOUNT, lowerVersionInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, higherVersionInv);
+        mController.addPendingInvalidation(TEST_ACCOUNT, lowerVersionInv);
 
         // Make sure there are pending invalidations.
-        Assert.assertTrue(mController.notifyPendingInvalidations(mContext));
+        Assert.assertTrue(mController.notifyPendingInvalidations());
         Assert.assertTrue(mController.mInvalidated);
 
         // As Invalidation for all ids has been received, it will supersede all other invalidations.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
index 22710e0e47..2dd1876 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
@@ -125,9 +125,9 @@
     }
 
     private void checkThatShowNotificationIsDenied() throws Exception {
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "showNotification('MyNotification', {})");
+        showNotification("MyNotification", "{}");
         waitForTitle("TypeError: No notification permission has been granted for this origin.");
+
         // Ideally we'd wait a little here, but it's hard to wait for things that shouldn't happen.
         Assert.assertTrue(mNotificationTestRule.getNotificationEntries().isEmpty());
     }
@@ -158,14 +158,12 @@
     @DisabledTest
     public void testPermissionDenied() throws Exception {
         // Notifications permission should initially be prompt, and showing should fail.
-        Assert.assertEquals("\"default\"",
-                mNotificationTestRule.runJavaScriptCodeInCurrentTab("Notification.permission"));
+        Assert.assertEquals("\"default\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
         // Notification.requestPermission() should show the notifications infobar.
         Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "Notification.requestPermission(sendToTest)");
+        runJavaScript("Notification.requestPermission(sendToTest)");
         InfoBar infoBar = getInfobarBlocking();
 
         // Dismissing the infobar should pass prompt to the requestPermission callback.
@@ -174,13 +172,11 @@
         waitForTitle("default"); // See https://crbug.com/434547.
 
         // Notifications permission should still be prompt.
-        Assert.assertEquals("\"default\"",
-                mNotificationTestRule.runJavaScriptCodeInCurrentTab("Notification.permission"));
+        Assert.assertEquals("\"default\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
         // Notification.requestPermission() should show the notifications infobar again.
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "Notification.requestPermission(sendToTest)");
+        runJavaScript("Notification.requestPermission(sendToTest)");
         infoBar = getInfobarBlocking();
 
         // Denying the infobar should pass denied to the requestPermission callback.
@@ -189,8 +185,7 @@
         waitForTitle("denied");
 
         // This should have caused notifications permission to become denied.
-        Assert.assertEquals("\"denied\"",
-                mNotificationTestRule.runJavaScriptCodeInCurrentTab("Notification.permission"));
+        Assert.assertEquals("\"denied\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
         // Reload page to ensure the block is persisted.
@@ -199,14 +194,12 @@
 
         // Notification.requestPermission() should immediately pass denied to the callback without
         // showing an infobar.
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "Notification.requestPermission(sendToTest)");
+        runJavaScript("Notification.requestPermission(sendToTest)");
         waitForTitle("denied");
         Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
 
         // Notifications permission should still be denied.
-        Assert.assertEquals("\"denied\"",
-                mNotificationTestRule.runJavaScriptCodeInCurrentTab("Notification.permission"));
+        Assert.assertEquals("\"denied\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
     }
 
@@ -220,14 +213,12 @@
     @DisabledTest
     public void testPermissionGranted() throws Exception {
         // Notifications permission should initially be prompt, and showing should fail.
-        Assert.assertEquals("\"default\"",
-                mNotificationTestRule.runJavaScriptCodeInCurrentTab("Notification.permission"));
+        Assert.assertEquals("\"default\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
         // Notification.requestPermission() should show the notifications infobar.
         Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "Notification.requestPermission(sendToTest)");
+        runJavaScript("Notification.requestPermission(sendToTest)");
         InfoBar infoBar = getInfobarBlocking();
 
         // Accepting the infobar should pass granted to the requestPermission callback.
@@ -240,9 +231,8 @@
                 mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE));
 
         // Notifications permission should now be granted, and showing should succeed.
-        Assert.assertEquals("\"granted\"",
-                mNotificationTestRule.runJavaScriptCodeInCurrentTab("Notification.permission"));
-        mNotificationTestRule.showAndGetNotification("MyNotification", "{}");
+        Assert.assertEquals("\"granted\"", runJavaScript("Notification.permission"));
+        showAndGetNotification("MyNotification", "{}");
     }
 
     /**
@@ -258,8 +248,8 @@
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
         Context context = InstrumentationRegistry.getTargetContext();
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("MyNotification", "{ body: 'Hello' }");
+        Notification notification = showAndGetNotification("MyNotification", "{body: 'Hello'}");
+
         String expectedOrigin = UrlFormatter.formatUrlForSecurityDisplayOmitScheme(
                 mEmbeddedTestServerRule.getOrigin());
 
@@ -321,7 +311,7 @@
         mNotificationTestRule.setNotificationContentSettingForOrigin(
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
 
-        Notification notification = mNotificationTestRule.showAndGetNotification("MyNotification",
+        Notification notification = showAndGetNotification("MyNotification",
                 "{ "
                         + " actions: [{action: 'myAction', title: 'reply', type: 'text',"
                         + " placeholder: 'hi' }]}");
@@ -357,7 +347,8 @@
 
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
-        Notification notification = mNotificationTestRule.showAndGetNotification("MyNotification",
+        runJavaScript("SetupReplyForwardingForTests();");
+        Notification notification = showAndGetNotification("MyNotification",
                 "{ "
                         + " actions: [{action: 'myAction', title: 'reply', type: 'text'}],"
                         + " data: 'ACTION_REPLY'}");
@@ -402,7 +393,8 @@
 
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
-        Notification notification = mNotificationTestRule.showAndGetNotification("MyNotification",
+        runJavaScript("SetupReplyForwardingForTests();");
+        Notification notification = showAndGetNotification("MyNotification",
                 "{ "
                         + " actions: [{action: 'myAction', title: 'reply', type: 'text'}],"
                         + " data: 'ACTION_REPLY'}");
@@ -460,7 +452,8 @@
 
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
-        Notification notification = mNotificationTestRule.showAndGetNotification("MyNotification",
+        runJavaScript("SetupReplyForwardingForTests();");
+        Notification notification = showAndGetNotification("MyNotification",
                 "{ "
                         + " actions: [{action: 'myAction', title: 'reply', type: 'text'}],"
                         + " data: 'ACTION_REPLY'}");
@@ -484,8 +477,8 @@
         mNotificationTestRule.setNotificationContentSettingForOrigin(
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
 
-        Notification notification = mNotificationTestRule.showAndGetNotification(
-                "MyNotification", "{ tag: 'myTag', renotify: true }");
+        Notification notification =
+                showAndGetNotification("MyNotification", "{ tag: 'myTag', renotify: true }");
 
         Assert.assertEquals(0, notification.flags & Notification.FLAG_ONLY_ALERT_ONCE);
     }
@@ -501,8 +494,7 @@
         mNotificationTestRule.setNotificationContentSettingForOrigin(
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("MyNotification", "{ silent: true }");
+        Notification notification = showAndGetNotification("MyNotification", "{ silent: true }");
 
         // Zero indicates that no defaults should be inherited from the system.
         Assert.assertEquals(0, notification.defaults);
@@ -521,8 +513,7 @@
             }
         });
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("MyNotification", notificationOptions);
+        Notification notification = showAndGetNotification("MyNotification", notificationOptions);
 
         // Vibration should not be in the defaults.
         Assert.assertEquals(
@@ -576,8 +567,7 @@
             }
         });
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("MyNotification", "{ vibrate: 42 }");
+        Notification notification = showAndGetNotification("MyNotification", "{ vibrate: 42 }");
 
         // Vibration should not be in the defaults, a custom pattern was provided.
         Assert.assertEquals(
@@ -602,8 +592,8 @@
         mNotificationTestRule.setNotificationContentSettingForOrigin(
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
 
-        Notification notification = mNotificationTestRule.showAndGetNotification(
-                "MyNotification", "{badge: 'badge.png'}");
+        Notification notification =
+                showAndGetNotification("MyNotification", "{badge: 'badge.png'}");
 
         Assert.assertEquals("MyNotification", NotificationTestUtil.getExtraTitle(notification));
 
@@ -656,8 +646,7 @@
         mNotificationTestRule.setNotificationContentSettingForOrigin(
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("MyNotification", "{icon: 'red.png'}");
+        Notification notification = showAndGetNotification("MyNotification", "{icon: 'red.png'}");
 
         Assert.assertEquals("MyNotification", NotificationTestUtil.getExtraTitle(notification));
 
@@ -680,8 +669,7 @@
         mNotificationTestRule.setNotificationContentSettingForOrigin(
                 ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("NoIconNotification", "{}");
+        Notification notification = showAndGetNotification("NoIconNotification", "{}");
 
         Assert.assertEquals("NoIconNotification", NotificationTestUtil.getExtraTitle(notification));
 
@@ -721,8 +709,7 @@
 
         UserActionTester actionTester = new UserActionTester();
 
-        Notification notification =
-                mNotificationTestRule.showAndGetNotification("MyNotification", "{}");
+        Notification notification = showAndGetNotification("MyNotification", "{}");
 
         // Sending the PendingIntent resembles activating the notification.
         Assert.assertNotNull(notification.contentIntent);
@@ -768,8 +755,8 @@
                 "Expected the notification test page to be the sole tab in the current model", 1,
                 mNotificationTestRule.getActivity().getCurrentTabModel().getCount());
 
-        Notification notification = mNotificationTestRule.showAndGetNotification(
-                "MyNotification", "{ data: 'ACTION_CREATE_TAB' }");
+        Notification notification =
+                showAndGetNotification("MyNotification", "{ data: 'ACTION_CREATE_TAB' }");
 
         // Sending the PendingIntent resembles activating the notification.
         Assert.assertNotNull(notification.contentIntent);
@@ -807,22 +794,20 @@
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
 
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "showNotification('MyNotification', {tag: 'myTag'});");
+        showNotification("First", "{tag: 'myTag'}");
         mNotificationTestRule.waitForNotificationManagerMutation();
         List<NotificationEntry> notifications = mNotificationTestRule.getNotificationEntries();
         String tag = notifications.get(0).tag;
         int id = notifications.get(0).id;
 
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab(
-                "showNotification('SecondNotification', {tag: 'myTag'});");
+        showNotification("Second", "{tag: 'myTag'}");
         mNotificationTestRule.waitForNotificationManagerMutation();
 
         // Verify that the notification was successfully replaced.
         notifications = mNotificationTestRule.getNotificationEntries();
         Assert.assertEquals(1, notifications.size());
-        Assert.assertEquals("SecondNotification",
-                NotificationTestUtil.getExtraTitle(notifications.get(0).notification));
+        Assert.assertEquals(
+                "Second", NotificationTestUtil.getExtraTitle(notifications.get(0).notification));
 
         // Verify that for replaced notifications their tag was the same.
         Assert.assertEquals(tag, notifications.get(0).tag);
@@ -849,7 +834,7 @@
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
 
         // Open the first notification and verify it is displayed.
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab("showNotification('One');");
+        showNotification("One", "{}");
         mNotificationTestRule.waitForNotificationManagerMutation();
         List<NotificationEntry> notifications = mNotificationTestRule.getNotificationEntries();
         Assert.assertEquals(1, notifications.size());
@@ -857,7 +842,7 @@
         Assert.assertEquals("One", NotificationTestUtil.getExtraTitle(notificationOne));
 
         // Open the second notification and verify it is displayed.
-        mNotificationTestRule.runJavaScriptCodeInCurrentTab("showNotification('Two');");
+        showNotification("Two", "{}");
         mNotificationTestRule.waitForNotificationManagerMutation();
         notifications = mNotificationTestRule.getNotificationEntries();
         Assert.assertEquals(2, notifications.size());
@@ -899,6 +884,31 @@
         // Expect +1 engagement from interacting with the notification.
         Assert.assertEquals(2.5, getEngagementScoreBlocking(), 0);
     }
+    /**
+     * Shows a notification with |title| and |options|, waits until it has been displayed and then
+     * returns the Notification object to the caller. Requires that only a single notification is
+     * being displayed in the notification manager.
+     *
+     * @param title Title of the Web Notification to show.
+     * @param options Optional map of options to include when showing the notification.
+     * @return The Android Notification object, as shown in the framework.
+     */
+    private Notification showAndGetNotification(String title, String options)
+            throws TimeoutException, InterruptedException {
+        showNotification(title, options);
+        return mNotificationTestRule.waitForNotification().notification;
+    }
+
+    private void showNotification(String title, String options)
+            throws TimeoutException, InterruptedException {
+        runJavaScript("GetActivatedServiceWorkerForTest()"
+                + ".then(reg => reg.showNotification('" + title + "', " + options + "))"
+                + ".catch(sendToTest)");
+    }
+
+    private String runJavaScript(String code) throws TimeoutException, InterruptedException {
+        return mNotificationTestRule.runJavaScriptCodeInCurrentTab(code);
+    }
 
     /**
      * Get Notification related actions, filter all other actions to avoid flakes.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestRule.java
index 14d1766..5943cbcc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestRule.java
@@ -6,8 +6,6 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
-import android.app.Notification;
-
 import org.junit.Assert;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -80,21 +78,6 @@
     }
 
     /**
-     * Shows a notification with |title| and |options|, waits until it has been displayed and then
-     * returns the Notification object to the caller. Requires that only a single notification is
-     * being displayed in the notification manager.
-     *
-     * @param title Title of the Web Notification to show.
-     * @param options Optional map of options to include when showing the notification.
-     * @return The Android Notification object, as shown in the framework.
-     */
-    public Notification showAndGetNotification(String title, String options)
-            throws InterruptedException, TimeoutException {
-        runJavaScriptCodeInCurrentTab("showNotification(\"" + title + "\", " + options + ");");
-        return waitForNotification().notification;
-    }
-
-    /**
      * Waits until a notification has been displayed and then returns a NotificationEntry object to
      * the caller. Requires that only a single notification is displayed.
      *
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
index ebb8218..5bffd9e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
@@ -24,12 +24,7 @@
     private Boolean mAllow2dIntents;
 
     public static void createTestVrShellDelegate(final ChromeActivity activity) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                sInstance = new TestVrShellDelegate(activity);
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(() -> { sInstance = new TestVrShellDelegate(activity); });
     }
 
     public static TestVrShellDelegate getInstance() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java
index 47092d0..38a4191 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserCompositorViewHolderTest.java
@@ -20,11 +20,9 @@
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.WebContents;
 
-import java.util.concurrent.Callable;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -56,55 +54,45 @@
         final int testHeight = 456;
         final WebContents webContents = mVrTestRule.getWebContents();
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                CompositorViewHolder compositorViewHolder =
-                        (CompositorViewHolder) mVrTestRule.getActivity().findViewById(
-                                R.id.compositor_view_holder);
-                compositorViewHolder.onEnterVr();
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            CompositorViewHolder compositorViewHolder =
+                    (CompositorViewHolder) mVrTestRule.getActivity().findViewById(
+                            R.id.compositor_view_holder);
+            compositorViewHolder.onEnterVr();
 
-                oldWidth.set(webContents.getWidth());
-                oldHeight.set(webContents.getHeight());
+            oldWidth.set(webContents.getWidth());
+            oldHeight.set(webContents.getHeight());
 
-                ViewGroup.LayoutParams layoutParams = compositorViewHolder.getLayoutParams();
-                layoutParams.width = testWidth;
-                layoutParams.height = testHeight;
-                compositorViewHolder.requestLayout();
-            }
+            ViewGroup.LayoutParams layoutParams = compositorViewHolder.getLayoutParams();
+            layoutParams.width = testWidth;
+            layoutParams.height = testHeight;
+            compositorViewHolder.requestLayout();
         });
-        CriteriaHelper.pollUiThread(Criteria.equals(testWidth, new Callable<Integer>() {
-            @Override
-            public Integer call() {
-                return mVrTestRule.getActivity()
-                        .findViewById(R.id.compositor_view_holder)
-                        .getMeasuredWidth();
-            }
-        }));
+        CriteriaHelper.pollUiThread(() -> {
+            return mVrTestRule.getActivity()
+                           .findViewById(R.id.compositor_view_holder)
+                           .getMeasuredWidth()
+                    == testWidth;
+        }, "CompositorViewHolder width did not match the requested layout width");
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                Assert.assertEquals(
-                        "Viewport width should not have changed when resizing a detached "
-                                + "CompositorViewHolder",
-                        webContents.getWidth(), oldWidth.get().intValue());
-                Assert.assertEquals(
-                        "Viewport width should not have changed when resizing a detached "
-                                + "CompositorViewHolder",
-                        webContents.getHeight(), oldHeight.get().intValue());
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            Assert.assertEquals(
+                    "Viewport width changed when resizing a detached CompositorViewHolder",
+                    webContents.getWidth(), oldWidth.get().intValue());
+            Assert.assertEquals(
+                    "Viewport height changed when resizing a detached CompositorViewHolder",
+                    webContents.getHeight(), oldHeight.get().intValue());
 
-                CompositorViewHolder compositorViewHolder =
-                        (CompositorViewHolder) mVrTestRule.getActivity().findViewById(
-                                R.id.compositor_view_holder);
-                compositorViewHolder.onExitVr();
-                Assert.assertNotEquals("Viewport width should have changed after the "
-                                + "CompositorViewHolder was re-attached",
-                        webContents.getHeight(), oldHeight.get().intValue());
-                Assert.assertNotEquals("Viewport width should have changed after the "
-                                + "CompositorViewHolder was re-attached",
-                        webContents.getWidth(), oldWidth.get().intValue());
-            }
+            CompositorViewHolder compositorViewHolder =
+                    (CompositorViewHolder) mVrTestRule.getActivity().findViewById(
+                            R.id.compositor_view_holder);
+            compositorViewHolder.onExitVr();
+            Assert.assertNotEquals(
+                    "Viewport width did not change after CompositorViewHolder re-attached",
+                    webContents.getHeight(), oldHeight.get().intValue());
+            Assert.assertNotEquals(
+                    "Viewport height did not change after CompositorViewHolder re-attached",
+                    webContents.getWidth(), oldWidth.get().intValue());
         });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java
index 876334f..cb8cb808 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeTabUtils;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.RenderCoordinates;
@@ -63,13 +62,10 @@
 
     private void waitForPageToBeScrollable(final RenderCoordinates coord) {
         final View view = mVrTestRule.getActivity().getActivityTab().getContentView();
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return coord.getContentHeightPixInt() > view.getHeight()
-                        && coord.getContentWidthPixInt() > view.getWidth();
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_LONG_MS);
+        CriteriaHelper.pollUiThread(() -> {
+            return coord.getContentHeightPixInt() > view.getHeight()
+                    && coord.getContentWidthPixInt() > view.getWidth();
+        }, "Page did not become scrollable", POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_LONG_MS);
     }
 
     /**
@@ -98,25 +94,25 @@
         // TODO(bsheedy): Figure out why this is the case
         mController.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed);
         int endScrollPoint = coord.getScrollYPixInt();
-        Assert.assertTrue("Controller was able to scroll down", startScrollPoint < endScrollPoint);
+        Assert.assertTrue("Controller failed to scroll down", startScrollPoint < endScrollPoint);
 
         // Test that scrolling up works
         startScrollPoint = endScrollPoint;
         mController.scroll(EmulatedVrController.ScrollDirection.UP, scrollSteps, scrollSpeed);
         endScrollPoint = coord.getScrollYPixInt();
-        Assert.assertTrue("Controller was able to scroll up", startScrollPoint > endScrollPoint);
+        Assert.assertTrue("Controller failed to scroll up", startScrollPoint > endScrollPoint);
 
         // Test that scrolling right works
         startScrollPoint = coord.getScrollXPixInt();
         mController.scroll(EmulatedVrController.ScrollDirection.RIGHT, scrollSteps, scrollSpeed);
         endScrollPoint = coord.getScrollXPixInt();
-        Assert.assertTrue("Controller was able to scroll right", startScrollPoint < endScrollPoint);
+        Assert.assertTrue("Controller failed to scroll right", startScrollPoint < endScrollPoint);
 
         // Test that scrolling left works
         startScrollPoint = endScrollPoint;
         mController.scroll(EmulatedVrController.ScrollDirection.LEFT, scrollSteps, scrollSpeed);
         endScrollPoint = coord.getScrollXPixInt();
-        Assert.assertTrue("Controller was able to scroll left", startScrollPoint > endScrollPoint);
+        Assert.assertTrue("Controller failed to scroll left", startScrollPoint > endScrollPoint);
     }
 
     /**
@@ -140,23 +136,21 @@
         mController.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed);
         final AtomicInteger endScrollPoint = new AtomicInteger(coord.getScrollYPixInt());
         // Check that we continue to scroll past wherever we were when we let go of the touchpad
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return coord.getScrollYPixInt() > endScrollPoint.get();
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_LONG_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> { return coord.getScrollYPixInt() > endScrollPoint.get(); },
+                "Controller failed to fling scroll down", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_LONG_MS);
         mController.cancelFlingScroll();
 
         // Test fling scrolling up
         mController.scroll(EmulatedVrController.ScrollDirection.UP, scrollSteps, scrollSpeed);
         endScrollPoint.set(coord.getScrollYPixInt());
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return coord.getScrollYPixInt() < endScrollPoint.get();
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_LONG_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> { return coord.getScrollYPixInt() < endScrollPoint.get(); },
+                "Controller failed  to fling scroll up", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_LONG_MS);
         mController.cancelFlingScroll();
         // Horizontal scrolling becomes flaky if the scroll bar is at the top when we try to scroll
         // horizontally, so scroll down a bit to ensure that isn't the case.
@@ -165,23 +159,21 @@
         // Test fling scrolling right
         mController.scroll(EmulatedVrController.ScrollDirection.RIGHT, scrollSteps, scrollSpeed);
         endScrollPoint.set(coord.getScrollXPixInt());
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return coord.getScrollXPixInt() > endScrollPoint.get();
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_LONG_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> { return coord.getScrollXPixInt() > endScrollPoint.get(); },
+                "Controller failed to fling scroll right", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_LONG_MS);
         mController.cancelFlingScroll();
 
         // Test fling scrolling left
         mController.scroll(EmulatedVrController.ScrollDirection.LEFT, scrollSteps, scrollSpeed);
         endScrollPoint.set(coord.getScrollXPixInt());
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return coord.getScrollXPixInt() < endScrollPoint.get();
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_LONG_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> { return coord.getScrollXPixInt() < endScrollPoint.get(); },
+                "Controller failed to fling scroll left", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_LONG_MS);
     }
 
     /**
@@ -242,13 +234,13 @@
         int scrollSpeed = 60;
         mController.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed);
         int endScrollPoint = recyclerView.computeVerticalScrollOffset();
-        Assert.assertTrue("Controller was able to scroll down", startScrollPoint < endScrollPoint);
+        Assert.assertTrue("Controller failed to scroll down", startScrollPoint < endScrollPoint);
 
         // Test that scrolling up works
         startScrollPoint = endScrollPoint;
         mController.scroll(EmulatedVrController.ScrollDirection.UP, scrollSteps, scrollSpeed);
         endScrollPoint = recyclerView.computeVerticalScrollOffset();
-        Assert.assertTrue("Controller was able to scroll up", startScrollPoint > endScrollPoint);
+        Assert.assertTrue("Controller failed to scroll up", startScrollPoint > endScrollPoint);
     }
 
     /**
@@ -266,18 +258,21 @@
         DOMUtils.clickNode(mVrBrowserTestFramework.getFirstTabWebContents(), "fullscreen",
                 false /* goThroughRootAndroidView */);
         mVrBrowserTestFramework.waitOnJavaScriptStep();
-        Assert.assertTrue(DOMUtils.isFullscreen(mVrBrowserTestFramework.getFirstTabWebContents()));
+        Assert.assertTrue("Page did not enter fullscreen",
+                DOMUtils.isFullscreen(mVrBrowserTestFramework.getFirstTabWebContents()));
 
         mController.pressReleaseAppButton();
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                try {
-                    return !DOMUtils.isFullscreen(mVrBrowserTestFramework.getFirstTabWebContents());
-                } catch (InterruptedException | TimeoutException e) {
-                    return false;
-                }
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_LONG_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> {
+                    try {
+                        return !DOMUtils.isFullscreen(
+                                mVrBrowserTestFramework.getFirstTabWebContents());
+                    } catch (InterruptedException | TimeoutException e) {
+                        return false;
+                    }
+                },
+                "Page did not exit fullscreen after app button was pressed", POLL_TIMEOUT_LONG_MS,
+                POLL_CHECK_INTERVAL_LONG_MS);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserDialogTest.java
index ed88891..6e568604 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserDialogTest.java
@@ -69,7 +69,7 @@
 
         // Create UiCapture image directory.
         if (!sBaseDirectory.exists() && !sBaseDirectory.isDirectory()) {
-            Assert.assertTrue(sBaseDirectory.mkdirs());
+            Assert.assertTrue("Failed to make image capture directory", sBaseDirectory.mkdirs());
         }
     }
 
@@ -80,18 +80,18 @@
         }
     }
 
-    private boolean captureScreen(String filename) throws InterruptedException {
+    private void captureScreen(String filename) throws InterruptedException {
         // Ensure that any UI changes that have been rendered and submitted have actually propogated
         // to the screen.
         NativeUiUtils.waitNumFrames(2);
         // TODO(bsheedy): Make this work on Android P by drawing the view hierarchy to a bitmap.
         File screenshotFile = new File(sBaseDirectory, filename + ".png");
-        if (screenshotFile.exists() && !screenshotFile.delete()) return false;
+        Assert.assertFalse("Failed to delete existing screenshot",
+                screenshotFile.exists() && !screenshotFile.delete());
 
         final UiDevice uiDevice =
                 UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
-        return uiDevice.takeScreenshot(screenshotFile);
+        Assert.assertTrue("Failed to take screenshot", uiDevice.takeScreenshot(screenshotFile));
     }
 
     private void displayPermissionPrompt(String initialPage, String navigationCommand)
@@ -160,9 +160,9 @@
                 "test_navigation_2d_page", "navigator.getUserMedia({audio: true}, ()=>{}, ()=>{})");
 
         // Capture image
-        Assert.assertTrue(captureScreen("MicrophonePermissionPrompt_Visible"));
+        captureScreen("MicrophonePermissionPrompt_Visible");
         NativeUiUtils.clickFallbackUiPositiveButton();
-        Assert.assertTrue(captureScreen("MicrophonePermissionPrompt_Granted"));
+        captureScreen("MicrophonePermissionPrompt_Granted");
     }
 
     /**
@@ -177,7 +177,7 @@
                 "test_navigation_2d_page", "navigator.getUserMedia({video: true}, ()=>{}, ()=>{})");
 
         // Capture image
-        Assert.assertTrue(captureScreen("CameraPermissionPrompt_Visible"));
+        captureScreen("CameraPermissionPrompt_Visible");
     }
 
     /**
@@ -192,7 +192,7 @@
                 "navigator.geolocation.getCurrentPosition(()=>{}, ()=>{})");
 
         // Capture image
-        Assert.assertTrue(captureScreen("LocationPermissionPrompt_Visible"));
+        captureScreen("LocationPermissionPrompt_Visible");
     }
 
     /**
@@ -207,7 +207,7 @@
                 "test_navigation_2d_page", "Notification.requestPermission(()=>{})");
 
         // Capture image
-        Assert.assertTrue(captureScreen("NotificationPermissionPrompt_Visible"));
+        captureScreen("NotificationPermissionPrompt_Visible");
     }
 
     /**
@@ -222,7 +222,7 @@
                 "test_navigation_2d_page", "navigator.requestMIDIAccess({sysex: true})");
 
         // Capture image
-        Assert.assertTrue(captureScreen("MidiPermissionPrompt_Visible"));
+        captureScreen("MidiPermissionPrompt_Visible");
     }
 
     /**
@@ -237,7 +237,7 @@
                 "test_navigation_2d_page", "alert('538 perf regressions detected')");
 
         // Capture image
-        Assert.assertTrue(captureScreen("JavaScriptAlert_Visible"));
+        captureScreen("JavaScriptAlert_Visible");
     }
 
     /**
@@ -252,15 +252,15 @@
                 "test_navigation_2d_page", "var c = confirm('This is a confirmation dialog')");
 
         // Capture image
-        Assert.assertTrue(captureScreen("JavaScriptConfirm_Visible"));
+        captureScreen("JavaScriptConfirm_Visible");
 
         NativeUiUtils.clickFallbackUiNegativeButton();
         NativeUiUtils.revertToRealControllerAndWaitForUiQuiescence();
         // Ensure the cancel button was clicked.
-        Assert.assertTrue("Negative button clicked",
+        Assert.assertTrue("JavaScript Confirm's cancel button was not clicked",
                 mVrBrowserTestFramework.runJavaScriptOrFail("c", POLL_TIMEOUT_SHORT_MS)
                         .equals("false"));
-        Assert.assertTrue(captureScreen("JavaScriptConfirm_Dismissed"));
+        captureScreen("JavaScriptConfirm_Dismissed");
     }
 
     /**
@@ -277,17 +277,17 @@
                 "var p = prompt('Are the Chrome controls broken?', '" + expectedString + "')");
 
         // Capture image
-        Assert.assertTrue(captureScreen("JavaScriptPrompt_Visible"));
+        captureScreen("JavaScriptPrompt_Visible");
         NativeUiUtils.clickFallbackUiPositiveButton();
         NativeUiUtils.revertToRealControllerAndWaitForUiQuiescence();
         // This JavaScript will only run once the prompt has been dismissed, and the return value
         // will only be what we expect if the positive button was actually clicked (as opposed to
         // canceled).
-        Assert.assertTrue("Positive button clicked",
+        Assert.assertTrue("JavaScript Prompt's OK button was not clicked",
                 mVrBrowserTestFramework
                         .runJavaScriptOrFail("p == '" + expectedString + "'", POLL_TIMEOUT_SHORT_MS)
                         .equals("true"));
-        Assert.assertTrue(captureScreen("JavaScriptPrompt_Dismissed"));
+        captureScreen("JavaScriptPrompt_Dismissed");
     }
 
     @Test
@@ -295,7 +295,7 @@
     @HeadTrackingMode(HeadTrackingMode.SupportedMode.FROZEN)
     public void testKeyboardAppearsOnUrlBarClick() throws InterruptedException, TimeoutException {
         clickElement("test_navigation_2d_page", UserFriendlyElementName.URL);
-        Assert.assertTrue(captureScreen("KeyboardAppearsOnUrlBarClick_Visible"));
+        captureScreen("KeyboardAppearsOnUrlBarClick_Visible");
     }
 
     @Test
@@ -303,7 +303,7 @@
     @HeadTrackingMode(HeadTrackingMode.SupportedMode.FROZEN)
     public void testOverflowMenuAppears() throws InterruptedException, TimeoutException {
         clickElement("test_navigation_2d_page", UserFriendlyElementName.OVERFLOW_MENU);
-        Assert.assertTrue(captureScreen("OverflowMenuAppears_Visible"));
+        captureScreen("OverflowMenuAppears_Visible");
     }
 
     @Test
@@ -312,6 +312,6 @@
     public void testPageInfoAppearsOnSecurityTokenClick()
             throws InterruptedException, TimeoutException {
         clickElement("test_navigation_2d_page", UserFriendlyElementName.PAGE_INFO_BUTTON);
-        Assert.assertTrue(captureScreen("PageInfoAppearsOnSecurityTokenClick_Visible"));
+        captureScreen("PageInfoAppearsOnSecurityTokenClick_Visible");
     }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java
index 9c254d8..1f7ea95 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNativeUiTest.java
@@ -55,7 +55,7 @@
             throws IllegalArgumentException, InterruptedException, TimeoutException {
         for (String url : NATIVE_URLS_OF_INTEREST) {
             mVrTestRule.loadUrl(url, PAGE_LOAD_TIMEOUT_S);
-            Assert.assertFalse("Should not be showing URL on " + url,
+            Assert.assertFalse("URL is being shown for native page " + url,
                     TestVrShellDelegate.isDisplayingUrlForTesting());
         }
     }
@@ -68,6 +68,7 @@
     public void testUrlOnNonNativeUi()
             throws IllegalArgumentException, InterruptedException, TimeoutException {
         mVrTestRule.loadUrl(TEST_PAGE_2D_URL, PAGE_LOAD_TIMEOUT_S);
-        Assert.assertTrue("Should be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
+        Assert.assertTrue("URL is not being show for non-native page",
+                TestVrShellDelegate.isDisplayingUrlForTesting());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
index df37326..2c345ae3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
@@ -100,32 +100,27 @@
      * navigation. This is desirable since we are testing navigation transitions end-to-end.
      */
     private void navigateTo(final Page to) throws InterruptedException {
-        ChromeTabUtils.waitForTabPageLoaded(
-                mTestRule.getActivity().getActivityTab(), new Runnable() {
-                    @Override
-                    public void run() {
-                        mVrBrowserTestFramework.runJavaScriptOrFail(
-                                "window.location.href = '" + getUrl(to) + "';",
-                                POLL_TIMEOUT_SHORT_MS);
-                    }
-                }, POLL_TIMEOUT_LONG_MS);
+        ChromeTabUtils.waitForTabPageLoaded(mTestRule.getActivity().getActivityTab(), () -> {
+            mVrBrowserTestFramework.runJavaScriptOrFail(
+                    "window.location.href = '" + getUrl(to) + "';", POLL_TIMEOUT_SHORT_MS);
+        }, POLL_TIMEOUT_LONG_MS);
     }
 
     private void enterFullscreenOrFail(WebContents webContents)
             throws InterruptedException, TimeoutException {
         DOMUtils.clickNode(webContents, "fullscreen", false /* goThroughRootAndroidView */);
         VrBrowserTestFramework.waitOnJavaScriptStep(webContents);
-        Assert.assertTrue(DOMUtils.isFullscreen(webContents));
+        Assert.assertTrue("Failed to enter fullscreen", DOMUtils.isFullscreen(webContents));
     }
 
     private void assertState(WebContents wc, Page page, PresentationMode presentationMode,
             FullscreenMode fullscreenMode) throws InterruptedException, TimeoutException {
-        Assert.assertTrue("Browser is in VR", VrShellDelegate.isInVr());
-        Assert.assertEquals("Browser is on correct web site", getUrl(page), wc.getVisibleUrl());
-        Assert.assertEquals("Browser is in VR Presentation Mode",
+        Assert.assertTrue("Browser is not in VR", VrShellDelegate.isInVr());
+        Assert.assertEquals("Browser is not on correct web site", getUrl(page), wc.getVisibleUrl());
+        Assert.assertEquals("Browser's presentation mode does not match expectation",
                 presentationMode == PresentationMode.PRESENTING,
                 TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
-        Assert.assertEquals("Browser is in fullscreen",
+        Assert.assertEquals("Browser's fullscreen mode does not match expectation'",
                 fullscreenMode == FullscreenMode.FULLSCREENED, DOMUtils.isFullscreen(wc));
         // Feedback infobar should never show up during navigations.
         VrInfoBarUtils.expectInfoBarPresent(mTestRule, false);
@@ -153,13 +148,13 @@
         ArrayList<HistoryItemView> itemViews = historyPage.getHistoryManagerForTesting()
                                                        .getAdapterForTests()
                                                        .getItemViewsForTests();
-        Assert.assertEquals("Two navigations showed up in history", 2, itemViews.size());
+        Assert.assertEquals("Incorrect number of items in history", 2, itemViews.size());
         // History is in reverse chronological order, so the first navigation should actually be
         // after the second in the list
-        Assert.assertEquals("First navigation is correct", getUrl(Page.PAGE_2D),
-                itemViews.get(1).getItem().getUrl());
-        Assert.assertEquals("Second navigation is correct", getUrl(Page.PAGE_2D_2),
-                itemViews.get(0).getItem().getUrl());
+        Assert.assertEquals("First navigation did not show correctly in history",
+                getUrl(Page.PAGE_2D), itemViews.get(1).getItem().getUrl());
+        Assert.assertEquals("Second navigation did not show correctly in history",
+                getUrl(Page.PAGE_2D_2), itemViews.get(0).getItem().getUrl());
 
         // Test that clicking on history items in VR works
         ThreadUtils.runOnUiThreadBlocking(() -> itemViews.get(0).onClick());
@@ -447,22 +442,18 @@
     public void testBackDoesntBackgroundChrome()
             throws IllegalArgumentException, InterruptedException {
         Assert.assertFalse(
-                "Back button isn't disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+                "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
         mTestRule.loadUrlInNewTab(getUrl(Page.PAGE_2D), false, TabLaunchType.FROM_CHROME_UI);
         Assert.assertFalse(
-                "Back button isn't disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+                "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
         final Tab tab =
                 mTestRule.loadUrlInNewTab(getUrl(Page.PAGE_2D), false, TabLaunchType.FROM_LINK);
         Assert.assertTrue(
-                "Back button isn't enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mTestRule.getActivity().getTabModelSelector().closeTab(tab);
-            }
-        });
+                "Back button is disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { mTestRule.getActivity().getTabModelSelector().closeTab(tab); });
         Assert.assertFalse(
-                "Back button isn't disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+                "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
     }
 
     /**
@@ -472,37 +463,37 @@
     @MediumTest
     public void testNavigationButtons() throws IllegalArgumentException, InterruptedException {
         Assert.assertFalse(
-                "Back button isn't disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
-        Assert.assertFalse("Forward button isn't disabled.",
-                VrBrowserTransitionUtils.isForwardButtonEnabled());
+                "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+        Assert.assertFalse(
+                "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled());
         // Opening a new tab shouldn't enable the back button
         mTestRule.loadUrlInNewTab(getUrl(Page.PAGE_2D), false, TabLaunchType.FROM_CHROME_UI);
         Assert.assertFalse(
-                "Back button isn't disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
-        Assert.assertFalse("Forward button isn't disabled.",
-                VrBrowserTransitionUtils.isForwardButtonEnabled());
+                "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+        Assert.assertFalse(
+                "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled());
         // Navigating to a new page should enable the back button
         mTestRule.loadUrl(getUrl(Page.PAGE_WEBVR));
         Assert.assertTrue(
-                "Back button isn't enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
-        Assert.assertFalse("Forward button isn't disabled.",
-                VrBrowserTransitionUtils.isForwardButtonEnabled());
+                "Back button is disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+        Assert.assertFalse(
+                "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled());
         // Navigating back should disable the back button and enable the forward button
         VrBrowserTransitionUtils.navigateBack();
         ChromeTabUtils.waitForTabPageLoaded(
                 mTestRule.getActivity().getActivityTab(), getUrl(Page.PAGE_2D));
         Assert.assertFalse(
-                "Back button isn't disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+                "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
         Assert.assertTrue(
-                "Forward button isn't enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled());
+                "Forward button is disabled.", VrBrowserTransitionUtils.isForwardButtonEnabled());
         // Navigating forward should disable the forward button and enable the back button
         VrBrowserTransitionUtils.navigateForward();
         ChromeTabUtils.waitForTabPageLoaded(
                 mTestRule.getActivity().getActivityTab(), getUrl(Page.PAGE_WEBVR));
         Assert.assertTrue(
-                "Back button isn't enabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
-        Assert.assertFalse("Forward button isn't disabled.",
-                VrBrowserTransitionUtils.isForwardButtonEnabled());
+                "Back button is disabled.", VrBrowserTransitionUtils.isBackButtonEnabled());
+        Assert.assertFalse(
+                "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled());
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTestFramework.java
index f5efb59..9fec598 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTestFramework.java
@@ -15,6 +15,6 @@
 public class VrBrowserTestFramework extends XrTestFramework {
     public VrBrowserTestFramework(ChromeActivityTestRule rule) {
         super(rule);
-        Assert.assertFalse("Test did not start in VR", VrShellDelegate.isInVr());
+        Assert.assertFalse("Test started in VR", VrShellDelegate.isInVr());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
index 4c134a6a..6da1d81 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
@@ -43,7 +43,6 @@
 import org.chromium.chrome.browser.vr.util.VrShellDelegateUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ActivityUtils;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
@@ -77,10 +76,10 @@
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         if (supported) {
             NfcSimUtils.simNfcScanUntilVrEntry(mTestRule.getActivity());
-            Assert.assertTrue(VrShellDelegate.isInVr());
+            Assert.assertTrue("Browser is not in VR", VrShellDelegate.isInVr());
         } else {
             NfcSimUtils.simNfcScan(mTestRule.getActivity());
-            Assert.assertFalse(VrShellDelegate.isInVr());
+            Assert.assertFalse("Browser is in VR", VrShellDelegate.isInVr());
         }
         VrBrowserTransitionUtils.forceExitVr();
     }
@@ -93,13 +92,13 @@
         VrBrowserTransitionUtils.forceEnterVrBrowser();
         if (supported) {
             VrBrowserTransitionUtils.waitForVrEntry(POLL_TIMEOUT_LONG_MS);
-            Assert.assertTrue(VrShellDelegate.isInVr());
+            Assert.assertTrue("Browser is not in VR", VrShellDelegate.isInVr());
         } else {
-            Assert.assertFalse(mockApi.getLaunchInVrCalled());
-            Assert.assertFalse(VrShellDelegate.isInVr());
+            Assert.assertFalse("launchInVr was called", mockApi.getLaunchInVrCalled());
+            Assert.assertFalse("Browser is in VR", VrShellDelegate.isInVr());
         }
         VrBrowserTransitionUtils.forceExitVr();
-        Assert.assertFalse(VrShellDelegate.isInVr());
+        Assert.assertFalse("Browser is in VR", VrShellDelegate.isInVr());
     }
 
     /**
@@ -158,12 +157,11 @@
 
         // Wait until we enter VR and have the correct URL.
         VrBrowserTransitionUtils.waitForVrEntry(POLL_TIMEOUT_LONG_MS);
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mTestRule.getWebContents().getVisibleUrl().equals(url);
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollUiThread(
+                ()
+                        -> { return mTestRule.getWebContents().getVisibleUrl().equals(url); },
+                "Displayed URL does not match URL provided to VR launch intent",
+                POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
         return url;
     }
 
@@ -179,13 +177,10 @@
         String url = testVrEntryIntentInternal();
 
         VrBrowserTransitionUtils.send2dMainIntent();
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !VrShellDelegate.isInVr();
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
-        Assert.assertEquals("Url correct", url, mTestRule.getWebContents().getVisibleUrl());
+        CriteriaHelper.pollUiThread(() -> {
+            return !VrShellDelegate.isInVr();
+        }, "2D intent did not exit VR", POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        Assert.assertEquals("URL is incorrect", url, mTestRule.getWebContents().getVisibleUrl());
     }
 
     /**
@@ -214,20 +209,23 @@
                 false /* goThroughRootAndroidView */);
         mVrBrowserTestFramework.waitOnJavaScriptStep();
 
-        Assert.assertTrue(DOMUtils.isFullscreen(mVrBrowserTestFramework.getFirstTabWebContents()));
+        Assert.assertTrue("Page is not in fullscreen",
+                DOMUtils.isFullscreen(mVrBrowserTestFramework.getFirstTabWebContents()));
         VrBrowserTransitionUtils.forceExitVr();
         // The fullscreen exit from exiting VR isn't necessarily instantaneous, so give it
         // a bit of time.
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                try {
-                    return !DOMUtils.isFullscreen(mVrBrowserTestFramework.getFirstTabWebContents());
-                } catch (InterruptedException | TimeoutException e) {
-                    return false;
-                }
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> {
+                    try {
+                        return !DOMUtils.isFullscreen(
+                                mVrBrowserTestFramework.getFirstTabWebContents());
+                    } catch (InterruptedException | TimeoutException e) {
+                        return false;
+                    }
+                },
+                "Exiting VR did not exit fullscreen", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
     }
 
     /**
@@ -273,12 +271,12 @@
         // We aren't comparing for equality because there is some rounding that occurs.
         String javascript = "Math.abs(screen.width - " + expectedWidth + ") <= 1 && "
                 + "Math.abs(screen.height - " + expectedHeight + ") <= 1";
-        Assert.assertTrue(framework.pollJavaScriptBoolean(javascript, POLL_TIMEOUT_LONG_MS));
+        framework.pollJavaScriptBooleanOrFail(javascript, POLL_TIMEOUT_LONG_MS);
 
         // Exit presentation through JavaScript.
         framework.runJavaScriptOrFail(exitPresentString, POLL_TIMEOUT_SHORT_MS);
 
-        Assert.assertTrue(framework.pollJavaScriptBoolean(javascript, POLL_TIMEOUT_LONG_MS));
+        framework.pollJavaScriptBooleanOrFail(javascript, POLL_TIMEOUT_LONG_MS);
     }
 
     /**
@@ -337,21 +335,18 @@
     @MediumTest
     public void testEnterVrInOverviewMode() throws InterruptedException, TimeoutException {
         final ChromeTabbedActivity activity = mTestRule.getActivity();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                ImageView tabSwitcher = (ImageView) activity.findViewById(R.id.tab_switcher_button);
-                tabSwitcher.callOnClick();
-            }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            ImageView tabSwitcher = (ImageView) activity.findViewById(R.id.tab_switcher_button);
+            tabSwitcher.callOnClick();
         });
 
-        Assert.assertTrue(activity.isInOverviewMode());
+        Assert.assertTrue("Browser is not in overview mode", activity.isInOverviewMode());
 
         MockVrDaydreamApi mockApi = new MockVrDaydreamApi();
         VrShellDelegateUtils.getDelegateInstance().overrideDaydreamApiForTesting(mockApi);
         VrBrowserTransitionUtils.forceEnterVrBrowserOrFail(POLL_TIMEOUT_LONG_MS);
-        Assert.assertFalse(mockApi.getExitFromVrCalled());
-        Assert.assertFalse(mockApi.getLaunchVrHomescreenCalled());
+        Assert.assertFalse("exitFromVr was called", mockApi.getExitFromVrCalled());
+        Assert.assertFalse("launchVrHomescreen was called", mockApi.getLaunchVrHomescreenCalled());
         VrShellDelegateUtils.getDelegateInstance().overrideDaydreamApiForTesting(null);
     }
 
@@ -396,8 +391,9 @@
         ThreadUtils.runOnUiThreadBlocking(
                 () -> { VrShellDelegateUtils.getDelegateInstance().acceptDoffPromptForTesting(); });
 
-        CriteriaHelper.pollUiThread(() -> { return mockApi.getExitFromVrCalled(); });
-        Assert.assertFalse(mockApi.getLaunchVrHomescreenCalled());
+        CriteriaHelper.pollUiThread(
+                () -> { return mockApi.getExitFromVrCalled(); }, "exitFromVr was not called");
+        Assert.assertFalse("launchVrHomescreen was called", mockApi.getLaunchVrHomescreenCalled());
         mockApi.close();
 
         MockVrDaydreamApi mockApiWithDoff = new MockVrDaydreamApi();
@@ -409,8 +405,9 @@
             PreferencesLauncher.launchSettingsPage(context, null);
             VrShellDelegateUtils.getDelegateInstance().acceptDoffPromptForTesting();
         });
-        CriteriaHelper.pollUiThread(
-                () -> { return VrShellDelegateUtils.getDelegateInstance().isShowingDoff(); });
+        CriteriaHelper.pollUiThread(() -> {
+            return VrShellDelegateUtils.getDelegateInstance().isShowingDoff();
+        }, "DOFF screen was not shown");
         ThreadUtils.runOnUiThreadBlocking(() -> {
             mTestRule.getActivity().onActivityResult(
                     VrShellDelegate.EXIT_VR_RESULT, Activity.RESULT_OK, null);
@@ -431,13 +428,11 @@
         Activity context = mTestRule.getActivity();
         VrBrowserTransitionUtils.forceEnterVrBrowserOrFail(POLL_TIMEOUT_LONG_MS);
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                Intent preferencesIntent = PreferencesLauncher.createIntentForSettingsPage(
-                        context, SingleWebsitePreferences.class.getName());
-                Assert.assertFalse(context.startActivityIfNeeded(preferencesIntent, 0));
-            }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            Intent preferencesIntent = PreferencesLauncher.createIntentForSettingsPage(
+                    context, SingleWebsitePreferences.class.getName());
+            Assert.assertFalse("Starting an activity did not trigger DOFF",
+                    context.startActivityIfNeeded(preferencesIntent, 0));
         });
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
index 2003604..6a9fd14 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
@@ -27,7 +27,6 @@
 import org.chromium.chrome.browser.vr.util.NativeUiUtils;
 import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 /**
@@ -74,13 +73,14 @@
         // focus gain spawns the keyboard by clicking in the center of the page.
         NativeUiUtils.clickElementAndWaitForUiQuiescence(
                 UserFriendlyElementName.CONTENT_QUAD, new PointF());
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Boolean visible = keyboard.getLastKeyboardVisibility();
-                return visible != null && visible;
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> {
+                    Boolean visible = keyboard.getLastKeyboardVisibility();
+                    return visible != null && visible;
+                },
+                "Keyboard did not show from focusing a web input box", POLL_TIMEOUT_LONG_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
 
         // Add text to the input field via the input connection and verify that the keyboard
         // interface is called to update the indices.
@@ -90,23 +90,25 @@
         // Inserting 'i' should move the cursor by one character and there should be no composition.
         MockBrowserKeyboardInterface.Indices expectedIndices =
                 new MockBrowserKeyboardInterface.Indices(1, 1, -1, -1);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                MockBrowserKeyboardInterface.Indices indices = keyboard.getLastIndices();
-                return indices == null ? false : indices.equals(expectedIndices);
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> {
+                    MockBrowserKeyboardInterface.Indices indices = keyboard.getLastIndices();
+                    return indices == null ? false : indices.equals(expectedIndices);
+                },
+                "Inputting text did not move cursor the expected amount", POLL_TIMEOUT_LONG_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
 
         // The second click should result in a focus loss and should hide the keyboard.
         NativeUiUtils.clickElementAndWaitForUiQuiescence(
                 UserFriendlyElementName.CONTENT_QUAD, new PointF());
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Boolean visible = keyboard.getLastKeyboardVisibility();
-                return visible != null && !visible;
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> {
+                    Boolean visible = keyboard.getLastKeyboardVisibility();
+                    return visible != null && !visible;
+                },
+                "Keyboard did not hide from unfocusing a web input box", POLL_TIMEOUT_LONG_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
index 7d876a8..562be4c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
@@ -61,11 +61,13 @@
         mWebXrVrTestFramework = new WebXrVrTestFramework(mTestRule);
         mWebVrTestFramework = new WebVrTestFramework(mTestRule);
         mVrBrowserTestFramework = new VrBrowserTestFramework(mTestRule);
-        Assert.assertFalse(VrFeedbackStatus.getFeedbackOptOut());
+        Assert.assertFalse(
+                "Test started opting out of feedback", VrFeedbackStatus.getFeedbackOptOut());
     }
 
     private void assertState(boolean isInVr, boolean isInfobarVisible) {
-        Assert.assertEquals("Browser is in VR", isInVr, VrShellDelegate.isInVr());
+        Assert.assertEquals(
+                "Browser VR state did not match expectation", isInVr, VrShellDelegate.isInVr());
         VrInfoBarUtils.expectInfoBarPresent(mTestRule, isInfobarVisible);
     }
 
@@ -121,7 +123,7 @@
 
         // Opt-out of seeing the infobar.
         VrInfoBarUtils.clickInfoBarButton(VrInfoBarUtils.Button.SECONDARY, mTestRule);
-        Assert.assertTrue(VrFeedbackStatus.getFeedbackOptOut());
+        Assert.assertTrue("Did not opt out of VR feedback", VrFeedbackStatus.getFeedbackOptOut());
 
         // The infobar should not show because the user opted out.
         enterThenExitVr();
@@ -156,7 +158,8 @@
         framework.loadUrlAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S);
         framework.enterSessionWithUserGestureOrFail();
         assertState(true /* isInVr */, false /* isInfobarVisible  */);
-        Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
+        Assert.assertTrue("Did not enter WebVR presentation",
+                TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
 
         // Exiting VR should not prompt for feedback since the no VR browsing was performed.
         VrBrowserTransitionUtils.forceExitVr();
@@ -195,18 +198,14 @@
         framework.loadUrlAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S);
         framework.enterSessionWithUserGestureOrFail();
         assertState(true /* isInVr */, false /* isInfobarVisible  */);
-        Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
+        Assert.assertTrue("Did not enter WebVR presentation",
+                TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
 
         // Exit presentation mode by navigating to a different url.
-        ChromeTabUtils.waitForTabPageLoaded(
-                mTestRule.getActivity().getActivityTab(), new Runnable() {
-                    @Override
-                    public void run() {
-                        mVrBrowserTestFramework.runJavaScriptOrFail(
-                                "window.location.href = '" + TEST_PAGE_2D_URL + "';",
-                                POLL_TIMEOUT_SHORT_MS);
-                    }
-                }, POLL_TIMEOUT_LONG_MS);
+        ChromeTabUtils.waitForTabPageLoaded(mTestRule.getActivity().getActivityTab(), () -> {
+            mVrBrowserTestFramework.runJavaScriptOrFail(
+                    "window.location.href = '" + TEST_PAGE_2D_URL + "';", POLL_TIMEOUT_SHORT_MS);
+        }, POLL_TIMEOUT_LONG_MS);
 
         // Exiting VR should prompt for feedback since 2D browsing was performed after.
         VrBrowserTransitionUtils.forceExitVr();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java
index 74bad02..3b53ea4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java
@@ -84,9 +84,11 @@
             }
             VrInfoBarUtils.expectInfoBarPresent(mVrTestRule, true);
             TextView tempView = (TextView) decorView.findViewById(R.id.infobar_message);
-            Assert.assertEquals(expectedMessage, tempView.getText().toString());
+            Assert.assertEquals("VR install/update infobar text did not match expectation",
+                    expectedMessage, tempView.getText().toString());
             tempView = (TextView) decorView.findViewById(R.id.button_primary);
-            Assert.assertEquals(expectedButton, tempView.getText().toString());
+            Assert.assertEquals("VR install/update button text did not match expectation",
+                    expectedButton, tempView.getText().toString());
         } else if (checkerReturnCompatibility == VrCoreCompatibility.VR_NOT_SUPPORTED) {
             VrInfoBarUtils.expectInfoBarPresent(mVrTestRule, false);
         } else {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebVrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebVrTestFramework.java
index 05cf410..3e1df68 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebVrTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebVrTestFramework.java
@@ -36,9 +36,9 @@
     @Override
     public void enterSessionWithUserGestureOrFail(WebContents webContents) {
         enterSessionWithUserGesture(webContents);
-        Assert.assertTrue(
-                pollJavaScriptBoolean("vrDisplay.isPresenting", POLL_TIMEOUT_LONG_MS, webContents));
-        Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
+        pollJavaScriptBooleanOrFail("vrDisplay.isPresenting", POLL_TIMEOUT_LONG_MS, webContents);
+        Assert.assertTrue("VRDisplay presenting, but VR Shell not in WebVR mode",
+                TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSessionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSessionTest.java
index 1f269ec6..9d29b96 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSessionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSessionTest.java
@@ -127,14 +127,16 @@
                 mServer.getURL(WebXrArTestFramework.getEmbeddedServerPathForHtmlTestFile(
                         "test_ar_request_session_succeeds")),
                 PAGE_LOAD_TIMEOUT_S);
-        Assert.assertTrue(mWebXrArTestFramework.arSessionRequestWouldTriggerPermissionPrompt());
+        Assert.assertTrue("First AR session request did not trigger permission prompt",
+                mWebXrArTestFramework.arSessionRequestWouldTriggerPermissionPrompt());
         mWebXrArTestFramework.enterSessionWithUserGestureOrFail();
         mWebXrArTestFramework.endSession();
         // Manually run through the same steps as enterArSessionOrFail so that we don't trigger
         // its automatic permission acceptance.
-        Assert.assertFalse(mWebXrArTestFramework.arSessionRequestWouldTriggerPermissionPrompt());
+        Assert.assertFalse("Second AR session request triggered permission prompt",
+                mWebXrArTestFramework.arSessionRequestWouldTriggerPermissionPrompt());
         mWebXrArTestFramework.enterSessionWithUserGesture();
-        Assert.assertTrue(mWebXrArTestFramework.pollJavaScriptBoolean(
-                "sessionInfos[sessionTypes.AR].currentSession != null", POLL_TIMEOUT_LONG_MS));
+        mWebXrArTestFramework.pollJavaScriptBooleanOrFail(
+                "sessionInfos[sessionTypes.AR].currentSession != null", POLL_TIMEOUT_LONG_MS);
     }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArTestFramework.java
index cd77b09..fc24a2d5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArTestFramework.java
@@ -6,12 +6,9 @@
 
 import android.content.DialogInterface;
 
-import org.junit.Assert;
-
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.permissions.PermissionDialogController;
 import org.chromium.chrome.test.ChromeActivityTestRule;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.WebContents;
 
@@ -27,9 +24,8 @@
     public static boolean arSessionRequestWouldTriggerPermissionPrompt(WebContents webContents) {
         runJavaScriptOrFail("checkIfArSessionWouldTriggerPermissionPrompt()", POLL_TIMEOUT_SHORT_MS,
                 webContents);
-        Assert.assertTrue(
-                pollJavaScriptBoolean("arSessionRequestWouldTriggerPermissionPrompt !== null",
-                        POLL_TIMEOUT_SHORT_MS, webContents));
+        pollJavaScriptBooleanOrFail("arSessionRequestWouldTriggerPermissionPrompt !== null",
+                POLL_TIMEOUT_SHORT_MS, webContents);
         return Boolean.valueOf(runJavaScriptOrFail("arSessionRequestWouldTriggerPermissionPrompt",
                 POLL_TIMEOUT_SHORT_MS, webContents));
     }
@@ -59,13 +55,10 @@
         enterSessionWithUserGesture(webContents);
         if (expectPermissionPrompt) {
             // Wait for the permission prompt to appear.
-            CriteriaHelper.pollUiThread(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return PermissionDialogController.getInstance().getCurrentDialogForTesting()
-                            != null;
-                }
-            });
+            CriteriaHelper.pollUiThread(() -> {
+                return PermissionDialogController.getInstance().getCurrentDialogForTesting()
+                        != null;
+            }, "Camera permission prompt did not appear");
             // Accept the permission prompt.
             ThreadUtils.runOnUiThreadBlocking(() -> {
                 PermissionDialogController.getInstance()
@@ -74,9 +67,8 @@
                         .performClick();
             });
         }
-        Assert.assertTrue(
-                pollJavaScriptBoolean("sessionInfos[sessionTypes.AR].currentSession != null",
-                        POLL_TIMEOUT_LONG_MS, webContents));
+        pollJavaScriptBooleanOrFail("sessionInfos[sessionTypes.AR].currentSession != null",
+                POLL_TIMEOUT_LONG_MS, webContents);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
index d6f32c6..869f0be 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
@@ -44,7 +44,6 @@
 import org.chromium.chrome.browser.vr.util.VrTransitionUtils;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.content_public.browser.ViewEventSink;
@@ -88,7 +87,7 @@
         String boolExpression = (framework instanceof WebVrTestFramework)
                 ? "!vrDisplay.isPresenting"
                 : "sessionInfos[sessionTypes.IMMERSIVE].currentSession == null";
-        Assert.assertEquals("App button exited presentation", shouldHaveExited,
+        Assert.assertEquals("App button effect matched expectation", shouldHaveExited,
                 mWebXrVrTestFramework.pollJavaScriptBoolean(boolExpression, POLL_TIMEOUT_SHORT_MS));
     }
 
@@ -143,7 +142,7 @@
                     }
                 });
         TouchCommon.singleClickView(mTestRule.getActivity().getWindow().getDecorView());
-        Assert.assertTrue("VrShellImpl dispatched touches",
+        Assert.assertTrue("VrShellImpl did not dispatch touches",
                 touchRegisteredLatch.await(POLL_TIMEOUT_LONG_MS * 10, TimeUnit.MILLISECONDS));
         framework.executeStepAndWait("stepVerifyNoAdditionalTaps()");
         framework.endTest();
@@ -174,11 +173,11 @@
                 break;
             }
         }
-        Assert.assertTrue("Gamepad API detected controller", controllerConnected);
+        Assert.assertTrue("Gamepad API did not detect controller", controllerConnected);
         // It's possible for input to get backed up if the emulated controller is being slow, so
         // ensure that any outstanding output has been received before starting by waiting for
         // 60 frames (1 second) of not receiving input.
-        mWebVrTestFramework.pollJavaScriptBoolean("isInputDrained()", POLL_TIMEOUT_LONG_MS);
+        mWebVrTestFramework.pollJavaScriptBooleanOrFail("isInputDrained()", POLL_TIMEOUT_LONG_MS);
         // Have a separate start condition so that the above presses/releases don't get
         // accidentally detected during the actual test
         mWebVrTestFramework.runJavaScriptOrFail("canStartTest = true;", POLL_TIMEOUT_SHORT_MS);
@@ -227,24 +226,18 @@
 
     private long sendScreenTouchDown(final View view, final int x, final int y) {
         long downTime = SystemClock.uptimeMillis();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                view.dispatchTouchEvent(
-                        MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0));
-            }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            view.dispatchTouchEvent(
+                    MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0));
         });
         return downTime;
     }
 
     private void sendScreenTouchUp(final View view, final int x, final int y, final long downTime) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                long now = SystemClock.uptimeMillis();
-                view.dispatchTouchEvent(
-                        MotionEvent.obtain(downTime, now, MotionEvent.ACTION_UP, x, y, 0));
-            }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            long now = SystemClock.uptimeMillis();
+            view.dispatchTouchEvent(
+                    MotionEvent.obtain(downTime, now, MotionEvent.ACTION_UP, x, y, 0));
         });
     }
 
@@ -503,19 +496,18 @@
                         "generic_webvr_page_with_activate_listener"),
                 PAGE_LOAD_TIMEOUT_S);
 
-        CriteriaHelper.pollUiThread(new Criteria("DisplayActivate was never registered.") {
-            @Override
-            public boolean isSatisfied() {
-                return VrShellDelegateUtils.getDelegateInstance().isListeningForWebVrActivate();
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                ViewEventSink.from(mTestRule.getWebContents()).onPauseForTesting();
-                Assert.assertFalse(
-                        VrShellDelegateUtils.getDelegateInstance().isListeningForWebVrActivate());
-            }
+        CriteriaHelper.pollUiThread(
+                ()
+                        -> {
+                    return VrShellDelegateUtils.getDelegateInstance().isListeningForWebVrActivate();
+                },
+                "DisplayActivate was never registered", POLL_TIMEOUT_LONG_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            ViewEventSink.from(mTestRule.getWebContents()).onPauseForTesting();
+            Assert.assertFalse(
+                    "VR Shell is listening for headset insertion after WebContents paused",
+                    VrShellDelegateUtils.getDelegateInstance().isListeningForWebVrActivate());
         });
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java
index cf3e0ef..2be9122b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java
@@ -17,7 +17,7 @@
 public class WebXrVrTestFramework extends WebXrTestFramework {
     public WebXrVrTestFramework(ChromeActivityTestRule rule) {
         super(rule);
-        Assert.assertFalse("Test did not start in VR", VrShellDelegate.isInVr());
+        Assert.assertFalse("Test started in VR", VrShellDelegate.isInVr());
     }
 
     /**
@@ -48,10 +48,10 @@
         runJavaScriptOrFail(
                 "sessionTypeToRequest = sessionTypes.IMMERSIVE", POLL_TIMEOUT_LONG_MS, webContents);
         enterSessionWithUserGesture(webContents);
-        Assert.assertTrue(
-                pollJavaScriptBoolean("sessionInfos[sessionTypes.IMMERSIVE].currentSession != null",
-                        POLL_TIMEOUT_LONG_MS, webContents));
-        Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
+        pollJavaScriptBooleanOrFail("sessionInfos[sessionTypes.IMMERSIVE].currentSession != null",
+                POLL_TIMEOUT_LONG_MS, webContents);
+        Assert.assertTrue("Immersive session started, but VR Shell not in presentation mode",
+                TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
index 22fad4c..c67a5229 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
@@ -45,7 +45,6 @@
 import org.chromium.chrome.browser.vr.util.VrTransitionUtils;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 import java.util.List;
@@ -116,35 +115,37 @@
             throws InterruptedException {
         framework.loadUrlAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S);
         framework.enterSessionWithUserGestureOrFail();
-        Assert.assertTrue("VrShellDelegate is in VR", VrShellDelegate.isInVr());
+        Assert.assertTrue("Browser did not enter VR", VrShellDelegate.isInVr());
 
         // Initial Pixel Test - Verify that the Canvas is blue.
         // The Canvas is set to blue while presenting.
         final UiDevice uiDevice =
                 UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Bitmap screenshot = InstrumentationRegistry.getInstrumentation()
-                                            .getUiAutomation()
-                                            .takeScreenshot();
+        CriteriaHelper.pollInstrumentationThread(
+                ()
+                        -> {
+                    Bitmap screenshot = InstrumentationRegistry.getInstrumentation()
+                                                .getUiAutomation()
+                                                .takeScreenshot();
 
-                if (screenshot != null) {
-                    // Calculate center of eye coordinates.
-                    int height = uiDevice.getDisplayHeight() / 2;
-                    int width = uiDevice.getDisplayWidth() / 4;
+                    if (screenshot != null) {
+                        // Calculate center of eye coordinates.
+                        int height = uiDevice.getDisplayHeight() / 2;
+                        int width = uiDevice.getDisplayWidth() / 4;
 
-                    // Verify screen is blue.
-                    int pixel = screenshot.getPixel(width, height);
-                    // Workaround for the immersive mode popup sometimes being rendered over the
-                    // screen on K, which causes the pure blue to be darkened to (0, 0, 127).
-                    // TODO(https://crbug.com/819021): Only check pure blue.
-                    return pixel == Color.BLUE || pixel == Color.rgb(0, 0, 127);
-                }
-                return false;
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_LONG_MS);
+                        // Verify screen is blue.
+                        int pixel = screenshot.getPixel(width, height);
+                        // Workaround for the immersive mode popup sometimes being rendered over
+                        // the screen on K, which causes the pure blue to be darkened to (0, 0,
+                        // 127).
+                        // TODO(https://crbug.com/819021): Only check pure blue.
+                        return pixel == Color.BLUE || pixel == Color.rgb(0, 0, 127);
+                    }
+                    return false;
+                },
+                "Immersive session started, but browser not visibly in VR", POLL_TIMEOUT_LONG_MS,
+                POLL_CHECK_INTERVAL_LONG_MS);
     }
 
     /**
@@ -291,12 +292,9 @@
         // Wait until the DON flow appears to be triggered
         // TODO(bsheedy): Make this less hacky if there's ever an explicit way to check if the
         // DON flow is currently active https://crbug.com/758296
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return uiDevice.getCurrentPackageName().equals("com.google.vr.vrcore");
-            }
-        }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollUiThread(() -> {
+            return uiDevice.getCurrentPackageName().equals("com.google.vr.vrcore");
+        }, "DON flow did not start", POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
         uiDevice.pressBack();
         framework.waitOnJavaScriptStep();
         framework.endTest();
@@ -336,13 +334,14 @@
         // to propagate. In the worst case this test will erroneously pass, but should never
         // erroneously fail, and should only be flaky if omnibox showing is broken.
         Thread.sleep(100);
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                ChromeActivity activity = framework.getRule().getActivity();
-                return activity.getFullscreenManager().getBrowserControlHiddenRatio() == 0.0;
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollUiThread(
+                ()
+                        -> {
+                    ChromeActivity activity = framework.getRule().getActivity();
+                    return activity.getFullscreenManager().getBrowserControlHiddenRatio() == 0.0;
+                },
+                "Browser controls did not unhide after exiting VR", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
     }
 
     /**
@@ -428,7 +427,7 @@
         framework.loadUrlAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S);
         framework.enterSessionWithUserGestureOrFail();
         framework.simulateRendererKilled();
-        Assert.assertTrue("Browser is in VR", VrShellDelegate.isInVr());
+        Assert.assertTrue("Browser did not enter VR", VrShellDelegate.isInVr());
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
index 8ccc78ba..369717e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
@@ -15,14 +15,12 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeActivityTestRule;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.WebContents;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -114,29 +112,26 @@
     }
 
     /**
-     * Polls the provided JavaScript boolean until the timeout is reached or
+     * Polls the provided JavaScript boolean expression until the timeout is reached or
      * the boolean is true.
-     * @param boolName The name of the JavaScript boolean or expression to poll.
+     * @param boolExpression The JavaScript boolean expression to poll.
      * @param timeoutMs The polling timeout in milliseconds.
      * @param webContents The WebContents to run the JavaScript through.
      * @return True if the boolean evaluated to true, false if timed out.
      */
     public static boolean pollJavaScriptBoolean(
-            final String boolName, int timeoutMs, final WebContents webContents) {
+            final String boolExpression, int timeoutMs, final WebContents webContents) {
         try {
-            CriteriaHelper.pollInstrumentationThread(Criteria.equals(true, new Callable<Boolean>() {
-                @Override
-                public Boolean call() {
-                    String result = "false";
-                    try {
-                        result = JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
-                                boolName, POLL_CHECK_INTERVAL_SHORT_MS, TimeUnit.MILLISECONDS);
-                    } catch (InterruptedException | TimeoutException e) {
-                        // Expected to happen regularly, do nothing
-                    }
-                    return Boolean.parseBoolean(result);
+            CriteriaHelper.pollInstrumentationThread(() -> {
+                String result = "false";
+                try {
+                    result = JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
+                            boolExpression, POLL_CHECK_INTERVAL_SHORT_MS, TimeUnit.MILLISECONDS);
+                } catch (InterruptedException | TimeoutException e) {
+                    // Expected to happen regularly, do nothing
                 }
-            }), timeoutMs, POLL_CHECK_INTERVAL_LONG_MS);
+                return Boolean.parseBoolean(result);
+            }, "Polling timed out", timeoutMs, POLL_CHECK_INTERVAL_LONG_MS);
         } catch (AssertionError e) {
             Log.d(TAG, "pollJavaScriptBoolean() timed out");
             return false;
@@ -145,6 +140,19 @@
     }
 
     /**
+     * Polls the provided JavaScript boolean expression, failing the test if it does not evaluate
+     * to true within the provided timeout.
+     * @param boolExpression The JavaScript boolean expression to poll.
+     * @param timeoutMs The polling timeout in milliseconds.
+     * @param webContents The Webcontents to run the JavaScript through.
+     */
+    public static void pollJavaScriptBooleanOrFail(
+            String boolExpression, int timeoutMs, WebContents webContents) {
+        Assert.assertTrue("Timed out polling boolean expression: " + boolExpression,
+                pollJavaScriptBoolean(boolExpression, timeoutMs, webContents));
+    }
+
+    /**
      * Executes a JavaScript step function using the given WebContents.
      * @param stepFunction The JavaScript step function to call.
      * @param webContents The WebContents for the tab the JavaScript is in.
@@ -291,12 +299,21 @@
 
     /**
      * Helper function to run pollJavaScriptBoolean with the first tab's WebContents.
-     * @param boolName The name of the JavaScript boolean or expression to poll.
+     * @param boolExpression The JavaScript boolean expression to poll.
      * @param timeoutMs The polling timeout in milliseconds.
      * @return True if the boolean evaluated to true, false if timed out.
      */
-    public boolean pollJavaScriptBoolean(String boolName, int timeoutMs) {
-        return pollJavaScriptBoolean(boolName, timeoutMs, mFirstTabWebContents);
+    public boolean pollJavaScriptBoolean(String boolExpression, int timeoutMs) {
+        return pollJavaScriptBoolean(boolExpression, timeoutMs, mFirstTabWebContents);
+    }
+
+    /**
+     * Helper function to run pollJavaScriptBooleanOrFail with the first tab's WebContents.
+     * @param boolExpression The JavaScript boolean expression to poll.
+     * @param timeoutMs The polling timeout in milliseconds.
+     */
+    public void pollJavaScriptBooleanOrFail(String boolExpression, int timeoutMs) {
+        pollJavaScriptBooleanOrFail(boolExpression, timeoutMs, mFirstTabWebContents);
     }
 
     /**
@@ -353,11 +370,7 @@
         final Tab tab = getRule().getActivity().getActivityTab();
         ThreadUtils.runOnUiThreadBlocking(() -> tab.simulateRendererKilledForTesting(true));
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return tab.isShowingSadTab();
-            }
-        });
+        CriteriaHelper.pollUiThread(
+                () -> { return tab.isShowingSadTab(); }, "Renderer killed, but sad tab not shown");
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/HeadTrackingUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/HeadTrackingUtils.java
index 3068ce10..d8b6af6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/HeadTrackingUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/HeadTrackingUtils.java
@@ -134,7 +134,8 @@
         Intent poseIntent = new Intent(ACTION_SET_FAKE_TRACKER_POSE);
         poseIntent.putExtra(EXTRA_FAKE_TRACKER_POSE, pose.getDataForExtra());
         poseIntent.setComponent(HEAD_TRACKING_COMPONENT);
-        Assert.assertTrue(InstrumentationRegistry.getContext().startService(poseIntent) != null);
+        Assert.assertTrue("Could not set head pose",
+                InstrumentationRegistry.getContext().startService(poseIntent) != null);
         rule.setTrackerDirty();
         // TODO(bsheedy): Remove this sleep. Could either expose poses up to Java and wait until
         // we receive a pose that's the same as the one we set or see if the head tracking service
@@ -181,7 +182,8 @@
         Intent modeIntent = new Intent(ACTION_SET_FAKE_TRACKER_MODE);
         modeIntent.putExtra(EXTRA_FAKE_TRACKER_MODE, supportedModeToString(mode));
         modeIntent.setComponent(HEAD_TRACKING_COMPONENT);
-        Assert.assertTrue(InstrumentationRegistry.getContext().startService(modeIntent) != null);
+        Assert.assertTrue("Could not set head tracking mode",
+                InstrumentationRegistry.getContext().startService(modeIntent) != null);
         rule.setTrackerDirty();
     }
 
@@ -203,7 +205,8 @@
         Intent typeIntent = new Intent(ACTION_SET_TRACKER_TYPE);
         typeIntent.putExtra(EXTRA_TRACKER_TYPE, "fake");
         typeIntent.setComponent(HEAD_TRACKING_COMPONENT);
-        Assert.assertTrue(InstrumentationRegistry.getContext().startService(typeIntent) != null);
+        Assert.assertTrue("Could not restart head tracking service",
+                InstrumentationRegistry.getContext().startService(typeIntent) != null);
         rule.setTrackerDirty();
     }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java
index 94895cc..1fe0f3a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java
@@ -100,8 +100,10 @@
 
         // Wait for any outstanding animations to finish.
         resultLatch.await();
-        Assert.assertEquals(
-                VrUiTestActivityResult.QUIESCENT, instance.getLastUiActivityResultForTesting());
+        int uiResult = instance.getLastUiActivityResultForTesting();
+        Assert.assertEquals("UI reported non-quiescent result '"
+                        + vrUiTestActivityResultToString(uiResult) + "'",
+                VrUiTestActivityResult.QUIESCENT, uiResult);
     }
 
     /**
@@ -128,11 +130,11 @@
         VrShellImpl vrShell = (VrShellImpl) (TestVrShellDelegate.getVrShellForTesting());
         VrViewContainer viewContainer = vrShell.getVrViewContainerForTesting();
         Assert.assertTrue(
-                "VrViewContainer actually has children", viewContainer.getChildCount() > 0);
+                "VrViewContainer does not have children", viewContainer.getChildCount() > 0);
         // Click on whatever dialog was most recently added
         VrDialog vrDialog = (VrDialog) viewContainer.getChildAt(viewContainer.getChildCount() - 1);
         View button = vrDialog.findViewById(buttonId);
-        Assert.assertNotNull("Found a View with matching ID", button);
+        Assert.assertNotNull("Did not find view with specified ID", button);
         // Calculate the center of the button we want to click on and scale it to fit a unit square
         // centered on (0,0).
         float x = ((button.getX() + button.getWidth() / 2) - vrDialog.getWidth() / 2)
@@ -142,4 +144,19 @@
         PointF buttonCenter = new PointF(x, y);
         clickElementAndWaitForUiQuiescence(UserFriendlyElementName.BROWSING_DIALOG, buttonCenter);
     }
+
+    private static String vrUiTestActivityResultToString(int result) {
+        switch (result) {
+            case VrUiTestActivityResult.UNREPORTED:
+                return "Unreported";
+            case VrUiTestActivityResult.QUIESCENT:
+                return "Quiescent";
+            case VrUiTestActivityResult.TIMEOUT_NO_START:
+                return "Timeout (UI activity not started)";
+            case VrUiTestActivityResult.TIMEOUT_NO_END:
+                return "Timeout (UI activity not stopped)";
+            default:
+                return "Unknown result";
+        }
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NfcSimUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NfcSimUtils.java
index 31f59d5..478dd45 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NfcSimUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NfcSimUtils.java
@@ -13,7 +13,6 @@
 import android.nfc.NfcAdapter;
 
 import org.chromium.chrome.browser.vr.TestVrShellDelegate;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 import java.nio.ByteBuffer;
@@ -79,14 +78,11 @@
     public static void simNfcScanUntilVrEntry(final Context context) {
         final TestVrShellDelegate delegate = VrShellDelegateUtils.getDelegateInstance();
         delegate.setExpectingBroadcast();
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                if (!delegate.isExpectingBroadcast()) return true;
-                simNfcScan(context);
-                return false;
-            }
-        }, NFC_SCAN_TIMEOUT_MS, NFC_SCAN_INTERVAL_MS);
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            if (!delegate.isExpectingBroadcast()) return true;
+            simNfcScan(context);
+            return false;
+        }, "NFC failed to cause VR entry", NFC_SCAN_TIMEOUT_MS, NFC_SCAN_INTERVAL_MS);
     }
 
     private static byte[] intToByteArray(int i) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrBrowserTransitionUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrBrowserTransitionUtils.java
index 79b9ddd..a979aec 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrBrowserTransitionUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrBrowserTransitionUtils.java
@@ -19,7 +19,6 @@
 import org.chromium.chrome.browser.vr.VrMainActivity;
 import org.chromium.chrome.browser.vr.VrShellDelegate;
 import org.chromium.chrome.browser.vr.VrShellImpl;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 import java.util.concurrent.ExecutionException;
@@ -146,12 +145,9 @@
      * @param timeout How long in milliseconds to wait before timing out and failing.
      */
     public static void waitForNativeUiPrompt(final int timeout) {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                VrShellImpl vrShell = (VrShellImpl) TestVrShellDelegate.getVrShellForTesting();
-                return vrShell.isDisplayingDialogView();
-            }
-        }, timeout, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            VrShellImpl vrShell = (VrShellImpl) TestVrShellDelegate.getVrShellForTesting();
+            return vrShell.isDisplayingDialogView();
+        }, "Native UI prompt did not display", timeout, POLL_CHECK_INTERVAL_SHORT_MS);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrInfoBarUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrInfoBarUtils.java
index a859740..6dc4df8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrInfoBarUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrInfoBarUtils.java
@@ -11,11 +11,9 @@
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.util.InfoBarUtil;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 import java.util.List;
-import java.util.concurrent.Callable;
 
 /**
  * Class containing utility functions for interacting with InfoBars at
@@ -46,16 +44,13 @@
     public static void clickInfoBarButton(final Button button, ChromeActivityTestRule rule) {
         if (!isInfoBarPresent(rule)) return;
         final List<InfoBar> infoBars = rule.getInfoBars();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                switch (button) {
-                    case PRIMARY:
-                        InfoBarUtil.clickPrimaryButton(infoBars.get(0));
-                        break;
-                    default:
-                        InfoBarUtil.clickSecondaryButton(infoBars.get(0));
-                }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            switch (button) {
+                case PRIMARY:
+                    InfoBarUtil.clickPrimaryButton(infoBars.get(0));
+                    break;
+                default:
+                    InfoBarUtil.clickSecondaryButton(infoBars.get(0));
             }
         });
         InfoBarUtil.waitUntilNoInfoBarsExist(rule.getInfoBars());
@@ -69,12 +64,7 @@
     public static void clickInfobarCloseButton(ChromeActivityTestRule rule) {
         if (!isInfoBarPresent(rule)) return;
         final List<InfoBar> infoBars = rule.getInfoBars();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                InfoBarUtil.clickCloseButton(infoBars.get(0));
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(() -> { InfoBarUtil.clickCloseButton(infoBars.get(0)); });
         InfoBarUtil.waitUntilNoInfoBarsExist(rule.getInfoBars());
     }
 
@@ -83,12 +73,11 @@
      * @param rule The ChromeActivityTestRule to get the InfoBars from
      * @param present Whether an InfoBar should be present.
      */
-    public static void expectInfoBarPresent(final ChromeActivityTestRule rule, boolean present) {
-        CriteriaHelper.pollUiThread(Criteria.equals(present, new Callable<Boolean>() {
-            @Override
-            public Boolean call() {
-                return isInfoBarPresent(rule);
-            }
-        }), POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+    public static void expectInfoBarPresent(
+            final ChromeActivityTestRule rule, final boolean present) {
+        CriteriaHelper.pollUiThread(()
+                                            -> { return isInfoBarPresent(rule) == present; },
+                "InfoBar bar did not " + (present ? "appear" : "disappear"), POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java
index 150cba0..8751fa1e6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java
@@ -26,12 +26,8 @@
     public static TestVrShellDelegate getDelegateInstance() {
         final AtomicReference<TestVrShellDelegate> delegate =
                 new AtomicReference<TestVrShellDelegate>();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                delegate.set(TestVrShellDelegate.getInstance());
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { delegate.set(TestVrShellDelegate.getInstance()); });
         return delegate.get();
     }
 
@@ -46,14 +42,12 @@
     public static MockVrCoreVersionCheckerImpl setVrCoreCompatibility(int compatibility) {
         final MockVrCoreVersionCheckerImpl mockChecker = new MockVrCoreVersionCheckerImpl();
         mockChecker.setMockReturnValue(new VrCoreInfo(null, compatibility));
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                VrShellDelegateUtils.getDelegateInstance().overrideVrCoreVersionCheckerForTesting(
-                        mockChecker);
-            }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            VrShellDelegateUtils.getDelegateInstance().overrideVrCoreVersionCheckerForTesting(
+                    mockChecker);
         });
-        Assert.assertEquals(compatibility, mockChecker.getLastReturnValue().compatibility);
+        Assert.assertEquals("Overriding VrCoreVersionChecker failed", compatibility,
+                mockChecker.getLastReturnValue().compatibility);
         return mockChecker;
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTransitionUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTransitionUtils.java
index 6ac32dd..e602c58 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTransitionUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTransitionUtils.java
@@ -10,7 +10,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.vr.TestVrShellDelegate;
 import org.chromium.chrome.browser.vr.VrShellDelegate;
-import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 /**
@@ -38,23 +37,19 @@
      */
     public static void waitForVrEntry(final int timeout) {
         // Relatively long timeout because sometimes GVR takes a while to enter VR
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return VrShellDelegateUtils.getDelegateInstance().isVrEntryComplete();
-            }
-        }, timeout, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollUiThread(() -> {
+            return VrShellDelegateUtils.getDelegateInstance().isVrEntryComplete();
+        }, "VR not entered in allotted time", timeout, POLL_CHECK_INTERVAL_SHORT_MS);
     }
 
     /**
      * Waits for the black overlay that shows during VR Browser entry to be gone.
      */
     public static void waitForOverlayGone() {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !TestVrShellDelegate.getInstance().isBlackOverlayVisible();
-            }
-        }, POLL_TIMEOUT_SHORT_MS, POLL_CHECK_INTERVAL_SHORT_MS);
+        CriteriaHelper.pollUiThread(
+                ()
+                        -> { return !TestVrShellDelegate.getInstance().isBlackOverlayVisible(); },
+                "Black overlay did not disappear in allotted time", POLL_TIMEOUT_SHORT_MS,
+                POLL_CHECK_INTERVAL_SHORT_MS);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTestRuleUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTestRuleUtils.java
index 388f96c..153c9de 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTestRuleUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTestRuleUtils.java
@@ -64,7 +64,7 @@
      * Creates a RuleChain that applies the XrActivityRestrictionRule before the given XrTestRule.
      */
     public static RuleChain wrapRuleInXrActivityRestrictionRule(TestRule rule) {
-        Assert.assertTrue("Given rule is a XrTestRule", rule instanceof XrTestRule);
+        Assert.assertTrue("Given rule is not an XrTestRule", rule instanceof XrTestRule);
         return RuleChain
                 .outerRule(new XrActivityRestrictionRule(((XrTestRule) rule).getRestriction()))
                 .around(rule);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadResumptionSchedulerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadResumptionSchedulerTest.java
index 82c5bbe1..49997c8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadResumptionSchedulerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadResumptionSchedulerTest.java
@@ -15,8 +15,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.content.Context;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -26,7 +24,6 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -49,8 +46,6 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
 public class DownloadResumptionSchedulerTest {
-    Context mContext;
-
     @Mock
     private BackgroundTaskScheduler mScheduler;
 
@@ -59,7 +54,6 @@
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
         BackgroundTaskSchedulerFactory.setSchedulerForTesting(mScheduler);
     }
 
@@ -71,7 +65,7 @@
     @Test
     @Feature({"Download"})
     public void testCancelRequest() {
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).cancel();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().cancel();
 
         verify(mScheduler, never()).schedule(any(), any());
         verify(mScheduler, times(1)).cancel(any(), eq(TaskIds.DOWNLOAD_RESUMPTION_JOB_ID));
@@ -80,7 +74,7 @@
     @Test
     @Feature({"Download"})
     public void testScheduleRequestWithNoDownloads() {
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         verify(mScheduler, never()).schedule(any(), any());
         verify(mScheduler, times(1)).cancel(any(), eq(TaskIds.DOWNLOAD_RESUMPTION_JOB_ID));
@@ -93,7 +87,7 @@
                 buildEntry(false /* isAutoResumable */, false /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         verify(mScheduler, never()).schedule(any(), any());
         verify(mScheduler, times(1)).cancel(any(), eq(TaskIds.DOWNLOAD_RESUMPTION_JOB_ID));
@@ -106,7 +100,7 @@
                 buildEntry(true /* isAutoResumable */, false /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         ArgumentCaptor<TaskInfo> taskCaptor = ArgumentCaptor.forClass(TaskInfo.class);
         verify(mScheduler, times(1)).schedule(any(), taskCaptor.capture());
@@ -122,7 +116,7 @@
                 buildEntry(true /* isAutoResumable */, true /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         ArgumentCaptor<TaskInfo> taskCaptor = ArgumentCaptor.forClass(TaskInfo.class);
         verify(mScheduler, times(1)).schedule(any(), taskCaptor.capture());
@@ -139,7 +133,7 @@
                 buildEntry(true /* isAutoResumable */, false /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         ArgumentCaptor<TaskInfo> taskCaptor = ArgumentCaptor.forClass(TaskInfo.class);
         verify(mScheduler, times(1)).schedule(any(), taskCaptor.capture());
@@ -156,7 +150,7 @@
                 buildEntry(false /* isAutoResumable */, false /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         ArgumentCaptor<TaskInfo> taskCaptor = ArgumentCaptor.forClass(TaskInfo.class);
         verify(mScheduler, times(1)).schedule(any(), taskCaptor.capture());
@@ -173,7 +167,7 @@
                 buildEntry(false /* isAutoResumable */, false /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         ArgumentCaptor<TaskInfo> taskCaptor = ArgumentCaptor.forClass(TaskInfo.class);
         verify(mScheduler, times(1)).schedule(any(), taskCaptor.capture());
@@ -191,7 +185,7 @@
                 buildEntry(true /* isAutoResumable */, false /* meteredOk */),
         });
 
-        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).scheduleIfNecessary();
+        DownloadResumptionScheduler.getDownloadResumptionScheduler().scheduleIfNecessary();
 
         ArgumentCaptor<TaskInfo> taskCaptor = ArgumentCaptor.forClass(TaskInfo.class);
         verify(mScheduler, times(1)).schedule(any(), taskCaptor.capture());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java
index 37379b7..485a94a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java
@@ -150,7 +150,7 @@
     @Test
     @Feature({"Sync"})
     public void testStop() throws Exception {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.stop();
         Intent intent = getOnlyIntent();
         validateIntentComponent(intent);
@@ -165,7 +165,7 @@
     @Test
     @Feature({"Sync"})
     public void testEnsureStartedAndUpdateRegisteredTypes() {
-        InvalidationController controller = new InvalidationController(mActivity, false);
+        InvalidationController controller = new InvalidationController(false);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Intent intent = getOnlyIntent();
 
@@ -195,7 +195,7 @@
     public void testPauseAndResumeMainActivityWithSyncDisabled() throws Exception {
         AndroidSyncSettings.disableChromeSync();
 
-        InvalidationController controller = new InvalidationController(mActivity, false);
+        InvalidationController controller = new InvalidationController(false);
         controller.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES);
         controller.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
         assertNoNewIntents();
@@ -210,7 +210,7 @@
     public void testNullProfileSyncService() throws Exception {
         ProfileSyncService.overrideForTests(null);
 
-        InvalidationController controller = new InvalidationController(mActivity, false);
+        InvalidationController controller = new InvalidationController(false);
         controller.ensureStartedAndUpdateRegisteredTypes();
         assertNoNewIntents();
     }
@@ -224,7 +224,7 @@
         final AtomicBoolean listenerCallbackCalled = new AtomicBoolean();
 
         // Create instance.
-        new InvalidationController(mActivity, true) {
+        new InvalidationController(true) {
             @Override
             public void onApplicationStateChange(int newState) {
                 listenerCallbackCalled.set(true);
@@ -246,7 +246,7 @@
     @Test
     @Feature({"Sync"})
     public void testCannotToggleSessionInvalidations() {
-        InvalidationController controller = new InvalidationController(mActivity, false);
+        InvalidationController controller = new InvalidationController(false);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
 
@@ -270,7 +270,7 @@
     @Test
     @Feature({"Sync"})
     public void testRecentTabsPageShown() {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
 
@@ -291,7 +291,7 @@
     @Test
     @Feature({"Sync"})
     public void testStartWhileRecentTabsPageShown() {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.onRecentTabsPageOpened();
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
         assertNoNewIntents();
@@ -312,7 +312,7 @@
     @Test
     @Feature({"Sync"})
     public void testMultipleRecentTabsPages() {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
 
@@ -339,7 +339,7 @@
     @Test
     @Feature({"Sync"})
     public void testOpenCloseRecentTabsPageQuickly() {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
 
@@ -369,7 +369,7 @@
     @Test
     @Feature({"Sync"})
     public void testDisableSessionInvalidationsOnStart() {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
         controller.onRecentTabsPageOpened();
@@ -395,7 +395,7 @@
     @Test
     @Feature({"Sync"})
     public void testDisableSessionInvalidationsOnResume() {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
         controller.onRecentTabsPageOpened();
@@ -420,7 +420,7 @@
     @Test
     @Feature({"Sync"})
     public void testPauseAndResumeMainActivity() throws Exception {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
         controller.onRecentTabsPageOpened();
@@ -444,7 +444,7 @@
     @Test
     @Feature({"Sync"})
     public void testPauseAndResumeMainActivityAfterStop() throws Exception {
-        InvalidationController controller = new InvalidationController(mActivity, true);
+        InvalidationController controller = new InvalidationController(true);
         controller.ensureStartedAndUpdateRegisteredTypes();
         Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent()));
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 9619cd9..10d2a26 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4820,6 +4820,12 @@
   <message name="IDS_VOICE_INTERACTION_LOGO" desc="Logo label for voice interaction.">
     Google assistant logo
   </message>
+  <message name="IDS_ASSISTANT_HOTWORD_TITLE" desc="Title for assistant hotword optin.">
+    OK Google
+  </message>
+  <message name="IDS_ASSISTANT_HOTWORD_DESC" desc="Description for assistant hotword optin.">
+    Access your Assistant anytime you say "OK Google" when your device is awake and unlocked.
+  </message>
   <message name="IDS_ASSISTANT_SCREEN_CONTEXT_TITLE" desc="Title for assistant screen context optin.">
     Get info for what's on screen
   </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 7d0ad77..2bc240e 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -59,8 +59,8 @@
     <message name="IDS_SETTINGS_ABOUT_PAGE_RELAUNCH" desc="The label for the relaunch button that relaunches the browser once update is complete">
       Restart
     </message>
-    <message name="IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH" desc="The label for the  button that relaunches and powerwashes the browser once update is complete">
-      Relaunch and Powerwash
+    <message name="IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH" desc="The label for the button that relaunches and powerwashes the browser once update is complete">
+      Restart and reset
     </message>
     <message name="IDS_SETTINGS_ABOUT_TPM_FIRMWARE_UPDATE_TITLE" desc="Title for the line item on the about page that allows the user to trigger a device hardware reset and request installation of a TPM firmware update.">
       Powerwash for added security
@@ -83,6 +83,12 @@
     <message name="IDS_SETTINGS_UPGRADE_SUCCESSFUL_CHANNEL_SWITCH" desc="Status label: Channel was successfully switched on ChromiumOS/ChromeOS">
       Channel changed. Restart your device to apply changes.
     </message>
+    <message name="IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS" desc="Status label: Rolling back ChromiumOS or Chrome OS.">
+      Your administrator is rolling back this device (<ph name="PROGRESS_PERCENT">$1<ex>90%</ex></ph>)
+    </message>
+    <message name="IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS" desc="Status label: Successfully rolled back Chrome OS. All data on the device will be deleted during the next reboot.">
+      Your administrator rolled back this device. Please save important files, then restart. All data on the device will be deleted.
+    </message>
     <message name="IDS_SETTINGS_UPGRADE_UP_TO_DATE" desc="Status label: Already up to date (ChromiumOS/ChromeOS)">
       Your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> is up to date
     </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index dc3a3fc..dbbba00 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1831,7 +1831,6 @@
     "//content/public/common:buildflags",
     "//content/public/common:feature_h264_with_openh264_ffmpeg",
     "//content/public/common:service_names",
-    "//courgette:courgette_lib",
     "//crypto",
     "//crypto:platform",
     "//device/base",
@@ -2948,6 +2947,7 @@
       "//components/vector_icons",
       "//components/web_modal",
       "//components/zoom",
+      "//courgette:courgette_lib",
     ]
 
     if (is_posix || is_fuchsia) {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index a0dab63..86941fd 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3730,10 +3730,6 @@
      FEATURE_VALUE_TYPE(features::kBundledConnectionHelpFeature)},
 
 #if defined(OS_CHROMEOS)
-    {"ash-enable-new-overview-animations",
-     flag_descriptions::kAshEnableNewOverviewAnimationsName,
-     flag_descriptions::kAshEnableNewOverviewAnimationsDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kNewOverviewAnimations)},
     {"enable-experimental-crostini-ui",
      flag_descriptions::kExperimentalCrostiniUIName,
      flag_descriptions::kExperimentalCrostiniUIDescription, kOsCrOS,
diff --git a/chrome/browser/android/consent_auditor/consent_auditor_bridge.cc b/chrome/browser/android/consent_auditor/consent_auditor_bridge.cc
index e9fb3db3..7338740 100644
--- a/chrome/browser/android/consent_auditor/consent_auditor_bridge.cc
+++ b/chrome/browser/android/consent_auditor/consent_auditor_bridge.cc
@@ -25,13 +25,22 @@
     jint j_feature,
     const JavaParamRef<jintArray>& j_consent_description,
     jint j_consent_confirmation) {
+  // TODO(markusheintz): Update the ConsentAuditorBridgeInterface.
+  DCHECK_EQ(static_cast<consent_auditor::Feature>(j_feature),
+            consent_auditor::Feature::CHROME_SYNC);
+
   std::vector<int> consent_description;
   base::android::JavaIntArrayToIntVector(env, j_consent_description,
                                          &consent_description);
+
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  sync_consent.set_confirmation_grd_id(j_consent_confirmation);
+  for (int id : consent_description) {
+    sync_consent.add_description_grd_ids(id);
+  }
   ConsentAuditorFactory::GetForProfile(
       ProfileAndroid::FromProfileAndroid(j_profile))
-      ->RecordGaiaConsent(ConvertJavaStringToUTF8(j_account_id),
-                          static_cast<consent_auditor::Feature>(j_feature),
-                          consent_description, j_consent_confirmation,
-                          consent_auditor::ConsentStatus::GIVEN);
+      ->RecordSyncConsent(ConvertJavaStringToUTF8(j_account_id), sync_consent);
 }
diff --git a/chrome/browser/autofill/personal_data_manager_factory.cc b/chrome/browser/autofill/personal_data_manager_factory.cc
index e89d027..0fb296c 100644
--- a/chrome/browser/autofill/personal_data_manager_factory.cc
+++ b/chrome/browser/autofill/personal_data_manager_factory.cc
@@ -47,20 +47,15 @@
       new PersonalDataManager(g_browser_process->GetApplicationLocale());
   auto local_storage = WebDataServiceFactory::GetAutofillWebDataForProfile(
       profile, ServiceAccessType::EXPLICIT_ACCESS);
-  auto account_storage =
-      base::FeatureList::IsEnabled(
-          features::kAutofillEnableAccountWalletStorage)
-          ? WebDataServiceFactory::GetAutofillWebDataForAccount(
-                profile, ServiceAccessType::EXPLICIT_ACCESS)
-          : nullptr;
+  auto account_storage = WebDataServiceFactory::GetAutofillWebDataForAccount(
+      profile, ServiceAccessType::EXPLICIT_ACCESS);
   service->Init(local_storage, account_storage, profile->GetPrefs(),
                 IdentityManagerFactory::GetForProfile(profile),
                 profile->IsOffTheRecord());
   // For now, just tell the PersonalDataManager to use the account storage if
   // the feature flag is enabled.
   // TODO(feuunk): Set this based on whether we're in lightweight sync mode.
-  service->SetUseAccountStorageForServerCards(base::FeatureList::IsEnabled(
-      features::kAutofillEnableAccountWalletStorage));
+  service->SetUseAccountStorageForServerCards(account_storage != nullptr);
   return service;
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 3596b4a..1be17fd8 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -201,7 +201,6 @@
 #include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/services/heap_profiling/public/mojom/constants.mojom.h"
-#include "components/services/patch/public/interfaces/constants.mojom.h"
 #include "components/services/unzip/public/interfaces/constants.mojom.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/signin/core/browser/signin_manager_base.h"
@@ -371,6 +370,7 @@
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/ui/search/new_tab_page_navigation_throttle.h"
 #include "chrome/common/importer/profile_import.mojom.h"
+#include "components/services/patch/public/interfaces/constants.mojom.h"
 #endif
 
 #if defined(OS_LINUX) || defined(OS_WIN)
@@ -3683,8 +3683,10 @@
       &l10n_util::GetStringUTF16, IDS_UTILITY_PROCESS_FILE_UTILITY_NAME);
 #endif
 
+#if !defined(OS_ANDROID)
   (*services)[patch::mojom::kServiceName] = base::BindRepeating(
       &l10n_util::GetStringUTF16, IDS_UTILITY_PROCESS_PATCH_NAME);
+#endif
 
   (*services)[unzip::mojom::kServiceName] = base::BindRepeating(
       &l10n_util::GetStringUTF16, IDS_UTILITY_PROCESS_UNZIP_NAME);
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
index 7f7bb93..737ae96 100644
--- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_path_override.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h"
@@ -1880,14 +1881,16 @@
 }
 
 // Tests collecting device status for registered consumer device.
-class ConsumerDeviceStatusCollectorTest : public DeviceStatusCollectorTest {
+class ConsumerDeviceStatusCollectorTimeLimitDisabledTest
+    : public DeviceStatusCollectorTest {
  public:
-  ConsumerDeviceStatusCollectorTest() {
+  ConsumerDeviceStatusCollectorTimeLimitDisabledTest() {
     user_account_id_ = AccountId::FromUserEmail("user0@gmail.com");
     MockChildUser(user_account_id_);
+    scoped_feature_list_.InitAndDisableFeature(features::kUsageTimeLimitPolicy);
   }
 
-  ~ConsumerDeviceStatusCollectorTest() override = default;
+  ~ConsumerDeviceStatusCollectorTimeLimitDisabledTest() override = default;
 
  protected:
   void RestartStatusCollector(
@@ -1903,9 +1906,10 @@
   }
 
   AccountId user_account_id_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-TEST_F(ConsumerDeviceStatusCollectorTest, ReportingBootMode) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest, ReportingBootMode) {
   fake_statistics_provider_.SetMachineStatistic(
       chromeos::system::kDevSwitchBootKey,
       chromeos::system::kDevSwitchBootValueVerified);
@@ -1916,8 +1920,7 @@
   EXPECT_EQ("Verified", device_status_.boot_mode());
 }
 
-
-TEST_F(ConsumerDeviceStatusCollectorTest, ReportingArcStatus) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest, ReportingArcStatus) {
   RestartStatusCollector(
       base::BindRepeating(&GetEmptyVolumeInfo),
       base::BindRepeating(&GetEmptyCPUStatistics),
@@ -1936,7 +1939,8 @@
   EXPECT_EQ(user_account_id_.GetUserEmail(), session_status_.user_dm_token());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, ReportingPartialVersionInfo) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest,
+       ReportingPartialVersionInfo) {
   GetStatus();
 
   // Should only report OS version.
@@ -1946,7 +1950,8 @@
   EXPECT_FALSE(device_status_.has_tpm_version_info());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, NotReportingVolumeInfo) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest,
+       NotReportingVolumeInfo) {
   std::vector<std::string> expected_mount_points;
   std::vector<em::VolumeInfo> expected_volume_info;
   for (const auto& mount_info :
@@ -1976,7 +1981,7 @@
   EXPECT_EQ(0, device_status_.volume_info_size());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, NotReportingUsers) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest, NotReportingUsers) {
   const AccountId account_id0(AccountId::FromUserEmail("user0@gmail.com"));
   const AccountId account_id1(AccountId::FromUserEmail("user1@gmail.com"));
   user_manager_->AddUserWithAffiliationAndType(account_id0, true,
@@ -1989,7 +1994,8 @@
   EXPECT_EQ(0, device_status_.user_size());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, NotReportingOSUpdateStatus) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest,
+       NotReportingOSUpdateStatus) {
   MockPlatformVersion("1234.0.0");
   MockAutoLaunchKioskAppWithRequiredPlatformVersion(
       fake_kiosk_device_local_account_, "1234.0.0");
@@ -1999,7 +2005,8 @@
   EXPECT_FALSE(device_status_.has_os_update_status());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, NotReportingDeviceHardwareStatus) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest,
+       NotReportingDeviceHardwareStatus) {
   const std::string full_cpu_usage("cpu  500 0 500 0");
 
   std::vector<em::CPUTempInfo> expected_temp_info;
@@ -2028,7 +2035,7 @@
   EXPECT_FALSE(device_status_.has_system_ram_total());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, TimeZoneReporting) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest, TimeZoneReporting) {
   const std::string timezone =
       base::UTF16ToUTF8(chromeos::system::TimezoneSettings::GetInstance()
                             ->GetCurrentTimezoneID());
@@ -2039,7 +2046,8 @@
   EXPECT_EQ(timezone, session_status_.time_zone());
 }
 
-TEST_F(ConsumerDeviceStatusCollectorTest, ActivityTimesFeatureDisable) {
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest,
+       ActivityTimesFeatureDisable) {
   settings_helper_.SetBoolean(chromeos::kReportDeviceActivityTimes, true);
   settings_helper_.SetBoolean(chromeos::kReportDeviceUsers, true);
   ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
@@ -2053,7 +2061,7 @@
 // Tests collecting device status for registered consumer device when time
 // limit feature is enabled.
 class ConsumerDeviceStatusCollectorTimeLimitEnabledTest
-    : public ConsumerDeviceStatusCollectorTest {
+    : public ConsumerDeviceStatusCollectorTimeLimitDisabledTest {
  public:
   ConsumerDeviceStatusCollectorTimeLimitEnabledTest() {
     scoped_feature_list_.InitAndEnableFeature(features::kUsageTimeLimitPolicy);
diff --git a/chrome/browser/chromeos/upgrade_detector_chromeos.cc b/chrome/browser/chromeos/upgrade_detector_chromeos.cc
index fc1a76f..efd87ae 100644
--- a/chrome/browser/chromeos/upgrade_detector_chromeos.cc
+++ b/chrome/browser/chromeos/upgrade_detector_chromeos.cc
@@ -146,7 +146,7 @@
     set_upgrade_detected_time(tick_clock()->NowTicks());
 
     if (status.is_rollback) {
-      set_is_factory_reset_required(true);
+      set_is_rollback(true);
       NotifyOnUpgrade();
     } else {
       // Determine whether powerwash is required based on the channel.
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
index e2e6b447..28fdfc3 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
@@ -123,6 +123,30 @@
   return result;
 }
 
+// Inserts a module into |modules|. Also does the type conversion.
+void InsertPackedListModule(
+    ModuleInfoKey module_key,
+    std::vector<third_party_dlls::PackedListModule>* modules) {
+  DCHECK(modules);
+
+  // Do the insertion.
+  modules->emplace_back();
+  third_party_dlls::PackedListModule& module = modules->back();
+
+  // Hash the basename.
+  const std::string module_basename = base::UTF16ToUTF8(
+      base::i18n::ToLower(module_key.module_path.BaseName().value()));
+  base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_basename.data()),
+                      module_basename.length(), module.basename_hash);
+
+  // Hash the code id.
+  const std::string module_code_id = GenerateCodeId(module_key);
+  base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_code_id.data()),
+                      module_code_id.length(), module.code_id_hash);
+
+  module.time_date_stamp = CalculateTimeDateStamp(base::Time::Now());
+}
+
 }  // namespace
 
 // static
@@ -140,11 +164,6 @@
       background_sequence_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BACKGROUND,
            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
-      // The use of base::Unretained() is safe here because the callback can
-      // only be invoked while |module_load_attempt_log_listener_| is alive.
-      module_load_attempt_log_listener_(
-          base::BindRepeating(&ModuleBlacklistCacheUpdater::OnNewModulesBlocked,
-                              base::Unretained(this))),
       weak_ptr_factory_(this) {
   DCHECK(module_list_filter_);
   module_database_event_source_->AddObserver(this);
@@ -189,6 +208,14 @@
   if (module_key.module_id + 1 > module_blocking_decisions_.size())
     module_blocking_decisions_.resize(module_key.module_id + 1);
 
+  if (module_data.module_properties & ModuleInfoData::kPropertyBlocked) {
+    InsertPackedListModule(module_key, &blocked_modules_);
+
+    module_blocking_decisions_[module_key.module_id] =
+        ModuleBlockingDecision::kBlocked;
+    return;
+  }
+
   // Only consider loaded modules.
   if ((module_data.module_properties & ModuleInfoData::kPropertyLoadedModule) ==
       0) {
@@ -261,22 +288,7 @@
       ModuleBlockingDecision::kBlacklisted;
 
   // Insert the blacklisted module.
-  newly_blacklisted_modules_.emplace_back();
-  third_party_dlls::PackedListModule& module =
-      newly_blacklisted_modules_.back();
-
-  // Hash the basename.
-  const std::string module_basename = base::UTF16ToUTF8(
-      base::i18n::ToLower(module_key.module_path.BaseName().value()));
-  base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_basename.data()),
-                      module_basename.length(), module.basename_hash);
-
-  // Hash the code id.
-  const std::string module_code_id = GenerateCodeId(module_key);
-  base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(module_code_id.data()),
-                      module_code_id.length(), module.code_id_hash);
-
-  module.time_date_stamp = CalculateTimeDateStamp(base::Time::Now());
+  InsertPackedListModule(module_key, &newly_blacklisted_modules_);
 
   // Signal the module database that this module will be added to the cache.
   // Note that observers that care about this information should register to
@@ -304,21 +316,6 @@
   StartModuleBlacklistCacheUpdate();
 }
 
-void ModuleBlacklistCacheUpdater::OnNewModulesBlocked(
-    std::vector<third_party_dlls::PackedListModule>&& blocked_modules) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  blocked_modules_.insert(blocked_modules_.begin(),
-                          std::make_move_iterator(blocked_modules.begin()),
-                          std::make_move_iterator(blocked_modules.end()));
-
-  // Start the timer.
-  timer_.Start(FROM_HERE,
-               kUpdateTimerDuration,
-               base::Bind(&ModuleBlacklistCacheUpdater::OnTimerExpired,
-                          base::Unretained(this)));
-}
-
 ModuleBlacklistCacheUpdater::ModuleBlockingDecision
 ModuleBlacklistCacheUpdater::GetModuleBlockingDecision(
     ModuleInfoKey module_key) const {
@@ -337,8 +334,6 @@
 void ModuleBlacklistCacheUpdater::StartModuleBlacklistCacheUpdate() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  timer_.Stop();
-
   base::FilePath cache_file_path = GetModuleBlacklistCachePath();
   if (cache_file_path.empty())
     return;
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
index cad149e..846cd9f2 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
@@ -16,7 +16,6 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/conflicts/module_database_observer_win.h"
-#include "chrome/browser/conflicts/module_load_attempt_log_listener_win.h"
 #include "chrome/browser/conflicts/proto/module_list.pb.h"
 #include "chrome_elf/third_party_dlls/packed_list_format.h"
 
@@ -99,6 +98,8 @@
     kTolerated,
     // Blacklisted and will be blocked next launch.
     kBlacklisted,
+    // The module was blocked from loading into the process.
+    kBlocked,
   };
 
   struct CacheUpdateResult {
@@ -143,10 +144,6 @@
                            const ModuleInfoData& module_data) override;
   void OnModuleDatabaseIdle() override;
 
-  // Callback for |module_load_attempt_log_listener_|;
-  void OnNewModulesBlocked(
-      std::vector<third_party_dlls::PackedListModule>&& blocked_modules);
-
   // Returns the blocking decision for a module.
   ModuleBlockingDecision GetModuleBlockingDecision(
       ModuleInfoKey module_key) const;
@@ -174,8 +171,6 @@
   // module blacklist cache.
   std::vector<third_party_dlls::PackedListModule> newly_blacklisted_modules_;
 
-  ModuleLoadAttemptLogListener module_load_attempt_log_listener_;
-
   // Temporarily holds modules that were blocked from loading into the browser
   // until they are used to update the cache.
   std::vector<third_party_dlls::PackedListModule> blocked_modules_;
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
index afbf4e98..c8a662f 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
@@ -351,25 +351,3 @@
 
   EXPECT_TRUE(internal::ModuleEqual()(expected, blacklisted_modules[0]));
 }
-
-// This tests that if a new blocked load attempt arrives, an update will still
-// be triggered even if the Module Database never goes idle afterwards.
-TEST_F(ModuleBlacklistCacheUpdaterTest, NewModulesBlockedOnly) {
-  EXPECT_FALSE(base::PathExists(module_blacklist_cache_path()));
-
-  auto module_blacklist_cache_updater = CreateModuleBlacklistCacheUpdater();
-
-  // Simulate a new blocked load attempt.
-  std::vector<third_party_dlls::PackedListModule> blocked_modules;
-  const third_party_dlls::PackedListModule module = {
-      {}, {}, 123456u,
-  };
-  blocked_modules.push_back(module);
-  module_blacklist_cache_updater->OnNewModulesBlocked(
-      std::move(blocked_modules));
-
-  FastForwardBy(ModuleBlacklistCacheUpdater::kUpdateTimerDuration);
-  EXPECT_TRUE(base::PathExists(module_blacklist_cache_path()));
-  EXPECT_TRUE(on_cache_updated_callback_invoked());
-  EXPECT_TRUE(RegistryKeyExists());
-}
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index 3b5bfab..07d6662a 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -51,8 +51,13 @@
       has_started_processing_(false),
       shell_extensions_enumerated_(false),
       ime_enumerated_(false),
-      // ModuleDatabase owns |module_inspector_|, so it is safe to use
-      // base::Unretained().
+// ModuleDatabase owns both |module_load_attempt_log_listener_| and
+// |module_inspector_|, so it is safe to use base::Unretained().
+#if defined(GOOGLE_CHROME_BUILD)
+      module_load_attempt_log_listener_(
+          base::BindRepeating(&ModuleDatabase::OnModuleBlocked,
+                              base::Unretained(this))),
+#endif  // defined(GOOGLE_CHROME_BUILD)
       module_inspector_(base::Bind(&ModuleDatabase::OnModuleInspected,
                                    base::Unretained(this))) {
   AddObserver(&third_party_metrics_);
@@ -176,6 +181,16 @@
   }
 }
 
+void ModuleDatabase::OnModuleBlocked(const base::FilePath& module_path,
+                                     uint32_t module_size,
+                                     uint32_t module_time_date_stamp) {
+  ModuleInfo* module_info = nullptr;
+  FindOrCreateModuleInfo(module_path, module_size, module_time_date_stamp,
+                         &module_info);
+
+  module_info->second.module_properties |= ModuleInfoData::kPropertyBlocked;
+}
+
 void ModuleDatabase::OnModuleAddedToBlacklist(const base::FilePath& module_path,
                                               uint32_t module_size,
                                               uint32_t module_time_date_stamp) {
diff --git a/chrome/browser/conflicts/module_database_win.h b/chrome/browser/conflicts/module_database_win.h
index 4c1f084..b1705a3 100644
--- a/chrome/browser/conflicts/module_database_win.h
+++ b/chrome/browser/conflicts/module_database_win.h
@@ -18,6 +18,10 @@
 #include "chrome/browser/conflicts/third_party_metrics_recorder_win.h"
 #include "content/public/common/process_type.h"
 
+#if defined(GOOGLE_CHROME_BUILD)
+#include "chrome/browser/conflicts/module_load_attempt_log_listener_win.h"
+#endif
+
 class ModuleDatabaseObserver;
 
 #if defined(GOOGLE_CHROME_BUILD)
@@ -98,6 +102,10 @@
                     uint32_t module_time_date_stamp,
                     uintptr_t module_load_address);
 
+  void OnModuleBlocked(const base::FilePath& module_path,
+                       uint32_t module_size,
+                       uint32_t module_time_date_stamp);
+
   // Marks the module as added to the module blacklist cache, which means it
   // will be blocked on the next browser launch.
   void OnModuleAddedToBlacklist(const base::FilePath& module_path,
@@ -221,6 +229,10 @@
   // Indicates if all input method editors have been enumerated.
   bool ime_enumerated_;
 
+#if defined(GOOGLE_CHROME_BUILD)
+  ModuleLoadAttemptLogListener module_load_attempt_log_listener_;
+#endif
+
   // Inspects new modules on a blocking task runner.
   ModuleInspector module_inspector_;
 
diff --git a/chrome/browser/conflicts/module_info_win.h b/chrome/browser/conflicts/module_info_win.h
index 2ee4d77c..438a4843 100644
--- a/chrome/browser/conflicts/module_info_win.h
+++ b/chrome/browser/conflicts/module_info_win.h
@@ -89,6 +89,8 @@
     kPropertyIme = 1 << 2,
     // The module was added to the module blacklist cache.
     kPropertyAddedToBlacklist = 1 << 3,
+    // These modules were blocked from loading into the process.
+    kPropertyBlocked = 1 << 4,
   };
 
   ModuleInfoData();
diff --git a/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc b/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc
index 89e77a2..9d26544 100644
--- a/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc
+++ b/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc
@@ -7,12 +7,13 @@
 #include <algorithm>
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/i18n/case_conversion.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/sha1.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
 #include "base/task_scheduler/post_task.h"
@@ -22,7 +23,12 @@
 
 namespace {
 
-std::vector<third_party_dlls::PackedListModule> DrainLogOnBackgroundTask() {
+// Drains the log of blocked modules from chrome_elf.dll.
+// Note that the paths returned are device paths, which starts with
+// "\Device\Harddisk". They need to be translated to their drive letter path
+// equivalent.
+std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>>
+DrainLogOnBackgroundTask() {
   // Query the number of bytes needed.
   uint32_t bytes_needed = 0;
   DrainLog(nullptr, 0, &bytes_needed);
@@ -32,10 +38,8 @@
   uint32_t bytes_written = DrainLog(buffer.get(), bytes_needed, nullptr);
   DCHECK_EQ(bytes_needed, bytes_written);
 
-  auto now_time_date_stamp = CalculateTimeDateStamp(base::Time::Now());
-
   // Parse the data using the recommanded pattern for iterating over the log.
-  std::vector<third_party_dlls::PackedListModule> blocked_modules;
+  std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>> blocked_modules;
   uint8_t* tracker = buffer.get();
   uint8_t* buffer_end = buffer.get() + bytes_written;
   while (tracker < buffer_end) {
@@ -51,29 +55,9 @@
     if (entry->type == third_party_dlls::LogType::kBlocked) {
       // No log path should be empty.
       DCHECK(entry->path_len);
-      blocked_modules.emplace_back();
-      third_party_dlls::PackedListModule& module = blocked_modules.back();
-      // Fill in a PackedListModule from the log entry.
-      std::string hash_string =
-          base::SHA1HashString(third_party_dlls::GetFingerprintString(
-              entry->time_date_stamp, entry->module_size));
-      std::copy(std::begin(hash_string), std::end(hash_string),
-                std::begin(module.code_id_hash));
-      // |entry->path| is a UTF-8 device path.  A hash of the
-      // lowercase, UTF-8 basename is needed for |module.basename_hash|.
-      base::FilePath file_path(base::UTF8ToUTF16(entry->path));
-      std::wstring basename = base::i18n::ToLower(file_path.BaseName().value());
-      hash_string = base::UTF16ToUTF8(basename);
-      hash_string = base::SHA1HashString(hash_string);
-      std::copy(std::begin(hash_string), std::end(hash_string),
-                std::begin(module.basename_hash));
-      module.time_date_stamp = now_time_date_stamp;
-
-      // TODO(pmonette): |file_path| is ready for
-      //                 base::DevicePathToDriveLetterPath() here if needed.
-      //                 Consider making these path conversions more efficient
-      //                 by caching the local mounted devices and corresponding
-      //                 drive paths once.
+      blocked_modules.emplace_back(
+          base::UTF8ToUTF16(base::StringPiece(entry->path, entry->path_len)),
+          entry->module_size, entry->time_date_stamp);
     }
 
     tracker += third_party_dlls::GetLogEntrySize(entry->path_len);
@@ -85,9 +69,8 @@
 }  // namespace
 
 ModuleLoadAttemptLogListener::ModuleLoadAttemptLogListener(
-    OnNewModulesBlockedCallback on_new_modules_blocked_callback)
-    : on_new_modules_blocked_callback_(
-          std::move(on_new_modules_blocked_callback)),
+    OnModuleBlockedCallback on_module_blocked_callback)
+    : on_module_blocked_callback_(std::move(on_module_blocked_callback)),
       background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::TaskPriority::BACKGROUND,
            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN,
@@ -118,6 +101,69 @@
 }
 
 void ModuleLoadAttemptLogListener::OnLogDrained(
-    std::vector<third_party_dlls::PackedListModule>&& blocked_modules) {
-  on_new_modules_blocked_callback_.Run(std::move(blocked_modules));
+    std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>>&&
+        blocked_modules) {
+  for (auto& entry : blocked_modules) {
+    // Translate the device path to their drive letter equivalent then notify
+    // via the callback. The callback is invoked regardless of the result of
+    // GetDriveLetterPath() so that the module still shows up in
+    // chrome://conflicts.
+    base::FilePath module_path = std::move(std::get<0>(entry));
+    bool drive_letter_path_found =
+        GetDriveLetterPath(module_path, &module_path);
+    UMA_HISTOGRAM_BOOLEAN("ThirdPartyModules.GetDriveLetterPathFound",
+                          drive_letter_path_found);
+    on_module_blocked_callback_.Run(std::move(module_path), std::get<1>(entry),
+                                    std::get<2>(entry));
+  }
+}
+
+bool ModuleLoadAttemptLogListener::GetDriveLetterPath(
+    const base::FilePath& device_path,
+    base::FilePath* drive_letter_path) {
+  for (size_t retry_count = 0; retry_count < 2; ++retry_count) {
+    // Only update the mapping if a matching device root wasn't found.
+    if (retry_count > 0)
+      UpdateDeviceToLetterPathMapping();
+
+    for (const auto& element : device_to_letter_path_mapping_) {
+      const base::FilePath& device_root = element.first;
+      const base::string16& drive_letter_root = element.second;
+      if (device_root.IsParent(device_path)) {
+        *drive_letter_path = base::FilePath(
+            drive_letter_root +
+            device_path.value().substr(device_root.value().length()));
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+void ModuleLoadAttemptLogListener::UpdateDeviceToLetterPathMapping() {
+  const int kDriveMappingSize = 1024;
+  wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
+  if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping))
+    return;
+
+  device_to_letter_path_mapping_.clear();
+
+  wchar_t* drive_map_ptr = drive_mapping;
+  wchar_t device_path_as_string[MAX_PATH];
+  wchar_t drive[] = L" :";
+
+  while (*drive_map_ptr) {
+    drive[0] = drive_map_ptr[0];  // Copy the drive letter.
+
+    if (::QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
+      device_to_letter_path_mapping_.emplace_back(
+          base::FilePath(device_path_as_string), drive);
+    }
+
+    // Move to the next drive letter string, which starts one
+    // increment after the '\0' that terminates the current string.
+    while (*drive_map_ptr++) {
+    }
+  }
 }
diff --git a/chrome/browser/conflicts/module_load_attempt_log_listener_win.h b/chrome/browser/conflicts/module_load_attempt_log_listener_win.h
index 468d8588..4538db3 100644
--- a/chrome/browser/conflicts/module_load_attempt_log_listener_win.h
+++ b/chrome/browser/conflicts/module_load_attempt_log_listener_win.h
@@ -5,9 +5,12 @@
 #ifndef CHROME_BROWSER_CONFLICTS_MODULE_LOAD_ATTEMPT_LOG_LISTENER_WIN_H_
 #define CHROME_BROWSER_CONFLICTS_MODULE_LOAD_ATTEMPT_LOG_LISTENER_WIN_H_
 
+#include <tuple>
+#include <utility>
 #include <vector>
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/waitable_event.h"
@@ -23,11 +26,13 @@
 // notifies its delegate for all modules that were blocked.
 class ModuleLoadAttemptLogListener : public base::win::ObjectWatcher::Delegate {
  public:
-  using OnNewModulesBlockedCallback = base::RepeatingCallback<void(
-      std::vector<third_party_dlls::PackedListModule>&& blocked_modules)>;
+  using OnModuleBlockedCallback =
+      base::RepeatingCallback<void(const base::FilePath& module_path,
+                                   uint32_t module_size,
+                                   uint32_t module_time_date_stamp)>;
 
   explicit ModuleLoadAttemptLogListener(
-      OnNewModulesBlockedCallback on_new_modules_blocked_callback);
+      OnModuleBlockedCallback on_module_blocked_callback);
   ~ModuleLoadAttemptLogListener() override;
 
   // base::win::ObjectWatcher::Delegate:
@@ -37,10 +42,20 @@
   void StartDrainingLogs();
 
   void OnLogDrained(
-      std::vector<third_party_dlls::PackedListModule>&& blocked_modules);
+      std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>>&&
+          blocked_modules);
 
-  // Invoked everytime the log is drained with the new blocked entries.
-  OnNewModulesBlockedCallback on_new_modules_blocked_callback_;
+  // Translates a path of the form "\Device\HarddiskVolumeXX\..." into its
+  // equivalent that starts with a drive letter ("C:\..."). Returns false on
+  // failure.
+  bool GetDriveLetterPath(const base::FilePath& device_path,
+                          base::FilePath* drive_letter_path);
+
+  // Update the |device_to_letter_path_mapping_|.
+  void UpdateDeviceToLetterPathMapping();
+
+  // Invoked once per blocked module every time the log is drained.
+  OnModuleBlockedCallback on_module_blocked_callback_;
 
   // The sequence in which the log is drained.
   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
@@ -51,6 +66,11 @@
   // Watches |waitable_event_|.
   base::win::ObjectWatcher object_watcher_;
 
+  // A cache of the mapping of device path roots to their drive letter root
+  // equivalent.
+  std::vector<std::pair<base::FilePath, base::string16>>
+      device_to_letter_path_mapping_;
+
   base::WeakPtrFactory<ModuleLoadAttemptLogListener> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ModuleLoadAttemptLogListener);
diff --git a/chrome/browser/conflicts/module_load_attempt_log_listener_win_unittest.cc b/chrome/browser/conflicts/module_load_attempt_log_listener_win_unittest.cc
index 40337cd..4000404b 100644
--- a/chrome/browser/conflicts/module_load_attempt_log_listener_win_unittest.cc
+++ b/chrome/browser/conflicts/module_load_attempt_log_listener_win_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/conflicts/module_load_attempt_log_listener_win.h"
 
 #include <memory>
+#include <tuple>
 #include <utility>
 
 #include "base/bind.h"
@@ -23,15 +24,17 @@
 
   std::unique_ptr<ModuleLoadAttemptLogListener>
   CreateModuleLoadAttemptLogListener() {
-    return std::make_unique<ModuleLoadAttemptLogListener>(base::BindRepeating(
-        &ModuleLoadAttemptLogListenerTest::OnNewModulesBlocked,
-        base::Unretained(this)));
+    return std::make_unique<ModuleLoadAttemptLogListener>(
+        base::BindRepeating(&ModuleLoadAttemptLogListenerTest::OnModuleBlocked,
+                            base::Unretained(this)));
   }
 
   // ModuleLoadAttemptLogListener::Delegate:
-  void OnNewModulesBlocked(
-      std::vector<third_party_dlls::PackedListModule>&& blocked_modules) {
-    blocked_modules_ = std::move(blocked_modules);
+  void OnModuleBlocked(const base::FilePath& module_path,
+                       uint32_t module_size,
+                       uint32_t module_time_date_stamp) {
+    blocked_modules_.emplace_back(module_path, module_size,
+                                  module_time_date_stamp);
 
     notified_ = true;
 
@@ -48,7 +51,8 @@
     run_loop.Run();
   }
 
-  const std::vector<third_party_dlls::PackedListModule>& blocked_modules() {
+  const std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>>&
+  blocked_modules() {
     return blocked_modules_;
   }
 
@@ -59,7 +63,7 @@
 
   base::Closure quit_closure_;
 
-  std::vector<third_party_dlls::PackedListModule> blocked_modules_;
+  std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>> blocked_modules_;
 
   DISALLOW_COPY_AND_ASSIGN(ModuleLoadAttemptLogListenerTest);
 };
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index ea4e2fa..bbc87c4 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -36,6 +36,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_channel.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -337,6 +338,7 @@
       GURL("chrome://version"),
       GURL("chrome://newtab"),
       GURL("http://[2607:f8b0:4005:805::200e]"),
+      ExtensionsClient::Get()->GetWebstoreBaseURL(),
       extension->GetResourceURL("test.html"),
       another_extension->GetResourceURL("test.html"),
   };
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 27e3b46..4d31e90 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/extensions/chrome_zipfile_installer.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/devtools_util.h"
+#include "chrome/browser/extensions/error_console/error_console_factory.h"
 #include "chrome/browser/extensions/extension_commands_global_registry.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
@@ -52,7 +53,9 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
@@ -66,15 +69,20 @@
 #include "extensions/browser/content_verifier.h"
 #include "extensions/browser/disable_reason.h"
 #include "extensions/browser/error_map.h"
+#include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extension_error.h"
 #include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_prefs_factory.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_registry_factory.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/file_highlighter.h"
 #include "extensions/browser/management_policy.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/browser/path_util.h"
+#include "extensions/browser/process_manager_factory.h"
 #include "extensions/browser/warning_service.h"
+#include "extensions/browser/warning_service_factory.h"
 #include "extensions/browser/zipfile_installer.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/feature_switch.h"
@@ -302,6 +310,20 @@
   return g_developer_private_api_factory.Pointer();
 }
 
+template <>
+void BrowserContextKeyedAPIFactory<
+    DeveloperPrivateAPI>::DeclareFactoryDependencies() {
+  DependsOn(ExtensionRegistryFactory::GetInstance());
+  DependsOn(ErrorConsoleFactory::GetInstance());
+  DependsOn(ProcessManagerFactory::GetInstance());
+  DependsOn(AppWindowRegistry::Factory::GetInstance());
+  DependsOn(WarningServiceFactory::GetInstance());
+  DependsOn(ExtensionPrefsFactory::GetInstance());
+  DependsOn(ExtensionManagementFactory::GetInstance());
+  DependsOn(CommandService::GetFactoryInstance());
+  DependsOn(EventRouterFactory::GetInstance());
+}
+
 // static
 DeveloperPrivateAPI* DeveloperPrivateAPI::Get(
     content::BrowserContext* context) {
@@ -341,6 +363,9 @@
       prefs::kExtensionsUIDeveloperMode,
       base::Bind(&DeveloperPrivateEventRouter::OnProfilePrefChanged,
                  base::Unretained(this)));
+  notification_registrar_.Add(
+      this, extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
+      content::Source<Profile>(profile_));
 }
 
 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
@@ -463,6 +488,18 @@
     BroadcastItemStateChanged(developer::EVENT_TYPE_WARNINGS_CHANGED, id);
 }
 
+void DeveloperPrivateEventRouter::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK_EQ(NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, type);
+
+  UpdatedExtensionPermissionsInfo* info =
+      content::Details<UpdatedExtensionPermissionsInfo>(details).ptr();
+  BroadcastItemStateChanged(developer::EVENT_TYPE_PERMISSIONS_CHANGED,
+                            info->extension->id());
+}
+
 void DeveloperPrivateEventRouter::OnProfilePrefChanged() {
   std::unique_ptr<base::ListValue> args(new base::ListValue());
   args->Append(CreateProfileInfo(profile_)->ToValue());
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 1d59e38..8edc8cc 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -23,6 +23,8 @@
 #include "chrome/common/extensions/api/developer_private.h"
 #include "chrome/common/extensions/webstore_install_result.h"
 #include "components/prefs/pref_change_registrar.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -59,7 +61,8 @@
                                     public CommandService::Observer,
                                     public ExtensionPrefsObserver,
                                     public ExtensionManagement::Observer,
-                                    public WarningService::Observer {
+                                    public WarningService::Observer,
+                                    public content::NotificationObserver {
  public:
   explicit DeveloperPrivateEventRouter(Profile* profile);
   ~DeveloperPrivateEventRouter() override;
@@ -115,6 +118,11 @@
   void ExtensionWarningsChanged(
       const ExtensionIdSet& affected_extensions) override;
 
+  // content::NotificationObserver:
+  void Observe(int notification_type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
   // Handles a profile preferance change.
   void OnProfilePrefChanged();
 
@@ -157,6 +165,8 @@
 
   PrefChangeRegistrar pref_change_registrar_;
 
+  content::NotificationRegistrar notification_registrar_;
+
   base::WeakPtrFactory<DeveloperPrivateEventRouter> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateEventRouter);
@@ -267,6 +277,10 @@
   DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateAPI);
 };
 
+template <>
+void BrowserContextKeyedAPIFactory<
+    DeveloperPrivateAPI>::DeclareFactoryDependencies();
+
 namespace api {
 
 class DeveloperPrivateAPIFunction : public UIThreadExtensionFunction {
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index e5c2c388..dc072d6 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_with_install.h"
 #include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/permissions_updater.h"
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
@@ -41,6 +43,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/web_contents_tester.h"
 #include "extensions/browser/api_test_utils.h"
+#include "extensions/browser/event_router.h"
 #include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_error_test_util.h"
@@ -51,12 +54,14 @@
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/install/extension_install_ui.h"
 #include "extensions/browser/mock_external_provider.h"
+#include "extensions/browser/test_event_router_observer.h"
 #include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_features.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/value_builder.h"
 #include "extensions/test/test_extension_dir.h"
 #include "services/data_decoder/data_decoder_service.h"
@@ -1494,6 +1499,66 @@
   EXPECT_FALSE(modifier.HasGrantedHostPermission(example_com));
 }
 
+TEST_F(DeveloperPrivateApiUnitTest, ExtensionUpdatedEventOnPermissionsChange) {
+  DeveloperPrivateAPI::Get(profile());
+  const ExtensionId listener_id = crx_file::id_util::GenerateId("listener");
+  EventRouter* event_router = EventRouter::Get(profile());
+
+  content::RenderProcessHost* process = nullptr;
+  const char* kEventName =
+      api::developer_private::OnItemStateChanged::kEventName;
+  event_router->AddEventListener(kEventName, process, listener_id);
+
+  scoped_refptr<const Extension> dummy_extension =
+      ExtensionBuilder("dummy")
+          .SetManifestKey("optional_permissions",
+                          ListBuilder().Append("tabs").Build())
+          .Build();
+
+  TestEventRouterObserver test_observer(event_router);
+  auto dispatched_updated_event = [&test_observer, kEventName,
+                                   &dummy_extension]() {
+    const auto& event_map = test_observer.events();
+    auto iter = event_map.find(kEventName);
+    if (iter == event_map.end())
+      return false;
+
+    const Event& event = *iter->second;
+    CHECK(event.event_args);
+    CHECK_GE(1u, event.event_args->GetList().size());
+    std::unique_ptr<api::developer_private::EventData> event_data =
+        api::developer_private::EventData::FromValue(
+            event.event_args->GetList()[0]);
+    if (!event_data)
+      return false;
+
+    if (event_data->item_id != dummy_extension->id() ||
+        event_data->event_type !=
+            api::developer_private::EVENT_TYPE_PERMISSIONS_CHANGED) {
+      return false;
+    }
+
+    return true;
+  };
+  EXPECT_FALSE(dispatched_updated_event());
+
+  APIPermissionSet apis;
+  apis.insert(APIPermission::kTab);
+  PermissionSet permissions(apis, ManifestPermissionSet(), URLPatternSet(),
+                            URLPatternSet());
+  PermissionsUpdater(profile()).GrantOptionalPermissions(*dummy_extension,
+                                                         permissions);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(dispatched_updated_event());
+
+  test_observer.ClearEvents();
+
+  PermissionsUpdater(profile()).RevokeOptionalPermissions(
+      *dummy_extension, permissions, PermissionsUpdater::REMOVE_HARD);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(dispatched_updated_event());
+}
+
 class DeveloperPrivateZipInstallerUnitTest
     : public DeveloperPrivateApiUnitTest {
  public:
diff --git a/chrome/browser/extensions/api/resources_private/resources_private_api.cc b/chrome/browser/extensions/api/resources_private/resources_private_api.cc
index bf1d431..7c3068a 100644
--- a/chrome/browser/extensions/api/resources_private/resources_private_api.cc
+++ b/chrome/browser/extensions/api/resources_private/resources_private_api.cc
@@ -45,6 +45,9 @@
   SetL10nString(dict, "pageReload", IDS_PDF_PAGE_RELOAD_BUTTON);
   SetL10nString(dict, "bookmarks", IDS_PDF_BOOKMARKS);
   SetL10nString(dict, "labelPageNumber", IDS_PDF_LABEL_PAGE_NUMBER);
+  SetL10nString(dict, "saveCalledTitle", IDS_PDF_SAVE_CALLED_TITLE);
+  SetL10nString(dict, "saveCalledText", IDS_PDF_SAVE_CALLED_TEXT);
+  SetL10nString(dict, "saveCalledButton", IDS_OK);
   SetL10nString(dict, "tooltipRotateCW", IDS_PDF_TOOLTIP_ROTATE_CW);
   SetL10nString(dict, "tooltipDownload", IDS_PDF_TOOLTIP_DOWNLOAD);
   SetL10nString(dict, "tooltipPrint", IDS_PDF_TOOLTIP_PRINT);
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 7dfae54..53b77a42 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2967,11 +2967,6 @@
     "Enable the mirrored screen mode. This mode flips the screen image "
     "horizontally.";
 
-const char kAshEnableNewOverviewAnimationsName[] =
-    "Enable new overview animations.";
-const char kAshEnableNewOverviewAnimationsDescription[] =
-    "Enables the new overview mode animations.";
-
 const char kAshEnablePersistentWindowBoundsName[] =
     "Enable persistent window bounds in multi-displays scenario.";
 const char kAshEnablePersistentWindowBoundsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d5191127..6e32a64 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1814,9 +1814,6 @@
 extern const char kAshEnableMirroredScreenName[];
 extern const char kAshEnableMirroredScreenDescription[];
 
-extern const char kAshEnableNewOverviewAnimationsName[];
-extern const char kAshEnableNewOverviewAnimationsDescription[];
-
 extern const char kAshEnablePersistentWindowBoundsName[];
 extern const char kAshEnablePersistentWindowBoundsDescription[];
 
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index 9356f4a8..6c5c4fe1 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -35,7 +35,6 @@
 #include "components/spellcheck/browser/pref_names.h"
 #include "components/startup_metric_utils/browser/pref_names.h"
 #include "components/suggestions/suggestions_pref_names.h"
-#include "components/sync/base/pref_names.h"
 #include "components/ukm/ukm_pref_names.h"
 #include "components/unified_consent/pref_names.h"
 #include "components/variations/pref_names.h"
@@ -1217,53 +1216,6 @@
     suggestions::prefs::kSuggestionsBlacklist,
     suggestions::prefs::kSuggestionsData,
 
-    // components/sync/base/pref_names.h
-    syncer::prefs::kSyncLastSyncedTime, syncer::prefs::kSyncLastPollTime,
-    syncer::prefs::kSyncShortPollIntervalSeconds,
-    syncer::prefs::kSyncLongPollIntervalSeconds,
-    syncer::prefs::kSyncHasAuthError, syncer::prefs::kSyncFirstSetupComplete,
-    syncer::prefs::kSyncKeepEverythingSynced, syncer::prefs::kSyncAppList,
-    syncer::prefs::kSyncAppNotifications, syncer::prefs::kSyncAppSettings,
-    syncer::prefs::kSyncApps, syncer::prefs::kSyncArcPackage,
-    syncer::prefs::kSyncArticles, syncer::prefs::kSyncAutofillProfile,
-    syncer::prefs::kSyncAutofillWallet,
-    syncer::prefs::kSyncAutofillWalletMetadata, syncer::prefs::kSyncAutofill,
-    syncer::prefs::kSyncBookmarks, syncer::prefs::kSyncDeviceInfo,
-    syncer::prefs::kSyncDictionary, syncer::prefs::kSyncExtensionSettings,
-    syncer::prefs::kSyncExtensions, syncer::prefs::kSyncFaviconImages,
-    syncer::prefs::kSyncFaviconTracking,
-    syncer::prefs::kSyncHistoryDeleteDirectives,
-    syncer::prefs::kSyncMountainShares, syncer::prefs::kSyncPasswords,
-    syncer::prefs::kSyncPreferences, syncer::prefs::kSyncPriorityPreferences,
-    syncer::prefs::kSyncPrinters, syncer::prefs::kSyncReadingList,
-    syncer::prefs::kSyncSearchEngines, syncer::prefs::kSyncSessions,
-    syncer::prefs::kSyncSupervisedUserSettings,
-    syncer::prefs::kSyncSupervisedUserSharedSettings,
-    syncer::prefs::kSyncSupervisedUserWhitelists,
-    syncer::prefs::kSyncSupervisedUsers,
-    syncer::prefs::kSyncSyncedNotificationAppInfo,
-    syncer::prefs::kSyncSyncedNotifications, syncer::prefs::kSyncTabs,
-    syncer::prefs::kSyncThemes, syncer::prefs::kSyncTypedUrls,
-    syncer::prefs::kSyncUserConsents, syncer::prefs::kSyncUserEvents,
-    syncer::prefs::kSyncWifiCredentials, syncer::prefs::kSyncManaged,
-    syncer::prefs::kSyncSuppressStart,
-    syncer::prefs::kSyncEncryptionBootstrapToken,
-    syncer::prefs::kSyncKeystoreEncryptionBootstrapToken,
-    syncer::prefs::kSyncSessionsGUID,
-
-#if defined(OS_CHROMEOS)
-    syncer::prefs::kSyncSpareBootstrapToken,
-#endif  // defined(OS_CHROMEOS)
-
-    syncer::prefs::kSyncFirstSyncTime, syncer::prefs::kSyncPassphrasePrompted,
-    syncer::prefs::kSyncMemoryPressureWarningCount,
-    syncer::prefs::kSyncShutdownCleanly,
-    syncer::prefs::kSyncInvalidationVersions,
-    syncer::prefs::kSyncLastRunVersion,
-    syncer::prefs::kSyncPassphraseEncryptionTransitionInProgress,
-    syncer::prefs::kSyncNigoriStateForPassphraseTransition,
-    syncer::prefs::kEnableLocalSyncBackend, syncer::prefs::kLocalSyncBackendDir,
-
     // components/ukm/ukm_pref_names.h
     ukm::prefs::kUkmClientId, ukm::prefs::kUkmPersistedLogs,
     ukm::prefs::kUkmSessionId,
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index 8fed45d1..5c60c7f 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -84,7 +85,6 @@
 class ResourceLoadingNoFeaturesBrowserTest : public InProcessBrowserTest {
  public:
   ResourceLoadingNoFeaturesBrowserTest() = default;
-
   ~ResourceLoadingNoFeaturesBrowserTest() override = default;
 
   void SetUpOnMainThread() override {
@@ -121,6 +121,8 @@
 
     redirect_url_ = http_server_->GetURL("/redirect.html");
     ASSERT_TRUE(redirect_url_.SchemeIs(url::kHttpScheme));
+
+    InProcessBrowserTest::SetUpOnMainThread();
   }
 
   void SetUpCommandLine(base::CommandLine* cmd) override {
@@ -138,7 +140,7 @@
         previews_service->previews_ui_service();
 
     std::vector<std::string> hints;
-    hints.push_back("jpg");
+    hints.push_back("foo.jpg");
     hints.push_back("png");
     hints.push_back("woff2");
 
@@ -170,12 +172,45 @@
   const GURL& http_url() const { return http_url_; }
   const GURL& redirect_url() const { return redirect_url_; }
 
+  void SetExpectedFooJpgRequest(bool expect_foo_jpg_requested) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    subresource_expected_["/foo.jpg"] = expect_foo_jpg_requested;
+  }
+  void SetExpectedBarJpgRequest(bool expect_bar_jpg_requested) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    subresource_expected_["/bar.jpg"] = expect_bar_jpg_requested;
+  }
+
+  // Verify that all subresources that were expected to be fetched were actually
+  // fetched.
+  void VerifyAllSubresourcesFetched() const {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    for (const auto& expect : subresource_expected_) {
+      EXPECT_FALSE(expect.second);
+    }
+  }
+
  protected:
   base::test::ScopedFeatureList scoped_feature_list_;
 
  private:
+  void TearDownOnMainThread() override {
+    VerifyAllSubresourcesFetched();
+
+    InProcessBrowserTest::TearDownOnMainThread();
+  }
+
   // Called by |https_server_|.
-  void MonitorResourceRequest(const net::test_server::HttpRequest& request) {}
+  void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
+    // This method is called on embedded test server thread. Post the
+    // information on UI thread.
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&ResourceLoadingNoFeaturesBrowserTest::
+                           MonitorResourceRequestOnUIThread,
+                       base::Unretained(this), request.GetURL()));
+  }
 
   std::unique_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
       const net::test_server::HttpRequest& request) {
@@ -188,6 +223,19 @@
     return std::move(response);
   }
 
+  void MonitorResourceRequestOnUIThread(const GURL& gurl) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    for (const auto& expect : subresource_expected_) {
+      if (gurl.path() == expect.first) {
+        EXPECT_TRUE(expect.second);
+        // Subresource should not be fetched again.
+        subresource_expected_[gurl.path()] = false;
+        return;
+      }
+    }
+  }
+
   optimization_guide::testing::TestComponentCreator test_component_creator_;
 
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
@@ -197,6 +245,12 @@
   GURL http_url_;
   GURL redirect_url_;
 
+  // Mapping from a subresource path to whether the resource is expected to be
+  // fetched. Once a subresource present in this map is fetched, the
+  // corresponding value is set to false.
+  // Must only be accessed on UI thread.
+  std::map<std::string, bool> subresource_expected_;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceLoadingNoFeaturesBrowserTest);
 };
 
@@ -240,6 +294,8 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        MAYBE_ResourceLoadingHintsHttpsWhitelisted) {
+  SetExpectedFooJpgRequest(false);
+  SetExpectedBarJpgRequest(true);
   SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
@@ -264,9 +320,12 @@
   // SetResourceLoadingHintsPatterns sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
+  VerifyAllSubresourcesFetched();
 
   // Load the same webpage to ensure that the resource loading hints are sent
   // again.
+  SetExpectedFooJpgRequest(false);
+  SetExpectedBarJpgRequest(true);
   ui_test_utils::NavigateToURL(browser(), https_url());
   RetryForHistogramUntilCountReached(
       &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns",
@@ -284,6 +343,8 @@
 IN_PROC_BROWSER_TEST_F(
     ResourceLoadingHintsBrowserTest,
     MAYBE_ResourceLoadingHintsHttpsWhitelistedRedirectToHttps) {
+  SetExpectedFooJpgRequest(false);
+  SetExpectedBarJpgRequest(true);
   SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
@@ -310,6 +371,8 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        ResourceLoadingHintsHttpsNoWhitelisted) {
+  SetExpectedFooJpgRequest(true);
+  SetExpectedBarJpgRequest(true);
   SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
@@ -335,6 +398,8 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        ResourceLoadingHintsHttp) {
+  SetExpectedFooJpgRequest(true);
+  SetExpectedBarJpgRequest(true);
   SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
@@ -360,6 +425,8 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        ResourceLoadingHintsHttpsWhitelistedNoTransform) {
+  SetExpectedFooJpgRequest(true);
+  SetExpectedBarJpgRequest(true);
   SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index dc56302..28bedba4 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -31,14 +31,16 @@
 #include <io.h>
 #endif
 
-namespace {
-
-
-}  // namespace
-
 namespace heap_profiling {
 
 namespace {
+// Slow-report trigger configuration.
+// see: content/browser/tracing/background_tracing_config_impl.cc
+const char kConfigsKey[] = "configs";
+const char kConfigModeKey[] = "mode";
+const char kConfigScenarioName[] = "scenario_name";
+const char kConfigCategoryKey[] = "category";
+const char kConfigCategoryMemlog[] = "MEMLOG";
 
 void OnTraceUploadComplete(TraceCrashServiceUploader* uploader,
                            bool success,
@@ -69,19 +71,19 @@
   base::Value rule(base::Value::Type::DICTIONARY);
   rule.SetKey("rule", base::Value("MEMLOG"));
   rule.SetKey("trigger_name", base::Value(std::move(trigger_name)));
-  rule.SetKey("category", base::Value("BENCHMARK_MEMORY_HEAVY"));
   rules_list.GetList().push_back(std::move(rule));
 
   std::string sampling_mode = base::StringPrintf("SAMPLING_%u", sampling_rate);
 
   base::Value configs(base::Value::Type::DICTIONARY);
-  configs.SetKey("mode", base::Value(sampling_mode));
-  configs.SetKey("category", base::Value("MEMLOG"));
-  configs.SetKey("configs", std::move(rules_list));
+  configs.SetKey(kConfigModeKey, base::Value(sampling_mode));
+  configs.SetKey(kConfigCategoryKey, base::Value(kConfigCategoryMemlog));
+  configs.SetKey(kConfigsKey, std::move(rules_list));
 
   std::unique_ptr<base::DictionaryValue> metadata =
       std::make_unique<base::DictionaryValue>();
   metadata->SetKey("config", std::move(configs));
+  metadata->SetKey(kConfigScenarioName, base::Value("MEMLOG"));
 
   TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
       g_browser_process->system_request_context());
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
index a3d3c63..705f74b8 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
@@ -43,10 +43,13 @@
    * @private
    */
   onNextTap_: function() {
-    var screenContext = (this.$$('#toggle0').getAttribute('checked') != null);
-    var emailOptedIn = (this.$$('#toggle1') != null) &&
-        (this.$$('#toggle1').getAttribute('checked') != null);
+    var hotword = this.$$('#toggle0').hasAttribute('checked');
+    var screenContext = this.$$('#toggle1').hasAttribute('checked');
+    var toggle2 = this.$$('#toggle2');
+    var emailOptedIn = toggle2 != null && toggle2.hasAttribute('checked');
 
+    // TODO(updowndota): Wrap chrome.send() calls with a proxy object.
+    chrome.send('hotwordResult', [hotword]);
     chrome.send(
         'AssistantGetMoreScreen.userActed', [screenContext, emailOptedIn]);
   },
@@ -76,7 +79,7 @@
    * Add a setting zippy with the provided data.
    */
   addSettingZippy: function(zippy_data) {
-    assert(zippy_data.length <= 2);
+    assert(zippy_data.length <= 3);
     for (var i in zippy_data) {
       var data = zippy_data[i];
       var zippy = document.createElement('setting-zippy');
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 3fc07a1a..6166470 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -126,6 +126,8 @@
         <include name="IDR_PDF_VIEWER_PASSWORD_SCREEN_JS" file="pdf/elements/viewer-password-screen/viewer-password-screen.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_HTML" file="pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_JS" file="pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js" type="BINDATA" />
+        <include name="IDR_PDF_VIEWER_SAVE_CALLED_HTML" file="pdf/elements/viewer-save-called-screen/viewer-save-called-screen.html" type="BINDATA" />
+        <include name="IDR_PDF_VIEWER_SAVE_CALLED_JS" file="pdf/elements/viewer-save-called-screen/viewer-save-called-screen.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_HTML" file="pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_JS" file="pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_ZOOM_BUTTON_HTML" file="pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.html" type="BINDATA" />
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 35087d3..6b540b1 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -229,6 +229,7 @@
         case EventType.WARNINGS_CHANGED:
         case EventType.COMMAND_ADDED:
         case EventType.COMMAND_REMOVED:
+        case EventType.PERMISSIONS_CHANGED:
           // |extensionInfo| can be undefined in the case of an extension
           // being unloaded right before uninstallation. There's nothing to do
           // here.
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index 5a3ce14..30b642b9 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -13,6 +13,7 @@
     "elements/viewer-page-indicator:closure_compile",
     "elements/viewer-page-selector:closure_compile",
     "elements/viewer-password-screen:closure_compile",
+    "elements/viewer-save-called-screen:closure_compile",
   ]
 }
 
diff --git a/chrome/browser/resources/pdf/elements/viewer-save-called-screen/BUILD.gn b/chrome/browser/resources/pdf/elements/viewer-save-called-screen/BUILD.gn
new file mode 100644
index 0000000..1e2b08cc
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-save-called-screen/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":viewer-save-called-screen",
+  ]
+}
+
+js_library("viewer-save-called-screen") {
+  deps = [
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+  ]
+}
diff --git a/chrome/browser/resources/pdf/elements/viewer-save-called-screen/viewer-save-called-screen.html b/chrome/browser/resources/pdf/elements/viewer-save-called-screen/viewer-save-called-screen.html
new file mode 100644
index 0000000..29cb355
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-save-called-screen/viewer-save-called-screen.html
@@ -0,0 +1,21 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+
+<dom-module id="viewer-save-called-screen">
+  <template>
+    <style include="paper-button-style"></style>
+    <cr-dialog id="dialog" no-cancel>
+      <div slot="title">[[strings.saveCalledTitle]]</div>
+      <div slot="body">[[strings.saveCalledText]]</div>
+      <div slot="button-container">
+        <paper-button class="action-button" on-click="dismiss_">
+          [[strings.saveCalledButton]]
+        </paper-button>
+      </div>
+    </cr-dialog>
+  </template>
+  <script src="viewer-save-called-screen.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/pdf/elements/viewer-save-called-screen/viewer-save-called-screen.js b/chrome/browser/resources/pdf/elements/viewer-save-called-screen/viewer-save-called-screen.js
new file mode 100644
index 0000000..f24206e
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-save-called-screen/viewer-save-called-screen.js
@@ -0,0 +1,20 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Polymer({
+  is: 'viewer-save-called-screen',
+
+  properties: {
+    strings: Object,
+  },
+
+  show: function() {
+    this.$.dialog.showModal();
+  },
+
+  /** @private */
+  dismiss_: function() {
+    this.$.dialog.close();
+  },
+});
diff --git a/chrome/browser/resources/pdf/index.html b/chrome/browser/resources/pdf/index.html
index dcec3cc..fabf9d2 100644
--- a/chrome/browser/resources/pdf/index.html
+++ b/chrome/browser/resources/pdf/index.html
@@ -7,6 +7,7 @@
   <link rel="import" href="elements/viewer-page-selector/viewer-page-selector.html">
   <link rel="import" href="elements/viewer-password-screen/viewer-password-screen.html">
   <link rel="import" href="elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html">
+  <link rel="import" href="elements/viewer-save-called-screen/viewer-save-called-screen.html">
   <link rel="import" href="elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html">
   <link rel="import" href="elements/shared-vars.html">
 
@@ -26,6 +27,8 @@
 
 <viewer-error-screen id="error-screen"></viewer-error-screen>
 
+<viewer-save-called-screen id="save-called-screen"></viewer-save-called-screen>
+
 </body>
 <script src="pdf_fitting_type.js"></script>
 <script src="toolbar_manager.js"></script>
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js
index 6de1c5c..c9b0f38 100644
--- a/chrome/browser/resources/pdf/pdf.js
+++ b/chrome/browser/resources/pdf/pdf.js
@@ -629,6 +629,7 @@
     $('zoom-toolbar').strings = strings;
     $('password-screen').strings = strings;
     $('error-screen').strings = strings;
+    $('save-called-screen').strings = strings;
   },
 
   /**
@@ -761,6 +762,9 @@
       case 'transformPagePointReply':
         this.coordsTransformer_.onReplyReceived(message);
         break;
+      case 'saveCalled':
+        $('save-called-screen').show();
+        break;
     }
   },
 
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js
index 1ddbddc..9fcdad33 100644
--- a/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -16,7 +16,12 @@
     /** @private {?UpdateStatusChangedEvent} */
     currentUpdateStatusEvent_: {
       type: Object,
-      value: {message: '', progress: 0, status: UpdateStatus.DISABLED},
+      value: {
+        message: '',
+        progress: 0,
+        rollback: false,
+        status: UpdateStatus.DISABLED
+      },
     },
 
     // <if expr="chromeos">
@@ -298,8 +303,8 @@
     this.showRelaunch_ = this.checkStatus_(UpdateStatus.NEARLY_UPDATED);
     // </if>
     // <if expr="chromeos">
-    this.showRelaunch_ = this.checkStatus_(UpdateStatus.NEARLY_UPDATED) &&
-        !this.isTargetChannelMoreStable_();
+    this.showRelaunch_ =
+        this.checkStatus_(UpdateStatus.NEARLY_UPDATED) && !this.isRollback_();
     // </if>
   },
 
@@ -324,6 +329,8 @@
         // <if expr="chromeos">
         if (this.currentChannel_ != this.targetChannel_)
           return this.i18nAdvanced('aboutUpgradeSuccessChannelSwitch');
+        if (this.currentUpdateStatusEvent_.rollback)
+          return this.i18nAdvanced('aboutRollbackSuccess');
         // </if>
         return this.i18nAdvanced('aboutUpgradeRelaunch');
       case UpdateStatus.UPDATED:
@@ -342,6 +349,11 @@
             ]
           });
         }
+        if (this.currentUpdateStatusEvent_.rollback) {
+          return this.i18nAdvanced('aboutRollbackInProgress', {
+            substitutions: [progressPercent],
+          });
+        }
         // </if>
         if (this.currentUpdateStatusEvent_.progress > 0) {
           // NOTE(dbeam): some platforms (i.e. Mac) always send 0% while
@@ -442,9 +454,13 @@
    * @return {boolean}
    * @private
    */
-  isTargetChannelMoreStable_: function() {
+  isRollback_: function() {
     assert(this.currentChannel_.length > 0);
     assert(this.targetChannel_.length > 0);
+    if (this.currentUpdateStatusEvent_.rollback) {
+      return true;
+    }
+    // Channel switch to a more stable channel is also a rollback
     return settings.isTargetChannelMoreStable(
         this.currentChannel_, this.targetChannel_);
   },
@@ -464,8 +480,7 @@
    * @private
    */
   computeShowRelaunchAndPowerwash_: function() {
-    return this.checkStatus_(UpdateStatus.NEARLY_UPDATED) &&
-        this.isTargetChannelMoreStable_();
+    return this.checkStatus_(UpdateStatus.NEARLY_UPDATED) && this.isRollback_();
   },
 
   /** @private */
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index a3cf72d..928a79d 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -50,6 +50,7 @@
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/profile_sync_components_factory_impl.h"
 #include "components/browser_sync/profile_sync_service.h"
@@ -223,10 +224,24 @@
 void ChromeSyncClient::Initialize() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  web_data_service_ = WebDataServiceFactory::GetAutofillWebDataForProfile(
-      profile_, ServiceAccessType::IMPLICIT_ACCESS);
-  db_thread_ =
-      web_data_service_ ? web_data_service_->GetDBTaskRunner() : nullptr;
+  profile_web_data_service_ =
+      WebDataServiceFactory::GetAutofillWebDataForProfile(
+          profile_, ServiceAccessType::IMPLICIT_ACCESS);
+  account_web_data_service_ =
+      base::FeatureList::IsEnabled(
+          autofill::features::kAutofillEnableAccountWalletStorage)
+          ? WebDataServiceFactory::GetAutofillWebDataForAccount(
+                profile_, ServiceAccessType::IMPLICIT_ACCESS)
+          : nullptr;
+  web_data_service_thread_ = profile_web_data_service_
+                                 ? profile_web_data_service_->GetDBTaskRunner()
+                                 : nullptr;
+
+  // This class assumes that the database thread is the same across the profile
+  // and account storage. This DCHECK makes that assumption explicit.
+  DCHECK(!account_web_data_service_ ||
+         web_data_service_thread_ ==
+             account_web_data_service_->GetDBTaskRunner());
   password_store_ = PasswordStoreFactory::GetForProfile(
       profile_, ServiceAccessType::IMPLICIT_ACCESS);
 
@@ -238,7 +253,7 @@
         prefs::kSavingBrowserHistoryDisabled,
         content::BrowserThread::GetTaskRunnerForThread(
             content::BrowserThread::UI),
-        db_thread_, web_data_service_, password_store_);
+        web_data_service_thread_, profile_web_data_service_, password_store_);
   }
 }
 
@@ -451,19 +466,37 @@
           ->GetSyncableService(syncer::PRIORITY_PREFERENCES)
           ->AsWeakPtr();
     case syncer::AUTOFILL_PROFILE:
-    case syncer::AUTOFILL_WALLET_DATA:
-    case syncer::AUTOFILL_WALLET_METADATA: {
-      if (!web_data_service_)
-        return base::WeakPtr<syncer::SyncableService>();
-      if (type == syncer::AUTOFILL_PROFILE) {
+      if (profile_web_data_service_) {
         return autofill::AutofillProfileSyncableService::FromWebDataService(
-            web_data_service_.get())->AsWeakPtr();
-      } else if (type == syncer::AUTOFILL_WALLET_METADATA) {
-        return autofill::AutofillWalletMetadataSyncableService::
-            FromWebDataService(web_data_service_.get())->AsWeakPtr();
+                   profile_web_data_service_.get())
+            ->AsWeakPtr();
       }
-      return autofill::AutofillWalletSyncableService::FromWebDataService(
-          web_data_service_.get())->AsWeakPtr();
+      return base::WeakPtr<syncer::SyncableService>();
+    case syncer::AUTOFILL_WALLET_DATA: {
+      // TODO(feuunk): This doesn't allow switching which database to use at
+      // runtime. This should be fixed as part of the USS migration for
+      // payments.
+      auto service = account_web_data_service_ ? account_web_data_service_
+                                               : profile_web_data_service_;
+      if (service) {
+        return autofill::AutofillWalletSyncableService::FromWebDataService(
+                   service.get())
+            ->AsWeakPtr();
+      }
+      return base::WeakPtr<syncer::SyncableService>();
+    }
+    case syncer::AUTOFILL_WALLET_METADATA: {
+      // TODO(feuunk): This doesn't allow switching which database to use at
+      // runtime. This should be fixed as part of the USS migration for
+      // payments.
+      auto service = account_web_data_service_ ? account_web_data_service_
+                                               : profile_web_data_service_;
+      if (service) {
+        return autofill::AutofillWalletMetadataSyncableService::
+            FromWebDataService(service.get())
+                ->AsWeakPtr();
+      }
+      return base::WeakPtr<syncer::SyncableService>();
     }
     case syncer::SEARCH_ENGINES:
       return TemplateURLServiceFactory::GetForProfile(profile_)->AsWeakPtr();
@@ -564,12 +597,12 @@
       return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::AUTOFILL:
       return autofill::AutocompleteSyncBridge::FromWebDataService(
-                 web_data_service_.get())
+                 profile_web_data_service_.get())
           ->change_processor()
           ->GetControllerDelegateOnUIThread();
     case syncer::AUTOFILL_PROFILE:
       return autofill::AutofillProfileSyncBridge::FromWebDataService(
-                 web_data_service_.get())
+                 profile_web_data_service_.get())
           ->change_processor()
           ->GetControllerDelegateOnUIThread();
 #if defined(OS_CHROMEOS)
@@ -620,7 +653,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   switch (group) {
     case syncer::GROUP_DB:
-      return new syncer::SequencedModelWorker(db_thread_, syncer::GROUP_DB);
+      return new syncer::SequencedModelWorker(web_data_service_thread_,
+                                              syncer::GROUP_DB);
     // TODO(stanisc): crbug.com/731903: Rename GROUP_FILE to reflect that it is
     // used only for app and extension settings.
     case syncer::GROUP_FILE:
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index 1996511..1fc2e7f 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -81,11 +81,12 @@
 
   // Members that must be fetched on the UI thread but accessed on their
   // respective backend threads.
-  scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
+  scoped_refptr<autofill::AutofillWebDataService> profile_web_data_service_;
+  scoped_refptr<autofill::AutofillWebDataService> account_web_data_service_;
   scoped_refptr<password_manager::PasswordStore> password_store_;
 
   // The task runner for the |web_data_service_|, if any.
-  scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+  scoped_refptr<base::SingleThreadTaskRunner> web_data_service_thread_;
 
   std::unique_ptr<sync_sessions::SyncSessionsClient> sync_sessions_client_;
 
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 1dcc854..afdb5ac95 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -4,25 +4,10 @@
 
 #include "chrome/browser/sync/sync_ui_util.h"
 
-#include <stdint.h>
-
-#include <string>
-
-#include "base/i18n/number_formatting.h"
-#include "base/i18n/time_formatting.h"
-#include "base/metrics/field_trial.h"
-#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
-#include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/webui/signin/login_ui_service.h"
-#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -31,26 +16,19 @@
 #include "components/signin/core/browser/signin_error_controller.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/sync/base/model_type.h"
 #include "components/sync/base/sync_prefs.h"
-#include "components/sync/engine/cycle/sync_cycle_snapshot.h"
-#include "components/sync/protocol/proto_enum_conversions.h"
 #include "components/sync/protocol/sync_protocol_error.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_CHROMEOS)
-#include "components/account_id/account_id.h"
-#include "components/user_manager/user_manager.h"
-#else
+#if !defined(OS_CHROMEOS)
 #include "chrome/browser/signin/signin_manager_factory.h"
+#include "components/signin/core/browser/signin_manager.h"
 #include "components/sync/driver/sync_error_controller.h"
 #endif  // defined(OS_CHROMEOS)
 
 using browser_sync::ProfileSyncService;
 
-using AuthError = GoogleServiceAuthError;
-
 namespace sync_ui_util {
 
 namespace {
@@ -58,7 +36,7 @@
 // Returns the message that should be displayed when the user is authenticated
 // and can connect to the sync server. If the user hasn't yet authenticated, an
 // empty string is returned.
-base::string16 GetSyncedStateStatusLabel(ProfileSyncService* service,
+base::string16 GetSyncedStateStatusLabel(const ProfileSyncService* service,
                                          const SigninManagerBase& signin,
                                          StatusLabelStyle style,
                                          bool sync_everything) {
@@ -117,7 +95,7 @@
 }
 
 void GetStatusForUnrecoverableError(Profile* profile,
-                                    ProfileSyncService* service,
+                                    const ProfileSyncService* service,
                                     base::string16* status_label,
                                     base::string16* link_label,
                                     ActionType* action_type) {
@@ -189,7 +167,7 @@
 
 // status_label and link_label must either be both null or both non-null.
 MessageType GetStatusInfo(Profile* profile,
-                          ProfileSyncService* service,
+                          const ProfileSyncService* service,
                           const SigninManagerBase& signin,
                           StatusLabelStyle style,
                           base::string16* status_label,
@@ -234,9 +212,9 @@
     // Check for sync errors if the sync service is enabled.
     if (service) {
       // Since there is no auth in progress, check for an auth error first.
-      AuthError auth_error =
+      GoogleServiceAuthError auth_error =
           SigninErrorControllerFactory::GetForProfile(profile)->auth_error();
-      if (auth_error.state() != AuthError::NONE) {
+      if (auth_error.state() != GoogleServiceAuthError::NONE) {
         if (status_label && link_label) {
           GetStatusForAuthError(profile, signin, status_label, link_label,
                                 action_type);
@@ -294,7 +272,7 @@
       result_type = PRE_SYNCED;
       syncer::SyncStatus status;
       service->QueryDetailedSyncStatus(&status);
-      AuthError auth_error =
+      GoogleServiceAuthError auth_error =
           SigninErrorControllerFactory::GetForProfile(profile)->auth_error();
       if (status_label) {
         status_label->assign(
@@ -305,8 +283,8 @@
           status_label->assign(
               l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
         }
-      } else if (auth_error.state() != AuthError::NONE &&
-                 auth_error.state() != AuthError::TWO_FACTOR) {
+      } else if (auth_error.state() != GoogleServiceAuthError::NONE &&
+                 auth_error.state() != GoogleServiceAuthError::TWO_FACTOR) {
         if (status_label && link_label) {
           GetStatusForAuthError(profile, signin, status_label, link_label,
                                 action_type);
@@ -345,16 +323,15 @@
 }  // namespace
 
 MessageType GetStatusLabels(Profile* profile,
-                            ProfileSyncService* service,
+                            const ProfileSyncService* service,
                             const SigninManagerBase& signin,
-                            StatusLabelStyle style,
                             base::string16* status_label,
                             base::string16* link_label,
                             ActionType* action_type) {
   DCHECK(status_label);
   DCHECK(link_label);
-  return sync_ui_util::GetStatusInfo(profile, service, signin, style,
-                                     status_label, link_label, action_type);
+  return GetStatusInfo(profile, service, signin, PLAIN_TEXT, status_label,
+                       link_label, action_type);
 }
 
 #if !defined(OS_CHROMEOS)
@@ -363,7 +340,7 @@
     const SigninManagerBase& signin,
     int* content_string_id,
     int* button_string_id) {
-  ProfileSyncService* service =
+  const ProfileSyncService* service =
       ProfileSyncServiceFactory::GetForProfile(profile);
 
   // The order or priority is going to be: 1. Unrecoverable errors.
@@ -421,7 +398,7 @@
     }
 
     // Check for a sync passphrase error.
-    syncer::SyncErrorController* sync_error_controller =
+    const syncer::SyncErrorController* sync_error_controller =
         service->sync_error_controller();
     if (sync_error_controller && sync_error_controller->HasError()) {
       *content_string_id = IDS_SYNC_ERROR_USER_MENU_PASSPHRASE_MESSAGE;
@@ -443,20 +420,11 @@
 #endif
 
 MessageType GetStatus(Profile* profile,
-                      ProfileSyncService* service,
+                      const ProfileSyncService* service,
                       const SigninManagerBase& signin) {
   ActionType action_type = NO_ACTION;
-  return sync_ui_util::GetStatusInfo(profile, service, signin, WITH_HTML,
-                                     nullptr, nullptr, &action_type);
-}
-
-base::string16 ConstructTime(int64_t time_in_int) {
-  base::Time time = base::Time::FromInternalValue(time_in_int);
-
-  // If time is null the format function returns a time in 1969.
-  if (time.is_null())
-    return base::string16();
-  return base::TimeFormatFriendlyDateAndTime(time);
+  return GetStatusInfo(profile, service, signin, WITH_HTML, nullptr, nullptr,
+                       &action_type);
 }
 
 }  // namespace sync_ui_util
diff --git a/chrome/browser/sync/sync_ui_util.h b/chrome/browser/sync/sync_ui_util.h
index 101e5a7..ca680a3 100644
--- a/chrome/browser/sync/sync_ui_util.h
+++ b/chrome/browser/sync/sync_ui_util.h
@@ -59,11 +59,9 @@
 
 // Create status and link labels for the current status labels and link text
 // by querying |service|.
-// |style| sets the link properties, see |StatusLabelStyle|.
 MessageType GetStatusLabels(Profile* profile,
-                            browser_sync::ProfileSyncService* service,
+                            const browser_sync::ProfileSyncService* service,
                             const SigninManagerBase& signin,
-                            StatusLabelStyle style,
                             base::string16* status_label,
                             base::string16* link_label,
                             ActionType* action_type);
@@ -79,8 +77,9 @@
 #endif
 
 MessageType GetStatus(Profile* profile,
-                      browser_sync::ProfileSyncService* service,
+                      const browser_sync::ProfileSyncService* service,
                       const SigninManagerBase& signin);
 
 }  // namespace sync_ui_util
+
 #endif  // CHROME_BROWSER_SYNC_SYNC_UI_UTIL_H_
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index a15a871b..f70b3ada 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -111,8 +111,7 @@
     case STATUS_CASE_SETUP_IN_PROGRESS: {
       EXPECT_CALL(*service, IsFirstSetupComplete())
           .WillRepeatedly(Return(false));
-      EXPECT_CALL(*service, IsFirstSetupInProgress())
-          .WillRepeatedly(Return(true));
+      EXPECT_CALL(*service, IsSetupInProgress()).WillRepeatedly(Return(true));
       syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
@@ -121,8 +120,7 @@
     case STATUS_CASE_SETUP_ERROR: {
       EXPECT_CALL(*service, IsFirstSetupComplete())
           .WillRepeatedly(Return(false));
-      EXPECT_CALL(*service, IsFirstSetupInProgress())
-          .WillRepeatedly(Return(false));
+      EXPECT_CALL(*service, IsSetupInProgress()).WillRepeatedly(Return(false));
       EXPECT_CALL(*service, GetDisableReasons())
           .WillRepeatedly(
               Return(syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR));
@@ -295,8 +293,7 @@
     base::string16 link_label;
     sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
     sync_ui_util::GetStatusLabels(profile.get(), &service, signin,
-                                  sync_ui_util::WITH_HTML, &status_label,
-                                  &link_label, &action_type);
+                                  &status_label, &link_label, &action_type);
 
     EXPECT_EQ(GetActionTypeforDistinctCase(idx), action_type);
     // If the status and link message combination is already present in the set
@@ -304,6 +301,11 @@
     // message, and the test has failed.
     EXPECT_FALSE(status_label.empty()) <<
         "Empty status label returned for case #" << idx;
+    // Ensures a search for string 'href' (found in links, not a string to be
+    // found in an English language message) fails, since links are excluded
+    // from the status label.
+    EXPECT_EQ(status_label.find(base::ASCIIToUTF16("href")),
+              base::string16::npos);
     base::string16 combined_label =
         status_label + base::ASCIIToUTF16("#") + link_label;
     EXPECT_TRUE(messages.find(combined_label) == messages.end()) <<
@@ -316,42 +318,6 @@
   }
 }
 
-// This test ensures that the html_links parameter on GetStatusLabels() is
-// honored.
-TEST_F(SyncUIUtilTest, HtmlNotIncludedInStatusIfNotRequested) {
-  for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
-    std::unique_ptr<Profile> profile = std::make_unique<TestingProfile>();
-    ProfileSyncService::InitParams init_params =
-        CreateProfileSyncServiceParamsForTest(profile.get());
-    NiceMock<ProfileSyncServiceMock> service(&init_params);
-    GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
-    EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
-    FakeSigninManagerForSyncUIUtilTest signin(profile.get());
-    signin.SetAuthenticatedAccountInfo(kTestGaiaId, kTestUser);
-    ProfileOAuth2TokenService* token_service =
-        ProfileOAuth2TokenServiceFactory::GetForProfile(profile.get());
-    GetDistinctCase(&service, &signin, token_service, idx);
-    base::string16 status_label;
-    base::string16 link_label;
-    sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
-    sync_ui_util::GetStatusLabels(profile.get(), &service, signin,
-                                  sync_ui_util::PLAIN_TEXT, &status_label,
-                                  &link_label, &action_type);
-
-    EXPECT_EQ(GetActionTypeforDistinctCase(idx), action_type);
-    // Ensures a search for string 'href' (found in links, not a string to be
-    // found in an English language message) fails when links are excluded from
-    // the status label.
-    EXPECT_FALSE(status_label.empty());
-    EXPECT_EQ(status_label.find(base::ASCIIToUTF16("href")),
-              base::string16::npos);
-    testing::Mock::VerifyAndClearExpectations(&service);
-    testing::Mock::VerifyAndClearExpectations(&signin);
-    EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
-    signin.Shutdown();
-  }
-}
-
 TEST_F(SyncUIUtilTest, UnrecoverableErrorWithActionableError) {
   std::unique_ptr<Profile> profile(MakeSignedInTestingProfile());
   SigninManagerBase* signin =
@@ -373,7 +339,6 @@
   base::string16 unrecoverable_error_status_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
   sync_ui_util::GetStatusLabels(profile.get(), &service, *signin,
-                                sync_ui_util::PLAIN_TEXT,
                                 &unrecoverable_error_status_label, &link_label,
                                 &action_type);
 
@@ -387,7 +352,6 @@
       .WillOnce(DoAll(SetArgPointee<0>(status), Return(true)));
   base::string16 upgrade_client_status_label;
   sync_ui_util::GetStatusLabels(profile.get(), &service, *signin,
-                                sync_ui_util::PLAIN_TEXT,
                                 &upgrade_client_status_label, &link_label,
                                 &action_type);
   // Expect an explicit 'client upgrade' action.
@@ -418,7 +382,6 @@
   base::string16 link_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
   sync_ui_util::GetStatusLabels(profile.get(), &service, *signin,
-                                sync_ui_util::PLAIN_TEXT,
                                 &first_actionable_error_status_label,
                                 &link_label, &action_type);
   // Expect a 'client upgrade' call to action.
@@ -432,7 +395,6 @@
   base::string16 second_actionable_error_status_label;
   action_type = sync_ui_util::NO_ACTION;
   sync_ui_util::GetStatusLabels(profile.get(), &service, *signin,
-                                sync_ui_util::PLAIN_TEXT,
                                 &second_actionable_error_status_label,
                                 &link_label, &action_type);
   // Expect a passive message instead of a call to action.
@@ -455,9 +417,9 @@
   base::string16 link_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
 
-  sync_ui_util::GetStatusLabels(
-      profile.get(), &service, *signin, sync_ui_util::PLAIN_TEXT,
-      &actionable_error_status_label, &link_label, &action_type);
+  sync_ui_util::GetStatusLabels(profile.get(), &service, *signin,
+                                &actionable_error_status_label, &link_label,
+                                &action_type);
 
   EXPECT_EQ(action_type, sync_ui_util::CONFIRM_SYNC_SETTINGS);
 }
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc
index dcd13d6..7b2145a 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.cc
+++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -76,7 +76,7 @@
       .WillOnce(SignalEvent(&done_event));
 
   scoped_refptr<AutofillWebDataService> wds =
-      autofill_helper::GetWebDataService(profile);
+      autofill_helper::GetProfileWebDataService(profile);
 
   void (AutofillWebDataService::*add_observer_func)(
       AutofillWebDataServiceObserverOnDBSequence*) =
@@ -202,11 +202,16 @@
   return profile;
 }
 
-scoped_refptr<AutofillWebDataService> GetWebDataService(int index) {
+scoped_refptr<AutofillWebDataService> GetProfileWebDataService(int index) {
   return WebDataServiceFactory::GetAutofillWebDataForProfile(
       test()->GetProfile(index), ServiceAccessType::EXPLICIT_ACCESS);
 }
 
+scoped_refptr<AutofillWebDataService> GetAccountWebDataService(int index) {
+  return WebDataServiceFactory::GetAutofillWebDataForAccount(
+      test()->GetProfile(index), ServiceAccessType::EXPLICIT_ACCESS);
+}
+
 PersonalDataManager* GetPersonalDataManager(int index) {
   return autofill::PersonalDataManagerFactory::GetForProfile(
       test()->GetProfile(index));
@@ -227,7 +232,7 @@
   EXPECT_CALL(mock_observer, AutofillEntriesChanged(_))
       .WillOnce(SignalEvent(&done_event));
 
-  scoped_refptr<AutofillWebDataService> wds = GetWebDataService(profile);
+  scoped_refptr<AutofillWebDataService> wds = GetProfileWebDataService(profile);
 
   void (AutofillWebDataService::*add_observer_func)(
       AutofillWebDataServiceObserverOnDBSequence*) =
@@ -249,7 +254,7 @@
 void RemoveKey(int profile, const AutofillKey& key) {
   RemoveKeyDontBlockForSync(profile, key);
   WaitForCurrentTasksToComplete(
-      autofill_helper::GetWebDataService(profile)->GetDBTaskRunner());
+      autofill_helper::GetProfileWebDataService(profile)->GetDBTaskRunner());
 }
 
 void RemoveKeys(int profile) {
@@ -258,11 +263,11 @@
     RemoveKeyDontBlockForSync(profile, entry.key());
   }
   WaitForCurrentTasksToComplete(
-      autofill_helper::GetWebDataService(profile)->GetDBTaskRunner());
+      autofill_helper::GetProfileWebDataService(profile)->GetDBTaskRunner());
 }
 
 std::set<AutofillEntry> GetAllKeys(int profile) {
-  scoped_refptr<AutofillWebDataService> wds = GetWebDataService(profile);
+  scoped_refptr<AutofillWebDataService> wds = GetProfileWebDataService(profile);
   std::vector<AutofillEntry> all_entries = GetAllAutofillEntries(wds.get());
   return std::set<AutofillEntry>(all_entries.begin(), all_entries.end());
 }
@@ -331,7 +336,7 @@
   // cancel outstanding queries, this is only instigated on the UI sequence,
   // which we are about to block, which means we are safe.
   WaitForCurrentTasksToComplete(
-      autofill_helper::GetWebDataService(profile)->GetDBTaskRunner());
+      autofill_helper::GetProfileWebDataService(profile)->GetDBTaskRunner());
 
   return pdm->GetProfiles();
 }
@@ -387,9 +392,9 @@
   // before any locally instigated async writes. This is run exactly one time
   // before the first IsExitConditionSatisfied() is called.
   WaitForCurrentTasksToComplete(
-      autofill_helper::GetWebDataService(profile_a_)->GetDBTaskRunner());
+      autofill_helper::GetProfileWebDataService(profile_a_)->GetDBTaskRunner());
   WaitForCurrentTasksToComplete(
-      autofill_helper::GetWebDataService(profile_b_)->GetDBTaskRunner());
+      autofill_helper::GetProfileWebDataService(profile_b_)->GetDBTaskRunner());
   return StatusChangeChecker::Wait();
 }
 
diff --git a/chrome/browser/sync/test/integration/autofill_helper.h b/chrome/browser/sync/test/integration/autofill_helper.h
index a4895dfc..93ac327 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.h
+++ b/chrome/browser/sync/test/integration/autofill_helper.h
@@ -35,7 +35,12 @@
 };
 
 // Used to access the web data service within a particular sync profile.
-scoped_refptr<autofill::AutofillWebDataService> GetWebDataService(
+scoped_refptr<autofill::AutofillWebDataService> GetProfileWebDataService(
+    int index) WARN_UNUSED_RESULT;
+
+// Used to access the account-scoped web data service within a particular sync
+// profile.
+scoped_refptr<autofill::AutofillWebDataService> GetAccountWebDataService(
     int index) WARN_UNUSED_RESULT;
 
 // Used to access the personal data manager within a particular sync profile.
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index fc63b07..7f6ecba 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -15,14 +15,18 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/test/fake_server/fake_server.h"
+#include "components/webdata/common/web_data_service_consumer.h"
 #include "content/public/browser/notification_service.h"
 
 using autofill_helper::GetPersonalDataManager;
+using autofill_helper::GetProfileWebDataService;
+using autofill_helper::GetAccountWebDataService;
 
 namespace {
 
@@ -34,6 +38,40 @@
 const sync_pb::WalletMaskedCreditCard_WalletCardType kDefaultCardType =
     sync_pb::WalletMaskedCreditCard::AMEX;
 
+template <class T>
+class AutofillWebDataServiceConsumer : public WebDataServiceConsumer {
+ public:
+  AutofillWebDataServiceConsumer() {}
+
+  virtual ~AutofillWebDataServiceConsumer() {}
+
+  void OnWebDataServiceRequestDone(
+      WebDataServiceBase::Handle handle,
+      std::unique_ptr<WDTypedResult> result) override {
+    result_ = std::move(static_cast<WDResult<T>*>(result.get())->GetValue());
+    run_loop_.Quit();
+  }
+
+  void Wait() { run_loop_.Run(); }
+
+  T& result() { return result_; }
+
+ private:
+  base::RunLoop run_loop_;
+  T result_;
+  DISALLOW_COPY_AND_ASSIGN(AutofillWebDataServiceConsumer);
+};
+
+std::vector<std::unique_ptr<autofill::CreditCard>> GetServerCards(
+    scoped_refptr<autofill::AutofillWebDataService> service) {
+  AutofillWebDataServiceConsumer<
+      std::vector<std::unique_ptr<autofill::CreditCard>>>
+      consumer;
+  service->GetServerCreditCards(&consumer);
+  consumer.Wait();
+  return std::move(consumer.result());
+}
+
 void AddDefaultCard(fake_server::FakeServer* server) {
   sync_pb::EntitySpecifics specifics;
   sync_pb::AutofillWalletSpecifics* wallet_specifics =
@@ -113,24 +151,75 @@
       syncer::AUTOFILL_WALLET_METADATA));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, Download) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, DownloadProfileStorage) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      // Enabled.
+      {},
+      // Disabled.
+      {autofill::features::kAutofillEnableAccountWalletStorage});
   AddDefaultCard(GetFakeServer());
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
 
+  auto profile_data = GetProfileWebDataService(0);
+  ASSERT_NE(nullptr, profile_data);
+  auto account_data = GetAccountWebDataService(0);
+  ASSERT_EQ(nullptr, account_data);
+
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
   std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
 
   autofill::CreditCard* card = cards[0];
-  ASSERT_EQ(autofill::CreditCard::MASKED_SERVER_CARD, card->record_type());
-  ASSERT_EQ(kDefaultCardID, card->server_id());
-  ASSERT_EQ(base::UTF8ToUTF16(kDefaultCardLastFour), card->LastFourDigits());
-  ASSERT_EQ(autofill::kAmericanExpressCard, card->network());
-  ASSERT_EQ(kDefaultCardExpMonth, card->expiration_month());
-  ASSERT_EQ(kDefaultCardExpYear, card->expiration_year());
-  ASSERT_EQ(base::UTF8ToUTF16(kDefaultCardName),
+  EXPECT_EQ(autofill::CreditCard::MASKED_SERVER_CARD, card->record_type());
+  EXPECT_EQ(kDefaultCardID, card->server_id());
+  EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardLastFour), card->LastFourDigits());
+  EXPECT_EQ(autofill::kAmericanExpressCard, card->network());
+  EXPECT_EQ(kDefaultCardExpMonth, card->expiration_month());
+  EXPECT_EQ(kDefaultCardExpYear, card->expiration_year());
+  EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardName),
             card->GetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL));
+
+  // Check that the card is stored in the profile storage.
+  EXPECT_EQ(1U, GetServerCards(GetProfileWebDataService(0)).size());
+}
+
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, DownloadAccountStorage) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      // Enabled.
+      {autofill::features::kAutofillEnableAccountWalletStorage},
+      // Disabled.
+      {});
+  AddDefaultCard(GetFakeServer());
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+
+  auto profile_data = GetProfileWebDataService(0);
+  ASSERT_NE(nullptr, profile_data);
+  auto account_data = GetAccountWebDataService(0);
+  ASSERT_NE(nullptr, account_data);
+
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+  std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+
+  autofill::CreditCard* card = cards[0];
+  EXPECT_EQ(autofill::CreditCard::MASKED_SERVER_CARD, card->record_type());
+  EXPECT_EQ(kDefaultCardID, card->server_id());
+  EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardLastFour), card->LastFourDigits());
+  EXPECT_EQ(autofill::kAmericanExpressCard, card->network());
+  EXPECT_EQ(kDefaultCardExpMonth, card->expiration_month());
+  EXPECT_EQ(kDefaultCardExpYear, card->expiration_year());
+  EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardName),
+            card->GetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL));
+
+  // Check that the card is *not* stored in the profile storage.
+  EXPECT_EQ(0U, GetServerCards(GetProfileWebDataService(0)).size());
+
+  // Check that the card is stored in the account storage.
+  EXPECT_EQ(1U, GetServerCards(GetAccountWebDataService(0)).size());
 }
 
 // Wallet data should get cleared from the database when sync is disabled.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0a6fd64..3b35f12 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2687,10 +2687,10 @@
       "views/try_chrome_dialog_win/try_chrome_dialog.h",
       "views/uninstall_view.cc",
       "views/uninstall_view.h",
-      "webui/conflicts_handler.cc",
-      "webui/conflicts_handler.h",
-      "webui/conflicts_ui.cc",
-      "webui/conflicts_ui.h",
+      "webui/conflicts/conflicts_handler.cc",
+      "webui/conflicts/conflicts_handler.h",
+      "webui/conflicts/conflicts_ui.cc",
+      "webui/conflicts/conflicts_ui.h",
       "webui/settings/chrome_cleanup_handler.cc",
       "webui/settings/chrome_cleanup_handler.h",
       "webui/settings_utils_win.cc",
diff --git a/chrome/browser/ui/ash/ash_shell_init.cc b/chrome/browser/ui/ash/ash_shell_init.cc
index 48e20e1..9ce7976f 100644
--- a/chrome/browser/ui/ash/ash_shell_init.cc
+++ b/chrome/browser/ui/ash/ash_shell_init.cc
@@ -11,10 +11,10 @@
 #include "ash/shell.h"
 #include "ash/shell_init_params.h"
 #include "ash/shell_port_classic.h"
-#include "ash/window_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 #include "content/public/browser/context_factory.h"
+#include "ui/aura/window_tree_host.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index a89af16..9327ba7 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -453,7 +453,7 @@
                                            : ash::mojom::UpdateType::FLASH;
 
   system_tray_->ShowUpdateIcon(severity, detector->is_factory_reset_required(),
-                               update_type);
+                               detector->is_rollback(), update_type);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm b/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm
index 636064cf..c50f112 100644
--- a/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm
+++ b/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm
@@ -362,6 +362,14 @@
   [view setFrameOrigin:NSZeroPoint];
   [[containerView superview] setFrameOrigin:NSZeroPoint];
   [containerView setFrameOrigin:NSMakePoint(kLeftPadding, 0)];
+
+  if (containerView.isHidden)
+    return;
+
+  // Remove and re-add menu item so menu gets the correct size.
+  NSInteger index = [[self menu] indexOfItem:browserActionsMenuItem_];
+  [[self menu] removeItemAtIndex:index];
+  [[self menu] insertItem:browserActionsMenuItem_ atIndex:index];
 }
 
 - (void)menuWillOpen:(NSMenu*)menu {
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
index 191d7ad..16714c67 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
@@ -76,7 +76,7 @@
             browser()->profile()));
     EXPECT_CALL(*mock_sync_service_1_, IsFirstSetupComplete())
         .WillRepeatedly(Return(false));
-    EXPECT_CALL(*mock_sync_service_1_, IsFirstSetupInProgress())
+    EXPECT_CALL(*mock_sync_service_1_, IsSetupInProgress())
         .WillRepeatedly(Return(true));
     EXPECT_CALL(*mock_sync_service_1_, IsSyncConfirmationNeeded())
         .WillRepeatedly(Return(false));
@@ -105,7 +105,7 @@
 
     EXPECT_CALL(*mock_sync_service_2_, IsFirstSetupComplete())
         .WillRepeatedly(Return(false));
-    EXPECT_CALL(*mock_sync_service_2_, IsFirstSetupInProgress())
+    EXPECT_CALL(*mock_sync_service_2_, IsSetupInProgress())
         .WillRepeatedly(Return(true));
     EXPECT_CALL(*mock_sync_service_2_, IsSyncConfirmationNeeded())
         .WillRepeatedly(Return(false));
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
index 0515de3..91711e9 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
@@ -63,14 +63,18 @@
             Profile::FromBrowserContext(profile))));
   }
 
-  bool IsFirstSetupInProgress() const override {
-    return first_setup_in_progress_;
-  }
+  bool IsFirstSetupComplete() const override { return first_setup_complete_; }
+
+  bool IsSetupInProgress() const override { return setup_in_progress_; }
 
   State GetState() const override { return state_; }
 
-  void set_first_setup_in_progress(bool in_progress) {
-    first_setup_in_progress_ = in_progress;
+  void set_first_setup_complete(bool complete) {
+    first_setup_complete_ = complete;
+  }
+
+  void set_setup_in_progress(bool in_progress) {
+    setup_in_progress_ = in_progress;
   }
 
   void set_state(State state) { state_ = state; }
@@ -78,10 +82,12 @@
  private:
   explicit OneClickTestProfileSyncService(InitParams init_params)
       : browser_sync::TestProfileSyncService(std::move(init_params)),
-        first_setup_in_progress_(false),
+        first_setup_complete_(false),
+        setup_in_progress_(false),
         state_(State::INITIALIZING) {}
 
-  bool first_setup_in_progress_;
+  bool first_setup_complete_;
+  bool setup_in_progress_;
   State state_;
 
   DISALLOW_COPY_AND_ASSIGN(OneClickTestProfileSyncService);
@@ -198,7 +204,8 @@
 TEST_F(OneClickSigninSyncObserverTest,
        OnSyncStateChanged_SyncConfiguredSuccessfully) {
   CreateSyncObserver(kContinueUrl);
-  sync_service_->set_first_setup_in_progress(false);
+  sync_service_->set_first_setup_complete(true);
+  sync_service_->set_setup_in_progress(false);
   sync_service_->set_state(syncer::SyncService::State::ACTIVE);
 
   EXPECT_CALL(*web_contents_observer_, DidStartNavigation(_));
@@ -211,7 +218,8 @@
 TEST_F(OneClickSigninSyncObserverTest,
        OnSyncStateChanged_SyncConfigurationFailed) {
   CreateSyncObserver(kContinueUrl);
-  sync_service_->set_first_setup_in_progress(false);
+  sync_service_->set_first_setup_complete(true);
+  sync_service_->set_setup_in_progress(false);
   sync_service_->set_state(syncer::SyncService::State::INITIALIZING);
 
   EXPECT_CALL(*web_contents_observer_, DidStartNavigation(_)).Times(0);
@@ -224,7 +232,8 @@
 TEST_F(OneClickSigninSyncObserverTest,
        OnSyncStateChanged_SyncConfigurationInProgress) {
   CreateSyncObserver(kContinueUrl);
-  sync_service_->set_first_setup_in_progress(true);
+  sync_service_->set_first_setup_complete(false);
+  sync_service_->set_setup_in_progress(true);
   sync_service_->set_state(syncer::SyncService::State::INITIALIZING);
 
   EXPECT_CALL(*web_contents_observer_, DidStartNavigation(_)).Times(0);
@@ -243,7 +252,8 @@
       signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
       signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT, false);
   CreateSyncObserver(continue_url.spec());
-  sync_service_->set_first_setup_in_progress(false);
+  sync_service_->set_first_setup_complete(true);
+  sync_service_->set_setup_in_progress(false);
   sync_service_->set_state(syncer::SyncService::State::ACTIVE);
 
   EXPECT_CALL(*web_contents_observer_, DidStartNavigation(_)).Times(0);
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index 72821f5e..9de17f6 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -642,9 +642,12 @@
   scroll_view_->set_draw_overflow_indicator(false);
   scroll_view_->ClipHeightTo(0, body_container->GetPreferredSize().height());
 
-  // Use an additional container to apply padding outside the scroll view.
-  // This ensures that the rounded corners appear properly by cutting them
-  // out of normal, static padding.
+  // Use an additional container to apply padding outside the scroll view, so
+  // that the padding area is stationary. This ensures that the rounded corners
+  // appear properly; on Mac, the clipping path will not apply properly to a
+  // scrollable area.
+  // NOTE: GetContentsVerticalPadding is guaranteed to return a size which
+  // accommodates the rounded corners.
   views::View* padding_wrapper = new views::View();
   padding_wrapper->SetBorder(
       views::CreateEmptyBorder(gfx::Insets(GetContentsVerticalPadding(), 0)));
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index 6503545f..38e21da 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -344,20 +344,17 @@
 void ImmersiveModeControllerAsh::OnWindowPropertyChanged(aura::Window* window,
                                                          const void* key,
                                                          intptr_t old) {
-  if (key == ash::kWindowStateTypeKey) {
-    ash::mojom::WindowStateType new_state =
-        window->GetProperty(ash::kWindowStateTypeKey);
-    ash::mojom::WindowStateType old_state = ash::mojom::WindowStateType(old);
+  if (key == aura::client::kShowStateKey) {
+    ui::WindowShowState new_state =
+        window->GetProperty(aura::client::kShowStateKey);
+    auto old_state = static_cast<ui::WindowShowState>(old);
 
     // Disable immersive fullscreen when the user exits fullscreen without going
     // through FullscreenController::ToggleBrowserFullscreenMode(). This is the
     // case if the user exits fullscreen via the restore button.
-    if (controller_->IsEnabled() &&
-        new_state != ash::mojom::WindowStateType::FULLSCREEN &&
-        new_state != ash::mojom::WindowStateType::PINNED &&
-        new_state != ash::mojom::WindowStateType::TRUSTED_PINNED &&
-        new_state != ash::mojom::WindowStateType::MINIMIZED &&
-        old_state == ash::mojom::WindowStateType::FULLSCREEN) {
+    if (controller_->IsEnabled() && new_state != ui::SHOW_STATE_FULLSCREEN &&
+        new_state != ui::SHOW_STATE_MINIMIZED &&
+        old_state == ui::SHOW_STATE_FULLSCREEN) {
       browser_view_->FullscreenStateChanged();
     }
   }
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
index 2cc40bb..79fbdfd 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_view.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
@@ -121,7 +121,6 @@
 }
 
 bool CastDialogView::Accept() {
-  scroll_position_ = scroll_view_->GetVisibleRect().y();
   const UIMediaSink& sink = GetSelectedSink();
   if (!sink.route_id.empty()) {
     controller_->StopCasting(sink.route_id);
@@ -147,6 +146,7 @@
 
 void CastDialogView::OnModelUpdated(const CastDialogModel& model) {
   if (model.media_sinks().empty()) {
+    scroll_position_ = 0;
     ShowNoSinksView();
   } else {
     // If |sink_buttons_| is empty, the sink list was empty before this update.
@@ -154,7 +154,10 @@
     // stopped with one click.
     if (sink_buttons_.empty())
       selected_sink_index_ = model.GetFirstActiveSinkIndex().value_or(0);
-    ShowScrollView();
+    if (scroll_view_)
+      scroll_position_ = scroll_view_->GetVisibleRect().y();
+    else
+      ShowScrollView();
     PopulateScrollView(model.media_sinks());
     RestoreSinkListState();
     metrics_.OnSinksLoaded(base::Time::Now());
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 28b8373..9e6fb7c 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -242,6 +242,80 @@
 
 TabDragController::TabDragData::TabDragData(TabDragData&&) = default;
 
+#if defined(OS_CHROMEOS)
+
+// The class to track the current deferred target tabstrip and also to observe
+// its native window's property ash::kIsDeferredTabDraggingTargetWindowKey.
+// The reason we need to observe the window property is the property might be
+// cleared outside of TabDragController (i.e. by ash), and we should update the
+// tracked deferred target tabstrip in this case.
+class TabDragController::DeferredTargetTabstripObserver
+    : public aura::WindowObserver {
+ public:
+  DeferredTargetTabstripObserver() = default;
+  ~DeferredTargetTabstripObserver() override {
+    if (deferred_target_tabstrip_) {
+      deferred_target_tabstrip_->GetWidget()->GetNativeWindow()->RemoveObserver(
+          this);
+      deferred_target_tabstrip_ = nullptr;
+    }
+  }
+
+  void SetDeferredTargetTabstrip(TabStrip* deferred_target_tabstrip) {
+    if (deferred_target_tabstrip_ == deferred_target_tabstrip)
+      return;
+
+    // Clear the window property on the previous |deferred_target_tabstrip_|.
+    if (deferred_target_tabstrip_) {
+      aura::Window* old_window =
+          deferred_target_tabstrip_->GetWidget()->GetNativeWindow();
+      old_window->RemoveObserver(this);
+      old_window->ClearProperty(ash::kIsDeferredTabDraggingTargetWindowKey);
+    }
+
+    deferred_target_tabstrip_ = deferred_target_tabstrip;
+
+    // Set the window property on the new |deferred_target_tabstrip_|.
+    if (deferred_target_tabstrip_) {
+      aura::Window* new_window =
+          deferred_target_tabstrip_->GetWidget()->GetNativeWindow();
+      new_window->SetProperty(ash::kIsDeferredTabDraggingTargetWindowKey, true);
+      new_window->AddObserver(this);
+    }
+  }
+
+  // aura::WindowObserver:
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override {
+    DCHECK_EQ(window,
+              deferred_target_tabstrip_->GetWidget()->GetNativeWindow());
+
+    if (key == ash::kIsDeferredTabDraggingTargetWindowKey &&
+        !window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey)) {
+      SetDeferredTargetTabstrip(nullptr);
+    }
+
+    // else do nothing. currently it's only possible that ash clears the window
+    // property, but doesn't set the window property.
+  }
+
+  void OnWindowDestroying(aura::Window* window) override {
+    DCHECK_EQ(window,
+              deferred_target_tabstrip_->GetWidget()->GetNativeWindow());
+    SetDeferredTargetTabstrip(nullptr);
+  }
+
+  TabStrip* deferred_target_tabstrip() { return deferred_target_tabstrip_; }
+
+ private:
+  TabStrip* deferred_target_tabstrip_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(DeferredTargetTabstripObserver);
+};
+
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // TabDragController, public:
 
@@ -468,11 +542,14 @@
   if (reason == END_DRAG_CAPTURE_LOST && is_dragging_window_)
     return;
 
+#if defined(OS_CHROMEOS)
   // It's possible that in Chrome OS we defer the windows that are showing in
   // overview to attach into during dragging. If so we need to attach the
   // dragged tabs to it first.
-  if (reason == END_DRAG_COMPLETE && deferred_target_tabstrip_)
+  if (reason == END_DRAG_COMPLETE && deferred_target_tabstrip_observer_)
     PerformDeferredAttach();
+#endif
+
   EndDragImpl(reason != END_DRAG_COMPLETE && source_tabstrip_ ?
               CANCELED : NORMAL);
 }
@@ -1473,8 +1550,13 @@
 }
 
 void TabDragController::PerformDeferredAttach() {
-  DCHECK(deferred_target_tabstrip_);
-  DCHECK_NE(deferred_target_tabstrip_, attached_tabstrip_);
+#if defined(OS_CHROMEOS)
+  TabStrip* deferred_target_tabstrip =
+      deferred_target_tabstrip_observer_->deferred_target_tabstrip();
+  if (!deferred_target_tabstrip)
+    return;
+
+  DCHECK_NE(deferred_target_tabstrip, attached_tabstrip_);
 
   // |is_dragging_new_browser_| needs to be reset here since after this function
   // is called, the browser window that was specially created for the dragged
@@ -1487,12 +1569,15 @@
   // after the drag ends.
   did_restore_window_ = false;
 
-  TabStrip* target_tabstrip = deferred_target_tabstrip_;
+  TabStrip* target_tabstrip = deferred_target_tabstrip;
   SetDeferredTargetTabstrip(nullptr);
+  deferred_target_tabstrip_observer_.reset();
+
   Detach(DONT_RELEASE_CAPTURE);
   // If we're attaching the dragged tabs to an overview window's tabstrip, the
   // tabstrip should not have focus.
   Attach(target_tabstrip, GetCursorScreenPoint(), /*set_capture=*/false);
+#endif
 }
 
 void TabDragController::RevertDrag() {
@@ -2016,19 +2101,11 @@
 void TabDragController::SetDeferredTargetTabstrip(
     TabStrip* deferred_target_tabstrip) {
 #if defined(OS_CHROMEOS)
-  if (deferred_target_tabstrip_ == deferred_target_tabstrip)
-    return;
-
-  // Clear the window property on the previous |deferred_target_tabstrip_|.
-  if (deferred_target_tabstrip_) {
-    deferred_target_tabstrip_->GetWidget()->GetNativeWindow()->ClearProperty(
-        ash::kIsDeferredTabDraggingTargetWindowKey);
+  if (!deferred_target_tabstrip_observer_) {
+    deferred_target_tabstrip_observer_ =
+        std::make_unique<DeferredTargetTabstripObserver>();
   }
-  deferred_target_tabstrip_ = deferred_target_tabstrip;
-  // Set the window property on the new |deferred_target_tabstrip_|.
-  if (deferred_target_tabstrip_) {
-    deferred_target_tabstrip_->GetWidget()->GetNativeWindow()->SetProperty(
-        ash::kIsDeferredTabDraggingTargetWindowKey, true);
-  }
+  deferred_target_tabstrip_observer_->SetDeferredTargetTabstrip(
+      deferred_target_tabstrip);
 #endif
 }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index 6af7ec79..a007fed 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -221,6 +221,10 @@
 
   typedef std::vector<TabDragData> DragData;
 
+#if defined(OS_CHROMEOS)
+  class DeferredTargetTabstripObserver;
+#endif
+
   // Sets |drag_data| from |tab|. This also registers for necessary
   // notifications and resets the delegate of the WebContents.
   void InitTabDragData(Tab* tab, TabDragData* drag_data);
@@ -500,10 +504,14 @@
   // dragged Tab is detached.
   TabStrip* attached_tabstrip_;
 
-  // The target TabStrip to attach to after the drag ends. It's only possible
-  // to happen in Chrome OS tablet mode, if the dragged tabs are dragged over
-  // an overview window, we should wait until the drag ends to attach it.
-  TabStrip* deferred_target_tabstrip_ = nullptr;
+#if defined(OS_CHROMEOS)
+  // Observe the target TabStrip to attach to after the drag ends. It's only
+  // possible to happen in Chrome OS tablet mode, if the dragged tabs are
+  // dragged over an overview window, we should wait until the drag ends to
+  // attach it.
+  std::unique_ptr<DeferredTargetTabstripObserver>
+      deferred_target_tabstrip_observer_;
+#endif
 
   // Whether capture can be released during the drag. When false, capture should
   // not be released when transferring capture between widgets and when starting
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 8493be2..ac4645f 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -2883,6 +2883,77 @@
   EXPECT_EQ(3u, browser_list->size());
 }
 
+namespace {
+
+void DeferredTargetTabStripTestStep2(DetachToBrowserTabDragControllerTest* test,
+                                     TabStrip* not_attached_tab_strip,
+                                     TabStrip* target_tab_strip) {
+  ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
+  ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
+  ASSERT_TRUE(TabDragController::IsActive());
+
+  // And there should be three browser windows, incluing the newly created one
+  // for the dragged tab.
+  EXPECT_EQ(3u, test->browser_list->size());
+
+  // Put the window that accociated with |target_tab_strip| in overview.
+  target_tab_strip->GetWidget()->GetNativeWindow()->SetProperty(
+      ash::kIsShowingInOverviewKey, true);
+
+  // Drag to target_tab_strip.
+  gfx::Point target_point(target_tab_strip->width() / 2,
+                          target_tab_strip->height() / 2);
+  views::View::ConvertPointToScreen(target_tab_strip, &target_point);
+  ASSERT_TRUE(test->DragInputTo(target_point));
+
+  // At this point, |target_tab_strip| should be the deferred target tabstip.
+  // Theoratically the dragged tabstrip will merge into |target_tab_strip| after
+  // the drag ends.
+  EXPECT_TRUE(target_tab_strip->GetWidget()->GetNativeWindow()->GetProperty(
+      ash::kIsDeferredTabDraggingTargetWindowKey));
+
+  // Now clear the property.
+  target_tab_strip->GetWidget()->GetNativeWindow()->ClearProperty(
+      ash::kIsDeferredTabDraggingTargetWindowKey);
+
+  if (test->input_source() == INPUT_SOURCE_TOUCH)
+    ASSERT_TRUE(test->ReleaseInput());
+  else
+    ASSERT_TRUE(test->ReleaseMouseAsync());
+}
+
+}  // namespace
+
+// Test that if a tabstrip is a deferred target tabstrip, and its corresponding
+// window key is cleared to remove itself as the deferred target tabstrip, the
+// dragged tabstrip should not attach into it after the drag ends.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       DeferredTargetTabStripTest) {
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+
+  // Add another tab to browser().
+  AddTabAndResetBrowser(browser());
+
+  // Create another browser.
+  Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
+
+  // Move to the first tab and drag it enough so that it detaches, but not
+  // enough that it attaches to browser2.
+  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
+  ASSERT_TRUE(PressInput(tab_0_center));
+  ASSERT_TRUE(DragInputToNotifyWhenDone(
+      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
+      base::BindOnce(&DeferredTargetTabStripTestStep2, this, tab_strip,
+                     tab_strip2)));
+  QuitWhenNotDragging();
+
+  // Now the dragged tab should not be attached to the target tabstrip after
+  // the drag ends.
+  ASSERT_FALSE(TabDragController::IsActive());
+  EXPECT_EQ(3u, browser_list->size());
+}
+
 #endif  // OS_CHROMEOS
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index ff193431..0144814 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -234,6 +234,8 @@
 }
 
 void BrowserAppMenuButton::SetTrailingMargin(int margin) {
+  if (margin == margin_trailing_)
+    return;
   margin_trailing_ = margin;
   UpdateThemedBorder();
   InvalidateLayout();
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 97eb43c..be8b073 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -180,7 +180,7 @@
 #endif
 
 #if defined(OS_WIN)
-#include "chrome/browser/ui/webui/conflicts_ui.h"
+#include "chrome/browser/ui/webui/conflicts/conflicts_ui.h"
 #include "chrome/browser/ui/webui/set_as_default_browser_ui_win.h"
 #include "chrome/browser/ui/webui/welcome_win10_ui.h"
 #endif
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc
index 8ad3c43..9a78b6b 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc
@@ -62,67 +62,86 @@
 using SettingZippyList = google::protobuf::RepeatedPtrField<
     assistant::ClassicActivityControlUiTexts::SettingZippy>;
 // Helper method to create zippy data.
-base::ListValue CreateZippyData(const SettingZippyList& zippy_list) {
-  base::ListValue zippy_data;
+base::Value CreateZippyData(const SettingZippyList& zippy_list) {
+  base::Value zippy_data(base::Value::Type::LIST);
   for (auto& setting_zippy : zippy_list) {
-    base::DictionaryValue data;
-    data.SetString("title", setting_zippy.title());
+    base::Value data(base::Value::Type::DICTIONARY);
+    data.SetKey("title", base::Value(setting_zippy.title()));
     if (setting_zippy.description_paragraph_size()) {
-      data.SetString("description", setting_zippy.description_paragraph(0));
+      data.SetKey("description",
+                  base::Value(setting_zippy.description_paragraph(0)));
     }
     if (setting_zippy.additional_info_paragraph_size()) {
-      data.SetString("additionalInfo",
-                     setting_zippy.additional_info_paragraph(0));
+      data.SetKey("additionalInfo",
+                  base::Value(setting_zippy.additional_info_paragraph(0)));
     }
-    data.SetString("iconUri", setting_zippy.icon_uri());
+    data.SetKey("iconUri", base::Value(setting_zippy.icon_uri()));
     zippy_data.GetList().push_back(std::move(data));
   }
   return zippy_data;
 }
 
 // Helper method to create disclosure data.
-base::ListValue CreateDisclosureData(const SettingZippyList& disclosure_list) {
-  base::ListValue disclosure_data;
+base::Value CreateDisclosureData(const SettingZippyList& disclosure_list) {
+  base::Value disclosure_data(base::Value::Type::LIST);
   for (auto& disclosure : disclosure_list) {
-    base::DictionaryValue data;
-    data.SetString("title", disclosure.title());
+    base::Value data(base::Value::Type::DICTIONARY);
+    data.SetKey("title", base::Value(disclosure.title()));
     if (disclosure.description_paragraph_size()) {
-      data.SetString("description", disclosure.description_paragraph(0));
+      data.SetKey("description",
+                  base::Value(disclosure.description_paragraph(0)));
     }
     if (disclosure.additional_info_paragraph_size()) {
-      data.SetString("additionalInfo", disclosure.additional_info_paragraph(0));
+      data.SetKey("additionalInfo",
+                  base::Value(disclosure.additional_info_paragraph(0)));
     }
-    data.SetString("iconUri", disclosure.icon_uri());
+    data.SetKey("iconUri", base::Value(disclosure.icon_uri()));
     disclosure_data.GetList().push_back(std::move(data));
   }
   return disclosure_data;
 }
 
 // Helper method to create get more screen data.
-base::ListValue CreateGetMoreData(
-    bool email_optin_needed,
-    const assistant::EmailOptInUi& email_optin_ui) {
-  base::ListValue get_more_data;
+base::Value CreateGetMoreData(bool email_optin_needed,
+                              const assistant::EmailOptInUi& email_optin_ui) {
+  base::Value get_more_data(base::Value::Type::LIST);
+
+  // Process hotword data.
+  base::Value hotword_data(base::Value::Type::DICTIONARY);
+  hotword_data.SetKey(
+      "title",
+      base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_HOTWORD_TITLE)));
+  hotword_data.SetKey(
+      "description",
+      base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_HOTWORD_DESC)));
+  hotword_data.SetKey("defaultEnabled", base::Value(true));
+  hotword_data.SetKey(
+      "iconUri",
+      base::Value("https://www.gstatic.com/images/icons/material/system/"
+                  "2x/mic_none_grey600_48dp.png"));
+  get_more_data.GetList().push_back(std::move(hotword_data));
 
   // Process screen context data.
-  base::DictionaryValue context_data;
-  context_data.SetString(
-      "title", l10n_util::GetStringUTF16(IDS_ASSISTANT_SCREEN_CONTEXT_TITLE));
-  context_data.SetString("description", l10n_util::GetStringUTF16(
-                                            IDS_ASSISTANT_SCREEN_CONTEXT_DESC));
-  context_data.SetBoolean("defaultEnabled", true);
-  context_data.SetString("iconUri",
-                         "https://www.gstatic.com/images/icons/material/system/"
-                         "2x/laptop_chromebook_grey600_24dp.png");
+  base::Value context_data(base::Value::Type::DICTIONARY);
+  context_data.SetKey("title", base::Value(l10n_util::GetStringUTF16(
+                                   IDS_ASSISTANT_SCREEN_CONTEXT_TITLE)));
+  context_data.SetKey("description", base::Value(l10n_util::GetStringUTF16(
+                                         IDS_ASSISTANT_SCREEN_CONTEXT_DESC)));
+  context_data.SetKey("defaultEnabled", base::Value(true));
+  context_data.SetKey(
+      "iconUri",
+      base::Value("https://www.gstatic.com/images/icons/material/system/"
+                  "2x/laptop_chromebook_grey600_24dp.png"));
   get_more_data.GetList().push_back(std::move(context_data));
 
   // Process email optin data.
   if (email_optin_needed) {
-    base::DictionaryValue data;
-    data.SetString("title", email_optin_ui.title());
-    data.SetString("description", email_optin_ui.description());
-    data.SetBoolean("defaultEnabled", email_optin_ui.default_enabled());
-    data.SetString("iconUri", email_optin_ui.icon_uri());
+    base::Value data(base::Value::Type::DICTIONARY);
+    data.SetKey("title", base::Value(email_optin_ui.title()));
+    data.SetKey("description", base::Value(email_optin_ui.description()));
+    data.SetKey("defaultEnabled",
+                base::Value(email_optin_ui.default_enabled()));
+    data.SetKey("iconUri", base::Value(email_optin_ui.icon_uri()));
     get_more_data.GetList().push_back(std::move(data));
   }
 
@@ -130,73 +149,72 @@
 }
 
 // Get string constants for settings ui.
-base::DictionaryValue GetSettingsUiStrings(
-    const assistant::SettingsUi& settings_ui,
-    bool activity_control_needed) {
+base::Value GetSettingsUiStrings(const assistant::SettingsUi& settings_ui,
+                                 bool activity_control_needed) {
   auto consent_ui = settings_ui.consent_flow_ui().consent_ui();
   auto confirm_reject_ui = consent_ui.activity_control_confirm_reject_ui();
   auto activity_control_ui = consent_ui.activity_control_ui();
   auto third_party_disclosure_ui = consent_ui.third_party_disclosure_ui();
-  base::DictionaryValue dictionary;
+  base::Value dictionary(base::Value::Type::DICTIONARY);
 
   // Add activity controll string constants.
   if (activity_control_needed) {
-    dictionary.SetString("valuePropIdentity", activity_control_ui.identity());
+    dictionary.SetKey("valuePropIdentity",
+                      base::Value(activity_control_ui.identity()));
     if (activity_control_ui.intro_text_paragraph_size()) {
-      dictionary.SetString("valuePropIntro",
-                           activity_control_ui.intro_text_paragraph(0));
+      dictionary.SetKey(
+          "valuePropIntro",
+          base::Value(activity_control_ui.intro_text_paragraph(0)));
     }
     if (activity_control_ui.footer_paragraph_size()) {
-      dictionary.SetString("valuePropFooter",
-                           activity_control_ui.footer_paragraph(0));
+      dictionary.SetKey("valuePropFooter",
+                        base::Value(activity_control_ui.footer_paragraph(0)));
     }
-    dictionary.SetString("valuePropNextButton",
-                         consent_ui.accept_button_text());
-    dictionary.SetString("valuePropSkipButton",
-                         consent_ui.reject_button_text());
+    dictionary.SetKey("valuePropNextButton",
+                      base::Value(consent_ui.accept_button_text()));
+    dictionary.SetKey("valuePropSkipButton",
+                      base::Value(consent_ui.reject_button_text()));
   }
 
   // Add confirm reject screen string constants.
   // TODO(updowndota) Use remote strings after server bug fixed.
-  dictionary.SetString(
-      "confirmRejectTitle",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONFIRM_SCREEN_TITLE));
-  dictionary.SetString(
-      "confirmRejectAcceptTitle",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONFIRM_SCREEN_ACCEPT_TITLE));
-  dictionary.SetString(
-      "confirmRejectAcceptMessage",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONFIRM_SCREEN_ACCEPT_MESSAGE));
-  dictionary.SetString(
-      "confirmRejectAcceptMessageExpanded",
-      l10n_util::GetStringUTF16(
-          IDS_ASSISTANT_CONFIRM_SCREEN_ACCEPT_MESSAGE_EXPANDED));
-  dictionary.SetString(
-      "confirmRejectRejectTitle",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONFIRM_SCREEN_REJECT_TITLE));
-  dictionary.SetString(
-      "confirmRejectRejectMessage",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONFIRM_SCREEN_REJECT_MESSAGE));
-  dictionary.SetString(
+  dictionary.SetKey("confirmRejectTitle",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_CONFIRM_SCREEN_TITLE)));
+  dictionary.SetKey("confirmRejectAcceptTitle",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_CONFIRM_SCREEN_ACCEPT_TITLE)));
+  dictionary.SetKey("confirmRejectAcceptMessage",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_CONFIRM_SCREEN_ACCEPT_MESSAGE)));
+  dictionary.SetKey("confirmRejectAcceptMessageExpanded",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_CONFIRM_SCREEN_ACCEPT_MESSAGE_EXPANDED)));
+  dictionary.SetKey("confirmRejectRejectTitle",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_CONFIRM_SCREEN_REJECT_TITLE)));
+  dictionary.SetKey("confirmRejectRejectMessage",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_CONFIRM_SCREEN_REJECT_MESSAGE)));
+  dictionary.SetKey(
       "confirmRejectContinueButton",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONTINUE_BUTTON));
+      base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_CONTINUE_BUTTON)));
 
   // Add third party string constants.
-  dictionary.SetString(
-      "thirdPartyTitle",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_THIRD_PARTY_SCREEN_TITLE));
-  dictionary.SetString(
+  dictionary.SetKey("thirdPartyTitle",
+                    base::Value(l10n_util::GetStringUTF16(
+                        IDS_ASSISTANT_THIRD_PARTY_SCREEN_TITLE)));
+  dictionary.SetKey(
       "thirdPartyContinueButton",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONTINUE_BUTTON));
-  dictionary.SetString("thirdPartyFooter", consent_ui.tos_pp_links());
+      base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_CONTINUE_BUTTON)));
+  dictionary.SetKey("thirdPartyFooter", base::Value(consent_ui.tos_pp_links()));
 
   // Add get more screen string constants.
-  dictionary.SetString(
-      "getMoreTitle",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_GET_MORE_SCREEN_TITLE));
-  dictionary.SetString(
+  dictionary.SetKey("getMoreTitle", base::Value(l10n_util::GetStringUTF16(
+                                        IDS_ASSISTANT_GET_MORE_SCREEN_TITLE)));
+  dictionary.SetKey(
       "getMoreContinueButton",
-      l10n_util::GetStringUTF16(IDS_ASSISTANT_CONTINUE_BUTTON));
+      base::Value(l10n_util::GetStringUTF16(IDS_ASSISTANT_CONTINUE_BUTTON)));
 
   return dictionary;
 }
@@ -219,6 +237,7 @@
 
 void AssistantOptInHandler::RegisterMessages() {
   AddCallback("initialized", &AssistantOptInHandler::HandleInitialized);
+  AddCallback("hotwordResult", &AssistantOptInHandler::HandleHotwordResult);
 }
 
 void AssistantOptInHandler::Initialize() {
@@ -245,7 +264,6 @@
     prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
                       false);
     prefs->SetBoolean(arc::prefs::kVoiceInteractionEnabled, true);
-    prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled, true);
     CallJSOrDefer("closeDialog");
   }
 }
@@ -290,12 +308,12 @@
                      weak_factory_.GetWeakPtr()));
 }
 
-void AssistantOptInHandler::ReloadContent(const base::DictionaryValue& dict) {
+void AssistantOptInHandler::ReloadContent(const base::Value& dict) {
   CallJSOrDefer("reloadContent", dict);
 }
 
 void AssistantOptInHandler::AddSettingZippy(const std::string& type,
-                                            const base::ListValue& data) {
+                                            const base::Value& data) {
   CallJSOrDefer("addSettingZippy", type, data);
 }
 
@@ -319,7 +337,6 @@
     prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
                       true);
     prefs->SetBoolean(arc::prefs::kVoiceInteractionEnabled, true);
-    prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled, true);
     ShowNextScreen();
   } else {
     AddSettingZippy("settings",
@@ -356,7 +373,6 @@
       prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
                         true);
       prefs->SetBoolean(arc::prefs::kVoiceInteractionEnabled, true);
-      prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled, true);
     }
   }
 
@@ -366,6 +382,12 @@
       // TODO(updowndta): Handle email optin update failure.
       LOG(ERROR) << "Email OptIn udpate error.";
     }
+    // Update hotword will cause Assistant restart. In order to make sure email
+    // optin request is successfully sent to server, update the hotword after
+    // email optin result has been received.
+    PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
+    prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled,
+                      enable_hotword_);
   }
 
   ShowNextScreen();
@@ -375,4 +397,16 @@
   ExecuteDeferredJSCalls();
 }
 
+void AssistantOptInHandler::HandleHotwordResult(bool enable_hotword) {
+  enable_hotword_ = enable_hotword;
+
+  if (!email_optin_needed_) {
+    // No need to send email optin result. Safe to update hotword pref and
+    // restart Assistant here.
+    PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
+    prefs->SetBoolean(arc::prefs::kVoiceInteractionHotwordEnabled,
+                      enable_hotword);
+  }
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.h b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.h
index 5f3dd0e..f24b409 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.h
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.h
@@ -46,8 +46,8 @@
   void SendGetSettingsRequest();
 
   // Send message and consent data to the page.
-  void ReloadContent(const base::DictionaryValue& dict);
-  void AddSettingZippy(const std::string& type, const base::ListValue& data);
+  void ReloadContent(const base::Value& dict);
+  void AddSettingZippy(const std::string& type, const base::Value& data);
 
   // Handle response from the settings manager.
   void OnGetSettingsResponse(const std::string& settings);
@@ -55,6 +55,7 @@
 
   // Handler for JS WebUI message.
   void HandleInitialized();
+  void HandleHotwordResult(bool enable_hotword);
 
   // Consent token used to complete the opt-in.
   std::string consent_token_;
@@ -65,6 +66,9 @@
   // Whether email optin is needed for user.
   bool email_optin_needed_ = false;
 
+  // Whether user chose to enable hotword.
+  bool enable_hotword_ = true;
+
   assistant::mojom::AssistantSettingsManagerPtr settings_manager_;
   base::WeakPtrFactory<AssistantOptInHandler> weak_factory_;
 
diff --git a/chrome/browser/ui/webui/conflicts/OWNERS b/chrome/browser/ui/webui/conflicts/OWNERS
new file mode 100644
index 0000000..4495bb1
--- /dev/null
+++ b/chrome/browser/ui/webui/conflicts/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/conflicts/OWNERS
diff --git a/chrome/browser/ui/webui/conflicts_handler.cc b/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
similarity index 96%
rename from chrome/browser/ui/webui/conflicts_handler.cc
rename to chrome/browser/ui/webui/conflicts/conflicts_handler.cc
index 4e278e7..5009ff7 100644
--- a/chrome/browser/ui/webui/conflicts_handler.cc
+++ b/chrome/browser/ui/webui/conflicts/conflicts_handler.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/webui/conflicts_handler.h"
+#include "chrome/browser/ui/webui/conflicts/conflicts_handler.h"
 
 #include <utility>
 
@@ -72,6 +72,8 @@
         return "Tolerated - Will be blocked in the future";
       case BlockingDecision::kBlacklisted:
         return "Disallowed - Added to the blacklist";
+      case BlockingDecision::kBlocked:
+        return "Disallowed - Blocked";
       case BlockingDecision::kUnknown:
         NOTREACHED();
         break;
@@ -156,9 +158,14 @@
   }
 #endif  // defined(GOOGLE_CHROME_BUILD)
 
-  base::string16 type_string;
+  std::string type_string;
   if (module_data.module_properties & ModuleInfoData::kPropertyShellExtension)
-    type_string = L"Shell extension";
+    type_string = "Shell extension";
+  if (module_data.module_properties & ModuleInfoData::kPropertyBlocked) {
+    if (!type_string.empty())
+      type_string += ", ";
+    type_string += "blocked";
+  }
   data->SetString("type_description", type_string);
 
   const auto& inspection_result = *module_data.inspection_result;
diff --git a/chrome/browser/ui/webui/conflicts_handler.h b/chrome/browser/ui/webui/conflicts/conflicts_handler.h
similarity index 94%
rename from chrome/browser/ui/webui/conflicts_handler.h
rename to chrome/browser/ui/webui/conflicts/conflicts_handler.h
index f6eeab2..51f0630 100644
--- a/chrome/browser/ui/webui/conflicts_handler.h
+++ b/chrome/browser/ui/webui/conflicts/conflicts_handler.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_WEBUI_CONFLICTS_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CONFLICTS_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_CONFLICTS_CONFLICTS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CONFLICTS_CONFLICTS_HANDLER_H_
 
 #include <memory>
 #include <string>
@@ -93,4 +93,4 @@
   DISALLOW_COPY_AND_ASSIGN(ConflictsHandler);
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CONFLICTS_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_CONFLICTS_CONFLICTS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/conflicts_ui.cc b/chrome/browser/ui/webui/conflicts/conflicts_ui.cc
similarity index 91%
rename from chrome/browser/ui/webui/conflicts_ui.cc
rename to chrome/browser/ui/webui/conflicts/conflicts_ui.cc
index 7e6761cf..38b4f7f1 100644
--- a/chrome/browser/ui/webui/conflicts_ui.cc
+++ b/chrome/browser/ui/webui/conflicts/conflicts_ui.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/conflicts_ui.h"
+#include "chrome/browser/ui/webui/conflicts/conflicts_ui.h"
 
 #include <memory>
 
 #include "base/memory/ref_counted_memory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/conflicts_handler.h"
+#include "chrome/browser/ui/webui/conflicts/conflicts_handler.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chromium_strings.h"
@@ -50,7 +50,7 @@
 
 // static
 base::RefCountedMemory* ConflictsUI::GetFaviconResourceBytes(
-      ui::ScaleFactor scale_factor) {
+    ui::ScaleFactor scale_factor) {
   return static_cast<base::RefCountedMemory*>(
       ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
           IDR_CONFLICT_FAVICON, scale_factor));
diff --git a/chrome/browser/ui/webui/conflicts_ui.h b/chrome/browser/ui/webui/conflicts/conflicts_ui.h
similarity index 77%
rename from chrome/browser/ui/webui/conflicts_ui.h
rename to chrome/browser/ui/webui/conflicts/conflicts_ui.h
index c13d471e..64599d5 100644
--- a/chrome/browser/ui/webui/conflicts_ui.h
+++ b/chrome/browser/ui/webui/conflicts/conflicts_ui.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_WEBUI_CONFLICTS_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CONFLICTS_UI_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_CONFLICTS_CONFLICTS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CONFLICTS_CONFLICTS_UI_H_
 
 #include "base/macros.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -25,4 +25,4 @@
   DISALLOW_COPY_AND_ASSIGN(ConflictsUI);
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CONFLICTS_UI_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_CONFLICTS_CONFLICTS_UI_H_
diff --git a/chrome/browser/ui/webui/help/version_updater.h b/chrome/browser/ui/webui/help/version_updater.h
index 2bfc0d5..ad34cb0 100644
--- a/chrome/browser/ui/webui/help/version_updater.h
+++ b/chrome/browser/ui/webui/help/version_updater.h
@@ -52,15 +52,22 @@
       EolStatusCallback;
 #endif
 
-  // Used to update the client of status changes. int parameter is the progress
-  // and should only be non-zero for the UPDATING state.
-  // std::string parameter is the version of the available update and should be
-  // empty string when update is not available.
-  // int64_t parameter is the size in bytes of the available update and should
-  // be 0 when update is not available.
-  // base::string16 parameter is a message explaining a failure.
-  typedef base::Callback<
-      void(Status, int, const std::string&, int64_t, const base::string16&)>
+  // Used to update the client of status changes.
+  // |status| is the current state of the update.
+  // |progress| should only be non-zero for the UPDATING state.
+  // |rollback| indicates whether the update is actually a rollback, which
+  //     requires wiping the device upon reboot.
+  // |version| is the version of the available update and should be empty string
+  //     when update is not available.
+  // |update_size| is the size of the available update in bytes and should be 0
+  //     when update is not available.
+  // |message| is a message explaining a failure.
+  typedef base::Callback<void(Status status,
+                              int progress,
+                              bool rollback,
+                              const std::string& version,
+                              int64_t update_size,
+                              const base::string16& message)>
       StatusCallback;
 
   // Used to show or hide the promote UI elements. Mac-only.
diff --git a/chrome/browser/ui/webui/help/version_updater_basic.cc b/chrome/browser/ui/webui/help/version_updater_basic.cc
index 8cb85a3..796d0a5 100644
--- a/chrome/browser/ui/webui/help/version_updater_basic.cc
+++ b/chrome/browser/ui/webui/help/version_updater_basic.cc
@@ -11,9 +11,10 @@
     const StatusCallback& status_callback,
     const PromoteCallback&) {
   if (UpgradeDetector::GetInstance()->notify_upgrade())
-    status_callback.Run(NEARLY_UPDATED, 0, std::string(), 0, base::string16());
+    status_callback.Run(NEARLY_UPDATED, 0, false, std::string(), 0,
+                        base::string16());
   else
-    status_callback.Run(DISABLED, 0, std::string(), 0, base::string16());
+    status_callback.Run(DISABLED, 0, false, std::string(), 0, base::string16());
 }
 
 VersionUpdater* VersionUpdater::Create(content::WebContents* web_contents) {
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index 815a49e..66060e64 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -106,7 +106,7 @@
 bool EnsureCanUpdate(bool interactive,
                      const VersionUpdater::StatusCallback& callback) {
   if (IsAutoUpdateDisabled()) {
-    callback.Run(VersionUpdater::DISABLED_BY_ADMIN, 0, std::string(), 0,
+    callback.Run(VersionUpdater::DISABLED_BY_ADMIN, 0, false, std::string(), 0,
                  l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY));
     return false;
   }
@@ -120,13 +120,13 @@
   // to a network for which updates are disallowed.
   NetworkStatus status = GetNetworkStatus(interactive, network);
   if (status == NETWORK_STATUS_OFFLINE) {
-    callback.Run(VersionUpdater::FAILED_OFFLINE, 0, std::string(), 0,
+    callback.Run(VersionUpdater::FAILED_OFFLINE, 0, false, std::string(), 0,
                  l10n_util::GetStringUTF16(IDS_UPGRADE_OFFLINE));
     return false;
   } else if (status == NETWORK_STATUS_DISALLOWED) {
     base::string16 message = l10n_util::GetStringFUTF16(
         IDS_UPGRADE_DISALLOWED, GetConnectionTypeAsUTF16(network));
-    callback.Run(VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED, 0,
+    callback.Run(VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED, 0, false,
                  std::string(), 0, message);
     return false;
   }
@@ -221,7 +221,7 @@
     // TODO(weidongg/691108): invoke callback to signal about page to show
     // appropriate error message.
     LOG(ERROR) << "Error setting update over cellular one time permission.";
-    callback_.Run(VersionUpdater::FAILED, 0, std::string(), 0,
+    callback_.Run(VersionUpdater::FAILED, 0, false, std::string(), 0,
                   base::string16());
   }
 }
@@ -325,7 +325,8 @@
       break;
   }
 
-  callback_.Run(my_status, progress, version, size, message);
+  callback_.Run(my_status, progress, status.is_rollback, version, size,
+                message);
   last_operation_ = status.status;
 
   if (check_for_update_when_idle_ &&
@@ -339,5 +340,5 @@
   // If version updating is not implemented, this binary is the most up-to-date
   // possible with respect to automatic updating.
   if (result == UpdateEngineClient::UPDATE_RESULT_NOTIMPLEMENTED)
-    callback_.Run(UPDATED, 0, std::string(), 0, base::string16());
+    callback_.Run(UPDATED, 0, false, std::string(), 0, base::string16());
 }
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc b/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc
index 2e47406..587ec32 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc
@@ -33,6 +33,7 @@
 
 void CheckNotification(VersionUpdater::Status /* status */,
                        int /* progress */,
+                       bool /* rollback */,
                        const std::string& /* version */,
                        int64_t /* size */,
                        const base::string16& /* message */) {}
diff --git a/chrome/browser/ui/webui/help/version_updater_mac.mm b/chrome/browser/ui/webui/help/version_updater_mac.mm
index 243d5624..e33976073 100644
--- a/chrome/browser/ui/webui/help/version_updater_mac.mm
+++ b/chrome/browser/ui/webui/help/version_updater_mac.mm
@@ -108,7 +108,8 @@
   } else {
     // There is no glue, or the application is on a read-only filesystem.
     // Updates and promotions are impossible.
-    status_callback_.Run(DISABLED, 0, std::string(), 0, base::string16());
+    status_callback_.Run(DISABLED, 0, false, std::string(), 0,
+                         base::string16());
   }
 }
 
@@ -235,7 +236,7 @@
   }
 
   if (!status_callback_.is_null())
-    status_callback_.Run(status, 0, std::string(), 0, message);
+    status_callback_.Run(status, 0, false, std::string(), 0, message);
 
   PromotionState promotion_state;
   if (!promote_callback_.is_null()) {
diff --git a/chrome/browser/ui/webui/help/version_updater_win.cc b/chrome/browser/ui/webui/help/version_updater_win.cc
index 861526ee..a09e575 100644
--- a/chrome/browser/ui/webui/help/version_updater_win.cc
+++ b/chrome/browser/ui/webui/help/version_updater_win.cc
@@ -29,7 +29,7 @@
   // There is no supported integration with Google Update for Chromium.
   callback_ = callback;
 
-  callback_.Run(CHECKING, 0, std::string(), 0, base::string16());
+  callback_.Run(CHECKING, 0, false, std::string(), 0, base::string16());
   DoBeginUpdateCheck(false /* !install_update_if_possible */);
 }
 
@@ -50,18 +50,18 @@
 
   // Notify the caller that the update is now beginning and initiate it.
   DoBeginUpdateCheck(true /* install_update_if_possible */);
-  callback_.Run(UPDATING, 0, std::string(), 0, base::string16());
+  callback_.Run(UPDATING, 0, false, std::string(), 0, base::string16());
 }
 
 void VersionUpdaterWin::OnUpgradeProgress(int progress,
                                           const base::string16& new_version) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  callback_.Run(UPDATING, progress, std::string(), 0, base::string16());
+  callback_.Run(UPDATING, progress, false, std::string(), 0, base::string16());
 }
 
 void VersionUpdaterWin::OnUpgradeComplete(const base::string16& new_version) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  callback_.Run(NEARLY_UPDATED, 0, std::string(), 0, base::string16());
+  callback_.Run(NEARLY_UPDATED, 0, false, std::string(), 0, base::string16());
 }
 
 void VersionUpdaterWin::OnError(GoogleUpdateErrorCode error_code,
@@ -92,7 +92,7 @@
       }
       break;
   }
-  callback_.Run(status, 0, std::string(), 0, message);
+  callback_.Run(status, 0, false, std::string(), 0, message);
 }
 
 void VersionUpdaterWin::DoBeginUpdateCheck(bool install_update_if_possible) {
@@ -104,7 +104,7 @@
 }
 
 void VersionUpdaterWin::OnPendingRestartCheck(bool is_update_pending_restart) {
-  callback_.Run(is_update_pending_restart ? NEARLY_UPDATED : UPDATED, 0,
+  callback_.Run(is_update_pending_restart ? NEARLY_UPDATED : UPDATED, 0, false,
                 std::string(), 0, base::string16());
 }
 
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index e7219656..6683c9e 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -647,6 +647,7 @@
 
 void AboutHandler::SetUpdateStatus(VersionUpdater::Status status,
                                    int progress,
+                                   bool rollback,
                                    const std::string& version,
                                    int64_t size,
                                    const base::string16& message) {
@@ -657,6 +658,7 @@
   event->SetString("status", UpdateStatusToString(status));
   event->SetString("message", message);
   event->SetInteger("progress", progress);
+  event->SetBoolean("rollback", rollback);
   event->SetString("version", version);
   // DictionaryValue does not support int64_t, so convert to string.
   event->SetString("size", base::Int64ToString(size));
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h
index 4363cda..4c8ae08a 100644
--- a/chrome/browser/ui/webui/settings/about_handler.h
+++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -127,6 +127,7 @@
   // Callback method which forwards status updates to the page.
   void SetUpdateStatus(VersionUpdater::Status status,
                        int progress,
+                       bool rollback,
                        const std::string& version,
                        int64_t size,
                        const base::string16& fail_message);
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 5918900..745ab48 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
@@ -335,6 +335,8 @@
     {"aboutPlatformLabel", IDS_SETTINGS_ABOUT_PAGE_PLATFORM},
     {"aboutRelaunchAndPowerwash",
      IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH},
+    {"aboutRollbackInProgress", IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS},
+    {"aboutRollbackSuccess", IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS},
     {"aboutUpgradeUpdatingChannelSwitch",
      IDS_SETTINGS_UPGRADE_UPDATING_CHANNEL_SWITCH},
     {"aboutUpgradeSuccessChannelSwitch",
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index d33f651..0a792471 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -905,10 +905,9 @@
   base::string16 link_label;
   sync_ui_util::ActionType action_type = sync_ui_util::NO_ACTION;
   bool status_has_error =
-      sync_ui_util::GetStatusLabels(profile_, service, *signin,
-                                    sync_ui_util::PLAIN_TEXT, &status_label,
-                                    &link_label, &action_type) ==
-      sync_ui_util::SYNC_ERROR;
+      sync_ui_util::GetStatusLabels(profile_, service, *signin, &status_label,
+                                    &link_label,
+                                    &action_type) == sync_ui_util::SYNC_ERROR;
   sync_status->SetString("statusText", status_label);
   sync_status->SetBoolean("hasError", status_has_error);
   sync_status->SetString("statusAction", GetSyncErrorAction(action_type));
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
index 96f6635..aa9a85e 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
@@ -119,11 +119,31 @@
                                              << consent_confirmation;
   int consent_confirmation_id = iter->second;
 
-  ConsentAuditorFactory::GetForProfile(profile_)->RecordGaiaConsent(
-      SigninManagerFactory::GetForProfile(profile_)
-          ->GetAuthenticatedAccountId(),
-      consent_feature_, consent_text_ids, consent_confirmation_id,
-      consent_auditor::ConsentStatus::GIVEN);
+  consent_auditor::ConsentAuditor* consent_auditor =
+      ConsentAuditorFactory::GetForProfile(profile_);
+  const std::string& account_id = SigninManagerFactory::GetForProfile(profile_)
+                                      ->GetAuthenticatedAccountId();
+  // TODO(markusheintz): Use a bool unified_consent_enabled instead of a
+  // consent_auditor::Feature type variable.
+  if (consent_feature_ == consent_auditor::Feature::CHROME_UNIFIED_CONSENT) {
+    sync_pb::UserConsentTypes::UnifiedConsent unified_consent;
+    unified_consent.set_confirmation_grd_id(consent_confirmation_id);
+    for (int id : consent_text_ids) {
+      unified_consent.add_description_grd_ids(id);
+    }
+    unified_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                                   UserConsentTypes_ConsentStatus_GIVEN);
+    consent_auditor->RecordUnifiedConsent(account_id, unified_consent);
+  } else {
+    sync_pb::UserConsentTypes::SyncConsent sync_consent;
+    sync_consent.set_confirmation_grd_id(consent_confirmation_id);
+    for (int id : consent_text_ids) {
+      sync_consent.add_description_grd_ids(id);
+    }
+    sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                                UserConsentTypes_ConsentStatus_GIVEN);
+    consent_auditor->RecordSyncConsent(account_id, sync_consent);
+  }
 }
 
 void SyncConfirmationHandler::SetUserImageURL(const std::string& picture_url) {
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
index 0480bf5..0a6df09a 100644
--- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
+++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
@@ -9,6 +9,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "components/spellcheck/browser/pref_names.h"
 
 ChromeUnifiedConsentServiceClient::ChromeUnifiedConsentServiceClient(
     PrefService* pref_service)
@@ -44,3 +45,8 @@
                                 ? chrome_browser_net::NETWORK_PREDICTION_DEFAULT
                                 : chrome_browser_net::NETWORK_PREDICTION_NEVER);
 }
+
+void ChromeUnifiedConsentServiceClient::SetSpellCheckEnabled(bool enabled) {
+  pref_service_->SetBoolean(spellcheck::prefs::kSpellCheckUseSpellingService,
+                            enabled);
+}
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.h b/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
index 58848294..b2a48778 100644
--- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
+++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
@@ -22,6 +22,7 @@
   void SetSafeBrowsingEnabled(bool enabled) override;
   void SetSafeBrowsingExtendedReportingEnabled(bool enabled) override;
   void SetNetworkPredictionEnabled(bool enabled) override;
+  void SetSpellCheckEnabled(bool enabled) override;
 
  private:
   PrefService* pref_service_;
diff --git a/chrome/browser/unified_consent/unified_consent_test_util.cc b/chrome/browser/unified_consent/unified_consent_test_util.cc
index f65a8023..cff4721 100644
--- a/chrome/browser/unified_consent/unified_consent_test_util.cc
+++ b/chrome/browser/unified_consent/unified_consent_test_util.cc
@@ -27,6 +27,7 @@
   void SetSafeBrowsingEnabled(bool enabled) override {}
   void SetSafeBrowsingExtendedReportingEnabled(bool enabled) override {}
   void SetNetworkPredictionEnabled(bool enabled) override {}
+  void SetSpellCheckEnabled(bool enabled) override {}
 };
 
 }  // namespace
diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h
index 140d399..084b3318 100644
--- a/chrome/browser/upgrade_detector.h
+++ b/chrome/browser/upgrade_detector.h
@@ -93,6 +93,10 @@
 
   bool is_factory_reset_required() const { return is_factory_reset_required_; }
 
+#if defined(OS_CHROMEOS)
+  bool is_rollback() const { return is_rollback_; }
+#endif  // defined(OS_CHROMEOS)
+
   // Retrieves the right icon based on the degree of severity (see
   // UpgradeNotificationAnnoyanceLevel, each level has an an accompanying icon
   // to go with it) to display within the app menu.
@@ -202,6 +206,10 @@
     is_factory_reset_required_ = is_factory_reset_required;
   }
 
+#if defined(OS_CHROMEOS)
+  void set_is_rollback(bool is_rollback) { is_rollback_ = is_rollback; }
+#endif  // defined(OS_CHROMEOS)
+
  private:
   FRIEND_TEST_ALL_PREFIXES(AppMenuModelTest, Basics);
   FRIEND_TEST_ALL_PREFIXES(SystemTrayClientTest, UpdateTrayIcon);
@@ -245,6 +253,13 @@
   // Whether a factory reset is needed to complete an update.
   bool is_factory_reset_required_;
 
+#if defined(OS_CHROMEOS)
+  // Whether the update is actually an admin-initiated rollback of the device
+  // to an earlier version of Chrome OS, which results in the device being
+  // wiped when it's rebooted.
+  bool is_rollback_ = false;
+#endif  // defined(OS_CHROMEOS)
+
   // A timer to check to see if we've been idle for long enough to show the
   // critical warning. Should only be set if |upgrade_available_| is
   // UPGRADE_AVAILABLE_CRITICAL.
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7c23829..f7823fb1 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -195,7 +195,7 @@
 
 // Whether the UsageTimeLimit policy should be applied to the user.
 const base::Feature kUsageTimeLimitPolicy{"UsageTimeLimitPolicy",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
+                                          base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
 #if defined(OS_WIN)
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl
index 4598292..836318c 100644
--- a/chrome/common/extensions/api/developer_private.idl
+++ b/chrome/common/extensions/api/developer_private.idl
@@ -375,7 +375,8 @@
     PREFS_CHANGED,
     WARNINGS_CHANGED,
     COMMAND_ADDED,
-    COMMAND_REMOVED
+    COMMAND_REMOVED,
+    PERMISSIONS_CHANGED
   };
 
   dictionary PackDirectoryResponse {
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index e617d5b7..941bf38b 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -1170,6 +1170,9 @@
 
       // The NTP.
       GURL("chrome://newtab"),
+
+      // The Chrome Web Store.
+      ExtensionsClient::Get()->GetWebstoreBaseURL(),
   };
 
   for (const GURL& url : test_urls) {
diff --git a/chrome/common/trace_event_args_whitelist.cc b/chrome/common/trace_event_args_whitelist.cc
index a20e34a..84760f8 100644
--- a/chrome/common/trace_event_args_whitelist.cc
+++ b/chrome/common/trace_event_args_whitelist.cc
@@ -50,6 +50,7 @@
                                     "physical-memory",
                                     "product-version",
                                     "scenario_name",
+                                    "trace-config",
                                     "user-agent"};
 
 }  // namespace
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index a0f20dc..5ae9737 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -112,6 +112,9 @@
     'ChromeDriverTest.testWindowFullScreen',
     # crbug.com/827171
     'ChromeDriverTest.testWindowMinimize',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2515
+    'HeadlessInvalidCertificateTest.testLoadsPage',
+    'HeadlessInvalidCertificateTest.testNavigateNewWindow',
 ]
 
 _DESKTOP_NEGATIVE_FILTER = [
diff --git a/chrome/test/data/notifications/android_test.html b/chrome/test/data/notifications/android_test.html
index 073972d..bede1c2 100644
--- a/chrome/test/data/notifications/android_test.html
+++ b/chrome/test/data/notifications/android_test.html
@@ -9,16 +9,19 @@
          test suite on Android. -->
     <script src="notification_test_utils.js"></script>
     <script>
-      function showNotification(title, options) {
-        GetActivatedServiceWorker('android_test_worker.js', location.pathname)
+      function GetActivatedServiceWorkerForTest() {
+        return GetActivatedServiceWorker(
+            'android_test_worker.js', location.pathname);
+      }
+
+      function SetupReplyForwardingForTests() {
+        GetActivatedServiceWorkerForTest()
             .then(registration => {
-                messagePort.addEventListener('message', function replyListener(event) {
-                  if (event.data.startsWith('reply: ')) {
-                    messagePort.removeEventListener('message', replyListener);
-                    sendToTest(event.data);
-                  }
-                });
-                return registration.showNotification(title, options);
+              messagePort.addEventListener('message', function replyListener(event) {
+                if (event.data.startsWith('reply: ')) {
+                  messagePort.removeEventListener('message', replyListener);
+                  sendToTest(event.data);
+                }});
             })
             .catch(sendToTest);
       }
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index ad07bf9..0383715 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3792,7 +3792,10 @@
   },
 
   "UsageTimeLimit": {
-    "note": "TODO(hgrandinetti): Re-enable the test once the feature is no longer behind an experiment flag (crbug.com/849738)"
+    "os": ["chromeos"],
+    "test_policy": { "UsageTimeLimit": { "time_window_limit": { "entries": [{ "effective_day": "WEDNESDAY", "starts_at": { "hour": 21, "minute": 0 }, "ends_at": { "hour": 7, "minute": 30 }, "last_updated_millis": "1000000" }, { "effective_day": "SATURDAY", "starts_at": { "hour": 14, "minute": 0 }, "ends_at": { "hour": 16, "minute": 15 }, "last_updated_millis": "1400000" }]}, "time_usage_limit": { "monday": { "usage_quota_mins": 120, "last_updated_millis": "1200000" }, "thursday": { "usage_quota_mins": 15, "last_updated_millis": "1600000" }, "reset_at": { "hour": 6, "minute": 0 }}, "overrides": [{ "action": "UNLOCK", "created_at_millis": "1250000", "action_specific_data": { "duration_mins": 30 }}]}},
+    "can_be_recommended": false,
+    "pref_mappings": [{ "pref": "screen_time.limit" }]
   },
 
   "EnableSyncConsent": {
diff --git a/chrome/test/data/previews/resource_loading_hints.html b/chrome/test/data/previews/resource_loading_hints.html
index e7dc052..ad2f1df 100644
--- a/chrome/test/data/previews/resource_loading_hints.html
+++ b/chrome/test/data/previews/resource_loading_hints.html
@@ -1,14 +1,19 @@
 <html>
   <head>
-    <meta name="viewport" content="width=device-width" />
-    <noscript>
-      <title>Page with Script Disabled</title>
-      <link rel="stylesheet" href="noscript_test.css">
-    </noscript>
-    <script>document.title='Page with Script Enabled and Executed';</script>
   </head>
   <body>
-    <p>Test page for NoScript Previews.</p>
-    <script src="noscript_test.js"></script>
-  </body>
+    <p>Test page for Resource Loading Hints.</p>
+   <iframe src="non_existent_file.js"></iframe>
+   <script>
+    window.addEventListener("load", function () {
+      var xhr_foo = new XMLHttpRequest();
+      xhr_foo.open('GET', 'foo.jpg', true /* async */);
+      xhr_foo.send();
+
+      var xhr_bar = new XMLHttpRequest();
+      xhr_bar.open('GET', 'bar.jpg', true /* async */);
+      xhr_bar.send();
+    });
+    </script>
+   </body>
 </html>
diff --git a/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html b/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html
index e7dc052..ad2f1df 100644
--- a/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html
+++ b/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html
@@ -1,14 +1,19 @@
 <html>
   <head>
-    <meta name="viewport" content="width=device-width" />
-    <noscript>
-      <title>Page with Script Disabled</title>
-      <link rel="stylesheet" href="noscript_test.css">
-    </noscript>
-    <script>document.title='Page with Script Enabled and Executed';</script>
   </head>
   <body>
-    <p>Test page for NoScript Previews.</p>
-    <script src="noscript_test.js"></script>
-  </body>
+    <p>Test page for Resource Loading Hints.</p>
+   <iframe src="non_existent_file.js"></iframe>
+   <script>
+    window.addEventListener("load", function () {
+      var xhr_foo = new XMLHttpRequest();
+      xhr_foo.open('GET', 'foo.jpg', true /* async */);
+      xhr_foo.send();
+
+      var xhr_bar = new XMLHttpRequest();
+      xhr_bar.open('GET', 'bar.jpg', true /* async */);
+      xhr_bar.send();
+    });
+    </script>
+   </body>
 </html>
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index c6a1365fb..f31a91a 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -32,7 +32,6 @@
     "//components/search_engines",
     "//components/services/heap_profiling",
     "//components/services/heap_profiling/public/cpp",
-    "//components/services/patch:lib",
     "//components/services/unzip:lib",
     "//components/strings",
     "//components/url_formatter",
@@ -92,6 +91,7 @@
       "//chrome/common:mojo_bindings",
       "//chrome/common/importer:interfaces",
       "//components/autofill/core/common",
+      "//components/services/patch:lib",
       "//services/data_decoder:lib",
       "//services/proxy_resolver:lib",
     ]
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index c685a37..b97904e3 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -16,8 +16,6 @@
 #include "chrome/common/buildflags.h"
 #include "components/services/heap_profiling/heap_profiling_service.h"
 #include "components/services/heap_profiling/public/mojom/constants.mojom.h"
-#include "components/services/patch/patch_service.h"
-#include "components/services/patch/public/interfaces/constants.mojom.h"
 #include "components/services/unzip/public/interfaces/constants.mojom.h"
 #include "components/services/unzip/unzip_service.h"
 #include "content/public/common/content_switches.h"
@@ -33,6 +31,8 @@
 #if !defined(OS_ANDROID)
 #include "chrome/utility/importer/profile_import_impl.h"
 #include "chrome/utility/importer/profile_import_service.h"
+#include "components/services/patch/patch_service.h"  // nogncheck
+#include "components/services/patch/public/interfaces/constants.mojom.h"  // nogncheck
 #include "services/network/url_request_context_builder_mojo.h"
 #include "services/proxy_resolver/proxy_resolver_service.h"  // nogncheck
 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"  // nogncheck
@@ -248,12 +248,14 @@
   }
 #endif
 
+#if !defined(OS_ANDROID)
   {
     service_manager::EmbeddedServiceInfo service_info;
     service_info.factory =
         base::BindRepeating(&patch::PatchService::CreateService);
     services->emplace(patch::mojom::kServiceName, service_info);
   }
+#endif
 
   {
     service_manager::EmbeddedServiceInfo service_info;
diff --git a/chrome/utility/mash_service_factory.cc b/chrome/utility/mash_service_factory.cc
index 5f572dc..fc8e728 100644
--- a/chrome/utility/mash_service_factory.cc
+++ b/chrome/utility/mash_service_factory.cc
@@ -15,13 +15,9 @@
 #include "ash/components/tap_visualizer/public/mojom/constants.mojom.h"
 #include "ash/components/tap_visualizer/tap_visualizer_app.h"
 #include "ash/public/interfaces/constants.mojom.h"
-#include "ash/window_manager_service.h"
 #include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
-#include "ui/base/ui_base_features.h"
 
 namespace {
 
@@ -57,11 +53,6 @@
 
 std::unique_ptr<service_manager::Service> CreateAshService() {
   RecordMashServiceLaunch(MashService::kAsh);
-  if (base::FeatureList::IsEnabled(features::kMashDeprecated)) {
-    const bool show_primary_host_on_connect = true;
-    return std::make_unique<ash::WindowManagerService>(
-        show_primary_host_on_connect);
-  }
   return std::make_unique<ash::AshService>();
 }
 
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastAudioManager.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastAudioManager.java
index 90445cd..cff55ac0 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastAudioManager.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastAudioManager.java
@@ -4,7 +4,9 @@
 
 package org.chromium.chromecast.shell;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
+import android.media.AudioFocusRequest;
 import android.media.AudioManager;
 import android.os.Build;
 
@@ -105,14 +107,22 @@
         }
     }
 
-    // TODO(sanfin): Use the AudioFocusRequest version on O and above.
+    @SuppressLint("NewApi")
+    public int requestAudioFocus(AudioFocusRequest focusRequest) {
+        return mAudioManager.requestAudioFocus(focusRequest);
+    }
+
     @SuppressWarnings("deprecation")
     public int requestAudioFocus(
             AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint) {
         return mAudioManager.requestAudioFocus(l, streamType, durationHint);
     }
 
-    // TODO(sanfin): Use the AudioFocusRequest version on O and above.
+    @SuppressLint("NewApi")
+    public int abandonAudioFocusRequest(AudioFocusRequest focusRequest) {
+        return mAudioManager.abandonAudioFocusRequest(focusRequest);
+    }
+
     @SuppressWarnings("deprecation")
     public int abandonAudioFocus(AudioManager.OnAudioFocusChangeListener l) {
         return mAudioManager.abandonAudioFocus(l);
diff --git a/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc b/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc
index 34df2452..542f926 100644
--- a/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc
+++ b/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/test/test_message_loop.h"
 #include "chromecast/media/cma/test/mock_cma_backend_factory.h"
 #include "media/audio/fake_audio_log_factory.h"
@@ -33,16 +34,20 @@
   CastAudioManagerAlsaTest() : media_thread_("CastMediaThread") {
     CHECK(media_thread_.Start());
 
+    backend_factory_ = std::make_unique<MockCmaBackendFactory>();
     audio_manager_ = std::make_unique<CastAudioManagerAlsa>(
         std::make_unique<::media::TestAudioThread>(), &audio_log_factory_,
-        std::make_unique<MockCmaBackendFactory>(), media_thread_.task_runner(),
-        false);
+        base::BindRepeating(&CastAudioManagerAlsaTest::GetCmaBackendFactory,
+                            base::Unretained(this)),
+        media_thread_.task_runner(), false);
   }
 
   ~CastAudioManagerAlsaTest() override { audio_manager_->Shutdown(); }
+  CmaBackendFactory* GetCmaBackendFactory() { return backend_factory_.get(); }
 
  protected:
   base::TestMessageLoop message_loop_;
+  std::unique_ptr<MockCmaBackendFactory> backend_factory_;
   base::Thread media_thread_;
   ::media::FakeAudioLogFactory audio_log_factory_;
   std::unique_ptr<CastAudioManagerAlsa> audio_manager_;
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc
index 0040b574..eb0372e 100644
--- a/components/autofill/core/browser/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -21,6 +21,11 @@
 
 namespace autofill {
 
+MigratableCreditCard::MigratableCreditCard(const CreditCard& credit_card)
+    : credit_card_(credit_card) {}
+
+MigratableCreditCard::~MigratableCreditCard() {}
+
 LocalCardMigrationManager::LocalCardMigrationManager(
     AutofillClient* client,
     payments::PaymentsClient* payments_client,
@@ -29,7 +34,8 @@
     : client_(client),
       payments_client_(payments_client),
       app_locale_(app_locale),
-      personal_data_manager_(personal_data_manager) {
+      personal_data_manager_(personal_data_manager),
+      weak_ptr_factory_(this) {
   if (payments_client_)
     payments_client_->SetSaveDelegate(this);
 }
@@ -56,12 +62,12 @@
   migratable_credit_cards_.clear();
 
   // Initialize the local credit card list and queue for showing and uploading.
-  for (CreditCard* card : local_credit_cards) {
+  for (CreditCard* credit_card : local_credit_cards) {
     // If the card is valid (has a valid card number, expiration date, and is
     // not expired) and is not a server card, add it to the list of migratable
     // cards.
-    if (card->IsValid() && !IsServerCard(card))
-      migratable_credit_cards_.push_back(*card);
+    if (credit_card->IsValid() && !IsServerCard(credit_card))
+      migratable_credit_cards_.push_back(MigratableCreditCard(*credit_card));
   }
 
   // If the form was submitted with a local card, only offer migration instead
@@ -98,6 +104,14 @@
       app_locale_);
 }
 
+// TODO(crbug.com/852904): Pops up a larger, modal dialog showing the local
+// cards to be uploaded. Pass the reference of vector<MigratableCreditCard> and
+// the callback function is OnConfirmLocalCardsMigration().
+void LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog() {
+  user_accepted_main_migration_dialog_ = false;
+  // Pops up a larger, modal dialog showing the local cards to be uploaded.
+}
+
 bool LocalCardMigrationManager::IsCreditCardMigrationEnabled() {
   // Confirm that the user is signed in, syncing, and the proper experiment
   // flags are enabled.
@@ -122,13 +136,18 @@
     legal_message_ = std::move(legal_message);
     // If we successfully received the legal docs, trigger the offer-to-migrate
     // dialog.
-    // TODO(crbug.com/852904): Show intermediate migration prompt here! Relies
-    // on CL/1117929 first.
+    client_->ShowLocalCardMigrationPrompt(base::BindOnce(
+        &LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog,
+        weak_ptr_factory_.GetWeakPtr()));
+    // TODO(crbug.com/852904): Call the client LoadRiskData()
   }
 }
 
-// TODO(crbug.com/852904): Starts the upload of the next local card if one
-// exists.
+// TODO(crbug.com/852904): Send the upload request once risk data is available.
+void LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog() {
+  user_accepted_main_migration_dialog_ = true;
+}
+
 void LocalCardMigrationManager::OnDidUploadCard(
     AutofillClient::PaymentsRpcResult result,
     const std::string& server_id) {}
@@ -139,9 +158,11 @@
   // If all cards to be migrated have a cardholder name, include it in the
   // detected values.
   bool all_cards_have_cardholder_name = true;
-  for (CreditCard card : migratable_credit_cards_) {
+  for (MigratableCreditCard migratable_credit_card : migratable_credit_cards_) {
     all_cards_have_cardholder_name &=
-        !card.GetInfo(AutofillType(CREDIT_CARD_NAME_FULL), app_locale_).empty();
+        !migratable_credit_card.credit_card()
+             .GetInfo(AutofillType(CREDIT_CARD_NAME_FULL), app_locale_)
+             .empty();
   }
   if (all_cards_have_cardholder_name)
     detected_values |= CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME;
diff --git a/components/autofill/core/browser/local_card_migration_manager.h b/components/autofill/core/browser/local_card_migration_manager.h
index 62802c8..12c3a210 100644
--- a/components/autofill/core/browser/local_card_migration_manager.h
+++ b/components/autofill/core/browser/local_card_migration_manager.h
@@ -18,6 +18,31 @@
 class CreditCard;
 class PersonalDataManager;
 
+// MigratableCreditCard class is used as a DataStructure to work as an
+// intermediary between the UI side and the migration manager. Besides the basic
+// credit card information, it also includes a boolean that represents whether
+// the card was chosen for upload.
+// TODO(crbug.com/852904): Create one Enum to represent migration status such as
+// whether the card is successfully uploaded or failure on uploading.
+class MigratableCreditCard {
+ public:
+  MigratableCreditCard(const CreditCard& credit_card);
+  ~MigratableCreditCard();
+
+  CreditCard credit_card() const { return credit_card_; }
+
+  bool is_chosen() const { return is_chosen_; }
+  void set_is_chosen(bool is_chosen) { is_chosen_ = is_chosen; }
+
+ private:
+  // The main card information of the current migratable card.
+  CreditCard credit_card_;
+
+  // Whether the user has decided to migrate the this card; shown as a checkbox
+  // in the UI.
+  bool is_chosen_ = true;
+};
+
 // Manages logic for determining whether migration of locally saved credit cards
 // to Google Payments is available as well as multiple local card uploading.
 // Owned by FormDataImporter.
@@ -38,6 +63,10 @@
   // Fetches legal documents and triggers the OnDidGetUploadDetails callback.
   void AttemptToOfferLocalCardMigration();
 
+  // Callback function when user agrees to migration on the intermediate dialog.
+  // Pops up a larger, modal dialog showing the local cards to be uploaded.
+  void OnUserAcceptedIntermediateMigrationDialog();
+
   // Check that the user is signed in, syncing, and the proper experiment
   // flags are enabled. Override in the test class.
   virtual bool IsCreditCardMigrationEnabled();
@@ -72,6 +101,11 @@
   payments::PaymentsClient* payments_client_;
 
  private:
+  // Callback function when user confirms migration on the main migration
+  // dialog. Sets |user_accepted_main_migration_dialog_| and sends the upload
+  // request.
+  void OnUserAcceptedMainMigrationDialog();
+
   std::unique_ptr<base::DictionaryValue> legal_message_;
 
   std::string app_locale_;
@@ -86,7 +120,13 @@
   payments::PaymentsClient::UploadRequestDetails upload_request_;
 
   // The local credit cards to be uploaded.
-  std::vector<CreditCard> migratable_credit_cards_;
+  std::vector<MigratableCreditCard> migratable_credit_cards_;
+
+  // |true| if the user has accepted migrating their local cards to Google Pay
+  // on the main dialog.
+  bool user_accepted_main_migration_dialog_ = false;
+
+  base::WeakPtrFactory<LocalCardMigrationManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationManager);
 };
diff --git a/components/autofill/ios/form_util/BUILD.gn b/components/autofill/ios/form_util/BUILD.gn
index 3b0c7ee8..30daeef2 100644
--- a/components/autofill/ios/form_util/BUILD.gn
+++ b/components/autofill/ios/form_util/BUILD.gn
@@ -56,7 +56,6 @@
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/tabs:tabs_internal",
     "//ios/chrome/browser/web:test_support",
-    "//ios/testing:ios_test_support",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
     "//ios/web/web_state/js",
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index de446289..54c4bfa 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -36,6 +36,7 @@
 #include "components/sync/device_info/device_info_sync_bridge.h"
 #include "components/sync/device_info/device_info_tracker.h"
 #include "components/sync/driver/backend_migrator.h"
+#include "components/sync/driver/clear_server_data_events.h"
 #include "components/sync/driver/directory_data_type_controller.h"
 #include "components/sync/driver/signin_manager_wrapper.h"
 #include "components/sync/driver/sync_api_component_factory.h"
@@ -832,7 +833,7 @@
 
 bool ProfileSyncService::IsSyncConfirmationNeeded() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return (!IsLocalSyncEnabled() && IsSignedIn()) && !IsFirstSetupInProgress() &&
+  return (!IsLocalSyncEnabled() && IsSignedIn()) && !IsSetupInProgress() &&
          !IsFirstSetupComplete() &&
          !HasDisableReason(DISABLE_REASON_USER_CHOICE);
 }
@@ -1266,7 +1267,7 @@
 }
 
 bool ProfileSyncService::QueryDetailedSyncStatus(
-    syncer::SyncEngine::Status* result) {
+    syncer::SyncEngine::Status* result) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (engine_ && engine_initialized_) {
     *result = engine_->GetDetailedStatus();
@@ -1287,11 +1288,6 @@
   return IsFirstSetupComplete() && !IsSetupInProgress();
 }
 
-bool ProfileSyncService::IsFirstSetupInProgress() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return !IsFirstSetupComplete() && IsSetupInProgress();
-}
-
 std::unique_ptr<syncer::SyncSetupInProgressHandle>
 ProfileSyncService::GetSetupInProgressHandle() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index d972597..3049c15 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -248,7 +248,6 @@
   void OnUserChoseDatatypes(bool sync_everything,
                             syncer::ModelTypeSet chosen_types) override;
   void SetFirstSetupComplete() override;
-  bool IsFirstSetupInProgress() const override;
   std::unique_ptr<syncer::SyncSetupInProgressHandle> GetSetupInProgressHandle()
       override;
   bool IsSetupInProgress() const override;
@@ -271,7 +270,7 @@
       const override;
   void ReenableDatatype(syncer::ModelType type) override;
   syncer::SyncTokenStatus GetSyncTokenStatus() const override;
-  bool QueryDetailedSyncStatus(syncer::SyncStatus* result) override;
+  bool QueryDetailedSyncStatus(syncer::SyncStatus* result) const override;
   base::Time GetLastSyncedTime() const override;
   syncer::SyncCycleSnapshot GetLastCycleSnapshot() const override;
   std::unique_ptr<base::Value> GetTypeStatusMap() override;
@@ -432,6 +431,9 @@
   syncer::SyncErrorController* sync_error_controller() {
     return sync_error_controller_.get();
   }
+  const syncer::SyncErrorController* sync_error_controller() const {
+    return sync_error_controller_.get();
+  }
 
   // KeyedService implementation.  This must be called exactly
   // once (before this object is destroyed).
diff --git a/components/browser_sync/profile_sync_service_mock.h b/components/browser_sync/profile_sync_service_mock.h
index d709fda..11b42e1 100644
--- a/components/browser_sync/profile_sync_service_mock.h
+++ b/components/browser_sync/profile_sync_service_mock.h
@@ -71,10 +71,10 @@
 
   MOCK_CONST_METHOD0(GetDisableReasons, int());
   MOCK_CONST_METHOD0(GetState, State());
-  MOCK_METHOD1(QueryDetailedSyncStatus,
-               bool(syncer::SyncEngine::Status* result));
+  MOCK_CONST_METHOD1(QueryDetailedSyncStatus,
+                     bool(syncer::SyncEngine::Status* result));
   MOCK_CONST_METHOD0(GetAuthError, const GoogleServiceAuthError&());
-  MOCK_CONST_METHOD0(IsFirstSetupInProgress, bool());
+  MOCK_CONST_METHOD0(IsSetupInProgress, bool());
   MOCK_CONST_METHOD0(GetLastSyncedTime, base::Time());
   MOCK_CONST_METHOD0(IsEngineInitialized, bool());
   MOCK_CONST_METHOD0(IsSyncConfirmationNeeded, bool());
diff --git a/components/consent_auditor/consent_auditor.h b/components/consent_auditor/consent_auditor.h
index ff90f01..30e61ac 100644
--- a/components/consent_auditor/consent_auditor.h
+++ b/components/consent_auditor/consent_auditor.h
@@ -12,10 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
-
-namespace syncer {
-class ModelTypeControllerDelegate;
-}
+#include "components/sync/model/model_type_sync_bridge.h"
 
 namespace consent_auditor {
 
@@ -55,12 +52,48 @@
   // Consent text consisted of strings with |consent_grd_ids|, and the UI
   // element the user clicked had the ID |confirmation_grd_id|.
   // Whether the consent was GIVEN or NOT_GIVEN is passed as |status|.
+  //
+  // DEPRECATED
+  // TODO(markusheintz): Make this method private once all clients have been
+  // migrated to the new API.
   virtual void RecordGaiaConsent(const std::string& account_id,
                                  Feature feature,
                                  const std::vector<int>& description_grd_ids,
                                  int confirmation_grd_id,
                                  ConsentStatus status) = 0;
 
+  // Records the ARC Play |consent| for the signed-in GAIA account with the ID
+  // |account_id| (as defined in AccountInfo).
+  virtual void RecordArcPlayConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent&
+          consent) = 0;
+
+  // Records the ARC Google Location Service |consent| for the signed-in GAIA
+  // account with the ID |account_id| (as defined in AccountInfo).
+  virtual void RecordArcGoogleLocationServiceConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent&
+          consent) = 0;
+
+  // Records the ARC Backup and Restore |consent| for the signed-in GAIA
+  // account with the ID |account_id| (as defined in AccountInfo).
+  virtual void RecordArcBackupAndRestoreConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent& consent) = 0;
+
+  // Records the Sync |consent| for the signed-in GAIA account with the ID
+  // |account_id| (as defined in AccountInfo).
+  virtual void RecordSyncConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::SyncConsent& consent) = 0;
+
+  // Records the Chrome Unified |consent| for the signed-in GAIA account with
+  // the ID |accounts_id| (as defined in Account Info).
+  virtual void RecordUnifiedConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::UnifiedConsent& consent) = 0;
+
   // Records that the user consented to a |feature|. The user was presented with
   // |description_text| and accepted it by interacting |confirmation_text|
   // (e.g. clicking on a button; empty if not applicable).
diff --git a/components/consent_auditor/consent_auditor_impl.cc b/components/consent_auditor/consent_auditor_impl.cc
index 913319d..63beb96d 100644
--- a/components/consent_auditor/consent_auditor_impl.cc
+++ b/components/consent_auditor/consent_auditor_impl.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/metrics/histogram_macros.h"
+#include "base/sha1.h"
 #include "base/values.h"
 #include "components/consent_auditor/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -81,6 +82,19 @@
   return UserConsentSpecifics::FEATURE_UNSPECIFIED;
 }
 
+ConsentStatus ConvertConsentStatus(
+    UserConsentTypes::ConsentStatus consent_status) {
+  DCHECK_NE(consent_status,
+            UserConsentTypes::ConsentStatus::
+                UserConsentTypes_ConsentStatus_CONSENT_STATUS_UNSPECIFIED);
+
+  if (consent_status ==
+      UserConsentTypes::ConsentStatus::UserConsentTypes_ConsentStatus_GIVEN) {
+    return ConsentStatus::GIVEN;
+  }
+  return ConsentStatus::NOT_GIVEN;
+}
+
 }  // namespace
 
 ConsentAuditorImpl::ConsentAuditorImpl(
@@ -201,6 +215,73 @@
   return specifics;
 }
 
+void ConsentAuditorImpl::RecordArcPlayConsent(
+    const std::string& account_id,
+    const UserConsentTypes::ArcPlayTermsOfServiceConsent& consent) {
+  std::vector<int> description_grd_ids;
+  description_grd_ids.push_back(consent.play_terms_of_service_text_length());
+
+  // TODO(markusheintz): The code below is a copy from the ARC code base. This
+  // will go away when the consent proto is set on the user consent specifics
+  // proto.
+  const std::string& hash_str = consent.play_terms_of_service_hash();
+  DCHECK_EQ(base::kSHA1Length, hash_str.size());
+  const uint8_t* hash = reinterpret_cast<const uint8_t*>(hash_str.data());
+  for (size_t i = 0; i < base::kSHA1Length; i += 4) {
+    uint32_t acc =
+        hash[i] << 24 | hash[i + 1] << 16 | hash[i + 2] << 8 | hash[i + 3];
+    description_grd_ids.push_back(static_cast<int>(acc));
+  }
+
+  RecordGaiaConsent(account_id, Feature::PLAY_STORE, description_grd_ids,
+                    consent.confirmation_grd_id(),
+                    ConvertConsentStatus(consent.status()));
+}
+
+void ConsentAuditorImpl::RecordArcGoogleLocationServiceConsent(
+    const std::string& account_id,
+    const UserConsentTypes::ArcGoogleLocationServiceConsent& consent) {
+  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                       consent.description_grd_ids().end());
+
+  RecordGaiaConsent(account_id, Feature::GOOGLE_LOCATION_SERVICE,
+                    description_grd_ids, consent.confirmation_grd_id(),
+                    ConvertConsentStatus(consent.status()));
+}
+
+void ConsentAuditorImpl::RecordArcBackupAndRestoreConsent(
+    const std::string& account_id,
+    const UserConsentTypes::ArcBackupAndRestoreConsent& consent) {
+  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                       consent.description_grd_ids().end());
+
+  RecordGaiaConsent(account_id, Feature::BACKUP_AND_RESTORE,
+                    description_grd_ids, consent.confirmation_grd_id(),
+                    ConvertConsentStatus(consent.status()));
+}
+
+void ConsentAuditorImpl::RecordSyncConsent(
+    const std::string& account_id,
+    const UserConsentTypes::SyncConsent& consent) {
+  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                       consent.description_grd_ids().end());
+
+  RecordGaiaConsent(account_id, Feature::CHROME_SYNC, description_grd_ids,
+                    consent.confirmation_grd_id(),
+                    ConvertConsentStatus(consent.status()));
+}
+
+void ConsentAuditorImpl::RecordUnifiedConsent(
+    const std::string& account_id,
+    const sync_pb::UserConsentTypes::UnifiedConsent& consent) {
+  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                       consent.description_grd_ids().end());
+
+  RecordGaiaConsent(account_id, Feature::CHROME_UNIFIED_CONSENT,
+                    description_grd_ids, consent.confirmation_grd_id(),
+                    ConvertConsentStatus(consent.status()));
+}
+
 void ConsentAuditorImpl::RecordLocalConsent(
     const std::string& feature,
     const std::string& description_text,
diff --git a/components/consent_auditor/consent_auditor_impl.h b/components/consent_auditor/consent_auditor_impl.h
index acad016..db789000 100644
--- a/components/consent_auditor/consent_auditor_impl.h
+++ b/components/consent_auditor/consent_auditor_impl.h
@@ -14,9 +14,9 @@
 #include "components/consent_auditor/consent_auditor.h"
 #include "components/consent_auditor/consent_sync_bridge.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/model/model_type_sync_bridge.h"
 
 namespace syncer {
-class ModelTypeControllerDelegate;
 class UserEventService;
 }  // namespace syncer
 
@@ -49,27 +49,32 @@
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
   // Consent auditor implementation.
-
-  // Records a consent for |feature| for the signed-in GAIA account with
-  // the ID |account_id| (as defined in AccountInfo).
-  // Consent text consisted of strings with |consent_grd_ids|, and the UI
-  // element the user clicked had the ID |confirmation_grd_id|.
-  // Whether the consent was GIVEN or NOT_GIVEN is passed as |status|.
   void RecordGaiaConsent(const std::string& account_id,
                          Feature feature,
                          const std::vector<int>& description_grd_ids,
                          int confirmation_grd_id,
                          ConsentStatus status) override;
-
-  // Records that the user consented to a |feature|. The user was presented with
-  // |description_text| and accepted it by interacting |confirmation_text|
-  // (e.g. clicking on a button; empty if not applicable).
-  // Returns true if successful.
+  void RecordArcPlayConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent& consent)
+      override;
+  void RecordArcGoogleLocationServiceConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent& consent)
+      override;
+  void RecordArcBackupAndRestoreConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent& consent)
+      override;
+  void RecordSyncConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::SyncConsent& consent) override;
+  void RecordUnifiedConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::UnifiedConsent& consent) override;
   void RecordLocalConsent(const std::string& feature,
                           const std::string& description_text,
                           const std::string& confirmation_text) override;
-
-  // Returns the underlying Sync integration point.
   base::WeakPtr<syncer::ModelTypeControllerDelegate>
   GetControllerDelegateOnUIThread() override;
 
diff --git a/components/consent_auditor/consent_auditor_impl_unittest.cc b/components/consent_auditor/consent_auditor_impl_unittest.cc
index b0d9ec655..2868b7ed 100644
--- a/components/consent_auditor/consent_auditor_impl_unittest.cc
+++ b/components/consent_auditor/consent_auditor_impl_unittest.cc
@@ -244,8 +244,11 @@
   SetUserEventService(std::make_unique<syncer::FakeUserEventService>());
   BuildConsentAuditorImpl();
 
-  consent_auditor()->RecordGaiaConsent(kAccountId, Feature::CHROME_SYNC, {}, 0,
-                                       ConsentStatus::GIVEN);
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+
+  consent_auditor()->RecordSyncConsent(kAccountId, sync_consent);
   auto& events = user_event_service()->GetRecordedUserEvents();
   EXPECT_EQ(1U, events.size());
 }
@@ -258,8 +261,10 @@
 
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(switches::kSyncUserConsentEvents);
-  consent_auditor()->RecordGaiaConsent(kAccountId, Feature::CHROME_SYNC, {}, 0,
-                                       ConsentStatus::GIVEN);
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  consent_auditor()->RecordSyncConsent(kAccountId, sync_consent);
   auto& events = user_event_service()->GetRecordedUserEvents();
   EXPECT_EQ(0U, events.size());
 }
@@ -275,9 +280,14 @@
   std::vector<int> kDescriptionMessageIds = {12, 37, 42};
   int kConfirmationMessageId = 47;
   base::Time t1 = base::Time::Now();
-  consent_auditor()->RecordGaiaConsent(
-      kAccountId, Feature::CHROME_SYNC, kDescriptionMessageIds,
-      kConfirmationMessageId, ConsentStatus::GIVEN);
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  sync_consent.set_confirmation_grd_id(kConfirmationMessageId);
+  for (int id : kDescriptionMessageIds) {
+    sync_consent.add_description_grd_ids(id);
+  }
+  consent_auditor()->RecordSyncConsent(kAccountId, sync_consent);
   base::Time t2 = base::Time::Now();
   auto& events = user_event_service()->GetRecordedUserEvents();
   EXPECT_EQ(1U, events.size());
@@ -312,9 +322,14 @@
   int kConfirmationMessageId = 47;
   // TODO(vitaliii): Inject a fake clock instead.
   base::Time time_before = base::Time::Now();
-  consent_auditor()->RecordGaiaConsent(
-      kAccountId, Feature::CHROME_SYNC, kDescriptionMessageIds,
-      kConfirmationMessageId, ConsentStatus::GIVEN);
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  sync_consent.set_confirmation_grd_id(kConfirmationMessageId);
+  for (int id : kDescriptionMessageIds) {
+    sync_consent.add_description_grd_ids(id);
+  }
+  consent_auditor()->RecordSyncConsent(kAccountId, sync_consent);
   base::Time time_after = base::Time::Now();
 
   std::vector<UserConsentSpecifics> consents =
@@ -367,4 +382,33 @@
             consent_auditor()->GetControllerDelegateOnUIThread().get());
 }
 
+// Test that RecordSyncConsent and RecordGaiaConsent record an identical user
+// consent proto with the user event service. This test ensures that the two
+// methods don't diverge during the migration to the new dedicated protos for
+// user events.
+TEST_F(ConsentAuditorImplTest, RecordGaiaUserRecordSyncConsentEquivalence) {
+  SetIsSeparateConsentTypeEnabledFeature(false);
+  SetConsentSyncBridge(nullptr);
+  SetUserEventService(std::make_unique<syncer::FakeUserEventService>());
+  BuildConsentAuditorImpl();
+
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  sync_consent.set_confirmation_grd_id(21);
+  sync_consent.add_description_grd_ids(1);
+  sync_consent.add_description_grd_ids(2);
+  sync_consent.add_description_grd_ids(3);
+
+  consent_auditor()->RecordSyncConsent(kAccountId, sync_consent);
+  consent_auditor()->RecordGaiaConsent(
+      kAccountId, consent_auditor::Feature::CHROME_SYNC, {1, 2, 3}, 21,
+      consent_auditor::ConsentStatus::GIVEN);
+
+  auto& events = user_event_service()->GetRecordedUserEvents();
+  EXPECT_EQ(2U, events.size());
+  EXPECT_EQ(events.at(0).user_consent().SerializeAsString(),
+            events.at(1).user_consent().SerializeAsString());
+}
+
 }  // namespace consent_auditor
diff --git a/components/consent_auditor/fake_consent_auditor.cc b/components/consent_auditor/fake_consent_auditor.cc
index fd99e13..64b24eb 100644
--- a/components/consent_auditor/fake_consent_auditor.cc
+++ b/components/consent_auditor/fake_consent_auditor.cc
@@ -4,14 +4,68 @@
 
 #include <utility>
 
+#include "components/consent_auditor/consent_auditor.h"
 #include "components/consent_auditor/fake_consent_auditor.h"
 
+namespace {
+
+consent_auditor::ConsentStatus ConvertConsentStatus(
+    sync_pb::UserConsentTypes::ConsentStatus consent_status) {
+  DCHECK_NE(consent_status,
+            sync_pb::UserConsentTypes::ConsentStatus::
+                UserConsentTypes_ConsentStatus_CONSENT_STATUS_UNSPECIFIED);
+
+  if (consent_status == sync_pb::UserConsentTypes::ConsentStatus::
+                            UserConsentTypes_ConsentStatus_GIVEN) {
+    return consent_auditor::ConsentStatus::GIVEN;
+  }
+  return consent_auditor::ConsentStatus::NOT_GIVEN;
+}
+
+}  // namespace
+
 namespace consent_auditor {
 
 FakeConsentAuditor::FakeConsentAuditor() {}
 
 FakeConsentAuditor::~FakeConsentAuditor() {}
 
+void FakeConsentAuditor::RecordSyncConsent(
+    const std::string& account_id,
+    const sync_pb::UserConsentTypes::SyncConsent& consent) {
+  // TODO(markusheintz): Change the Fake to store the proto instead of calling
+  // RecordGaiaConsent.
+  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                       consent.description_grd_ids().end());
+  RecordGaiaConsent(account_id, Feature::CHROME_SYNC, description_grd_ids,
+                    consent.confirmation_grd_id(),
+                    ConvertConsentStatus(consent.status()));
+}
+
+void FakeConsentAuditor::RecordArcPlayConsent(
+    const std::string& account_id,
+    const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent& consent) {
+  NOTIMPLEMENTED();
+}
+
+void FakeConsentAuditor::RecordArcGoogleLocationServiceConsent(
+    const std::string& account_id,
+    const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent& consent) {
+  NOTIMPLEMENTED();
+}
+
+void FakeConsentAuditor::RecordArcBackupAndRestoreConsent(
+    const std::string& account_id,
+    const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent& consent) {
+  NOTIMPLEMENTED();
+}
+
+void FakeConsentAuditor::RecordUnifiedConsent(
+    const std::string& account_id,
+    const sync_pb::UserConsentTypes::UnifiedConsent& consent) {
+  NOTIMPLEMENTED();
+}
+
 void FakeConsentAuditor::RecordGaiaConsent(
     const std::string& account_id,
     consent_auditor::Feature feature,
diff --git a/components/consent_auditor/fake_consent_auditor.h b/components/consent_auditor/fake_consent_auditor.h
index 82310e8..c964cbc 100644
--- a/components/consent_auditor/fake_consent_auditor.h
+++ b/components/consent_auditor/fake_consent_auditor.h
@@ -18,6 +18,29 @@
   ~FakeConsentAuditor() override;
 
   // ConsentAuditor implementation.
+  void RecordSyncConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::SyncConsent& consent) override;
+
+  void RecordArcPlayConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent& consent)
+      override;
+
+  void RecordArcGoogleLocationServiceConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent& consent)
+      override;
+
+  void RecordArcBackupAndRestoreConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent& consent)
+      override;
+
+  void RecordUnifiedConsent(
+      const std::string& account_id,
+      const sync_pb::UserConsentTypes::UnifiedConsent& consent) override;
+
   void RecordGaiaConsent(const std::string& account_id,
                          consent_auditor::Feature feature,
                          const std::vector<int>& description_grd_ids,
@@ -32,6 +55,10 @@
   // Methods for fake.
   const std::string& account_id() const { return account_id_; }
 
+  const sync_pb::UserConsentTypes::SyncConsent& recorded_sync_consent() const {
+    return recorded_sync_consent_;
+  }
+
   const std::vector<std::vector<int>>& recorded_id_vectors() {
     return recorded_id_vectors_;
   }
@@ -46,8 +73,10 @@
     return recorded_statuses_;
   }
 
- private:
   std::string account_id_;
+
+  sync_pb::UserConsentTypes::SyncConsent recorded_sync_consent_;
+
   std::vector<std::vector<int>> recorded_id_vectors_;
   std::vector<int> recorded_confirmation_ids_;
   std::vector<Feature> recorded_features_;
diff --git a/components/feed/OWNERS b/components/feed/OWNERS
index 7f1733c..90e498d 100644
--- a/components/feed/OWNERS
+++ b/components/feed/OWNERS
@@ -1,6 +1,7 @@
 fgorski@chromium.org
 pavely@chromium.org
 pnoland@chromium.org
+skym@chromium.org
 zea@chromium.org
 
 per-file *Test.java=aluo@chromium.org
diff --git a/components/feed/features.gni b/components/feed/features.gni
index d61856bd8..73f73c7 100644
--- a/components/feed/features.gni
+++ b/components/feed/features.gni
@@ -3,6 +3,5 @@
 # found in the LICENSE file.
 
 declare_args() {
-  # Temporarily compile out Feed while M69 branches to avoid bloating binary.
-  enable_feed_in_chrome = false
+  enable_feed_in_chrome = is_android
 }
diff --git a/components/invalidation/impl/BUILD.gn b/components/invalidation/impl/BUILD.gn
index 092e48c..03a593c 100644
--- a/components/invalidation/impl/BUILD.gn
+++ b/components/invalidation/impl/BUILD.gn
@@ -65,6 +65,8 @@
 
   if (!is_android) {
     sources += [
+      "fcm_invalidator.cc",
+      "fcm_invalidator.h",
       "fcm_network_handler.cc",
       "fcm_network_handler.h",
       "fcm_sync_invalidation_listener.cc",
@@ -156,6 +158,7 @@
     # Non-Android tests.
     sources += [
       "fake_invalidator_unittest.cc",
+      "fcm_invalidator_unittest.cc",
       "fcm_network_handler_unittests.cc",
       "fcm_sync_invalidation_listener_unittest.cc",
       "gcm_invalidation_bridge_unittest.cc",
diff --git a/components/invalidation/impl/fcm_invalidator.cc b/components/invalidation/impl/fcm_invalidator.cc
new file mode 100644
index 0000000..15a6638
--- /dev/null
+++ b/components/invalidation/impl/fcm_invalidator.cc
@@ -0,0 +1,76 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/invalidation/impl/fcm_invalidator.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "components/invalidation/impl/fcm_sync_network_channel.h"
+#include "components/invalidation/impl/per_user_topic_invalidation_client.h"
+#include "components/invalidation/public/object_id_invalidation_map.h"
+
+namespace syncer {
+
+FCMInvalidator::FCMInvalidator(
+    std::unique_ptr<FCMSyncNetworkChannel> network_channel,
+    PrefService* pref_service,
+    network::mojom::URLLoaderFactory* loader_factory,
+    const ParseJSONCallback& parse_json)
+    : pref_service_(pref_service),
+      loader_factory_(loader_factory),
+      parse_json_(parse_json),
+      invalidation_listener_(std::move(network_channel)) {}
+
+FCMInvalidator::~FCMInvalidator() {}
+
+void FCMInvalidator::RegisterHandler(InvalidationHandler* handler) {
+  registrar_.RegisterHandler(handler);
+}
+
+bool FCMInvalidator::UpdateRegisteredIds(InvalidationHandler* handler,
+                                         const ObjectIdSet& ids) {
+  if (!registrar_.UpdateRegisteredIds(handler, ids))
+    return false;
+
+  invalidation_listener_.UpdateRegisteredIds(registrar_.GetAllRegisteredIds());
+  return true;
+}
+
+void FCMInvalidator::UnregisterHandler(InvalidationHandler* handler) {
+  registrar_.UnregisterHandler(handler);
+}
+
+InvalidatorState FCMInvalidator::GetInvalidatorState() const {
+  return registrar_.GetInvalidatorState();
+}
+
+void FCMInvalidator::UpdateCredentials(const std::string& email,
+                                       const std::string& token) {
+  if (!is_started_) {
+    auto registration_manager =
+        std::make_unique<PerUserTopicRegistrationManager>(
+            token, pref_service_, loader_factory_, parse_json_);
+    invalidation_listener_.Start(
+        base::BindOnce(&CreatePerUserTopicInvalidationClient), this,
+        std::move(registration_manager));
+    is_started_ = true;
+  }
+  // TODO(melandory): The token change is irrelevant for current implementation.
+}
+
+void FCMInvalidator::OnInvalidate(
+    const ObjectIdInvalidationMap& invalidation_map) {
+  registrar_.DispatchInvalidationsToHandlers(invalidation_map);
+}
+
+void FCMInvalidator::RequestDetailedStatus(
+    base::RepeatingCallback<void(const base::DictionaryValue&)> callback)
+    const {}
+
+void FCMInvalidator::OnInvalidatorStateChange(InvalidatorState state) {
+  registrar_.UpdateInvalidatorState(state);
+}
+
+}  // namespace syncer
diff --git a/components/invalidation/impl/fcm_invalidator.h b/components/invalidation/impl/fcm_invalidator.h
new file mode 100644
index 0000000..4f138be
--- /dev/null
+++ b/components/invalidation/impl/fcm_invalidator.h
@@ -0,0 +1,70 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATOR_H_
+#define COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATOR_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/invalidation/impl/fcm_sync_invalidation_listener.h"
+#include "components/invalidation/impl/invalidator.h"
+#include "components/invalidation/impl/invalidator_registrar.h"
+#include "components/invalidation/public/invalidator_state.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+class PrefService;
+
+namespace syncer {
+
+class FCMSyncNetworkChannel;
+
+// This class inplements the Invalidator interface and serves as a
+// bridge betwen invalidation Listener and invalidationr Service.
+class FCMInvalidator : public Invalidator,
+                       public FCMSyncInvalidationListener::Delegate {
+ public:
+  FCMInvalidator(std::unique_ptr<FCMSyncNetworkChannel> network_channel,
+                 PrefService* pref_service,
+                 network::mojom::URLLoaderFactory* loader_factory,
+                 const ParseJSONCallback& parse_json);
+
+  ~FCMInvalidator() override;
+
+  // Invalidator implementation.
+  void RegisterHandler(InvalidationHandler* handler) override;
+  bool UpdateRegisteredIds(InvalidationHandler* handler,
+                           const ObjectIdSet& ids) override;
+  void UnregisterHandler(InvalidationHandler* handler) override;
+  InvalidatorState GetInvalidatorState() const override;
+  void UpdateCredentials(const std::string& email,
+                         const std::string& token) override;
+  void RequestDetailedStatus(
+      base::RepeatingCallback<void(const base::DictionaryValue&)> callback)
+      const override;
+
+  // SyncInvalidationListener::Delegate implementation.
+  void OnInvalidate(const ObjectIdInvalidationMap& invalidation_map) override;
+  void OnInvalidatorStateChange(InvalidatorState state) override;
+
+ private:
+  friend class FCMInvalidatorTestDelegate;
+
+  bool is_started_ = false;
+  InvalidatorRegistrar registrar_;
+
+  // Needed for the creation of the registration manager.
+  std::string instance_id_token_;
+  PrefService* pref_service_;
+  network::mojom::URLLoaderFactory* loader_factory_ = nullptr;
+  syncer::ParseJSONCallback parse_json_;
+
+  // The invalidation listener.
+  FCMSyncInvalidationListener invalidation_listener_;
+
+  DISALLOW_COPY_AND_ASSIGN(FCMInvalidator);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATOR_H_
diff --git a/components/invalidation/impl/fcm_invalidator_unittest.cc b/components/invalidation/impl/fcm_invalidator_unittest.cc
new file mode 100644
index 0000000..6ab746fb
--- /dev/null
+++ b/components/invalidation/impl/fcm_invalidator_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/invalidation/impl/fcm_invalidator.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/invalidation/impl/fake_invalidation_handler.h"
+#include "components/invalidation/impl/invalidator_test_template.h"
+#include "components/invalidation/impl/json_unsafe_parser.h"
+#include "components/invalidation/impl/per_user_topic_registration_manager.h"
+#include "components/invalidation/impl/push_client_channel.h"
+#include "components/prefs/testing_pref_service.h"
+#include "net/url_request/url_request_test_util.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+namespace {
+
+class FCMInvalidatorTestDelegate {
+ public:
+  FCMInvalidatorTestDelegate() {
+    PerUserTopicRegistrationManager::RegisterProfilePrefs(
+        pref_service_.registry());
+  }
+
+  ~FCMInvalidatorTestDelegate() { DestroyInvalidator(); }
+
+  void CreateInvalidator(const std::string&,
+                         const std::string&,
+                         const base::WeakPtr<InvalidationStateTracker>&) {
+    DCHECK(!invalidator_);
+    auto network_channel = std::make_unique<FCMSyncNetworkChannel>();
+    invalidator_.reset(new FCMInvalidator(
+        std::move(network_channel), &pref_service_, &url_loader_factory_,
+        base::BindRepeating(&syncer::JsonUnsafeParser::Parse)));
+  }
+
+  Invalidator* GetInvalidator() { return invalidator_.get(); }
+
+  void DestroyInvalidator() {
+    base::RunLoop().RunUntilIdle();
+    invalidator_.reset();
+  }
+
+  void WaitForInvalidator() { base::RunLoop().RunUntilIdle(); }
+
+  void TriggerOnInvalidatorStateChange(InvalidatorState state) {
+    invalidator_->OnInvalidatorStateChange(state);
+  }
+
+  void TriggerOnIncomingInvalidation(
+      const ObjectIdInvalidationMap& invalidation_map) {
+    invalidator_->OnInvalidate(invalidation_map);
+  }
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  std::unique_ptr<FCMInvalidator> invalidator_;
+  network::TestURLLoaderFactory url_loader_factory_;
+  TestingPrefServiceSimple pref_service_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(FCMInvalidatorTest,
+                              InvalidatorTest,
+                              FCMInvalidatorTestDelegate);
+
+}  // namespace
+
+}  // namespace syncer
diff --git a/components/offline_pages/core/model/add_page_task.cc b/components/offline_pages/core/model/add_page_task.cc
index 8760e8b..6815597 100644
--- a/components/offline_pages/core/model/add_page_task.cc
+++ b/components/offline_pages/core/model/add_page_task.cc
@@ -37,9 +37,6 @@
 
 ItemActionStatus AddOfflinePageSync(const OfflinePageItem& item,
                                     sql::Connection* db) {
-  if (!db)
-    return ItemActionStatus::STORE_ERROR;
-
   static const char kSql[] =
       "INSERT OR IGNORE INTO offlinepages_v1"
       " (offline_id, online_url, client_namespace, client_id, file_path,"
@@ -95,7 +92,8 @@
   }
   store_->Execute(base::BindOnce(&AddOfflinePageSync, offline_page_),
                   base::BindOnce(&AddPageTask::OnAddPageDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  ItemActionStatus::STORE_ERROR);
 }
 
 void AddPageTask::OnAddPageDone(ItemActionStatus status) {
diff --git a/components/offline_pages/core/model/add_page_to_download_manager_task.cc b/components/offline_pages/core/model/add_page_to_download_manager_task.cc
index 7e8fea7..1ee21a9 100644
--- a/components/offline_pages/core/model/add_page_to_download_manager_task.cc
+++ b/components/offline_pages/core/model/add_page_to_download_manager_task.cc
@@ -19,9 +19,6 @@
 bool SetDownloadIdSync(int64_t offline_id,
                        int64_t download_id,
                        sql::Connection* db) {
-  if (!db)
-    return false;
-
   static const char kSql[] = "UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
                              " SET system_download_id = ?"
                              " WHERE offline_id = ?";
@@ -75,7 +72,8 @@
   // Add the download ID to the OfflinePageModel database.
   store_->Execute(base::BindOnce(&SetDownloadIdSync, offline_id_, download_id),
                   base::BindOnce(&AddPageToDownloadManagerTask::OnAddIdDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  false);
 }
 
 void AddPageToDownloadManagerTask::OnAddIdDone(bool result) {
diff --git a/components/offline_pages/core/model/cleanup_thumbnails_task.cc b/components/offline_pages/core/model/cleanup_thumbnails_task.cc
index afc673c..0040715e 100644
--- a/components/offline_pages/core/model/cleanup_thumbnails_task.cc
+++ b/components/offline_pages/core/model/cleanup_thumbnails_task.cc
@@ -18,8 +18,6 @@
 
 CleanupThumbnailsTask::Result CleanupThumbnailsSync(base::Time now,
                                                     sql::Connection* db) {
-  if (!db)
-    return CleanupThumbnailsTask::Result();
   static const char kSql[] =
       "DELETE FROM page_thumbnails "
       "WHERE offline_id IN ("
@@ -53,7 +51,8 @@
 void CleanupThumbnailsTask::Run() {
   store_->Execute(base::BindOnce(CleanupThumbnailsSync, now_),
                   base::BindOnce(&CleanupThumbnailsTask::Complete,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  Result());
 }
 
 void CleanupThumbnailsTask::Complete(Result result) {
diff --git a/components/offline_pages/core/model/clear_digest_task.cc b/components/offline_pages/core/model/clear_digest_task.cc
index e217754..f32ac8b 100644
--- a/components/offline_pages/core/model/clear_digest_task.cc
+++ b/components/offline_pages/core/model/clear_digest_task.cc
@@ -14,9 +14,6 @@
 namespace {
 
 bool ClearDigestSync(int64_t offline_id, sql::Connection* db) {
-  if (!db)
-    return false;
-
   static const char kSql[] =
       "UPDATE OR IGNORE offlinepages_v1"
       " SET digest = '' "
@@ -39,7 +36,8 @@
 void ClearDigestTask::Run() {
   store_->Execute(base::BindOnce(&ClearDigestSync, offline_id_),
                   base::BindOnce(&ClearDigestTask::OnClearDigestDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  false);
 }
 
 void ClearDigestTask::OnClearDigestDone(bool result) {
diff --git a/components/offline_pages/core/model/clear_storage_task.cc b/components/offline_pages/core/model/clear_storage_task.cc
index 4110dd10..99b5083f 100644
--- a/components/offline_pages/core/model/clear_storage_task.cc
+++ b/components/offline_pages/core/model/clear_storage_task.cc
@@ -185,9 +185,6 @@
     const base::Time& start_time,
     const ArchiveManager::StorageStats& stats,
     sql::Connection* db) {
-  if (!db)
-    return std::make_pair(0, DeletePageResult::STORE_FAILURE);
-
   std::unique_ptr<std::vector<PageInfo>> page_infos =
       GetPageInfosToClear(temp_namespace_policy_map, start_time, stats, db);
 
@@ -259,7 +256,8 @@
   store_->Execute(base::BindOnce(&ClearPagesSync, temp_namespace_policy_map,
                                  clearup_time_, stats),
                   base::BindOnce(&ClearStorageTask::OnClearPagesDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  {0, DeletePageResult::STORE_FAILURE});
 }
 
 void ClearStorageTask::OnClearPagesDone(
diff --git a/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc b/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc
index 8fd6db9..70b0336 100644
--- a/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc
+++ b/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc
@@ -24,9 +24,6 @@
     const std::string& digest,
     int64_t file_size,
     sql::Connection* db) {
-  if (!db)
-    return CompleteUpgradeStatus::DB_ERROR;
-
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return CompleteUpgradeStatus::DB_ERROR;
@@ -116,7 +113,8 @@
                      temporary_file_path_, target_file_path_, digest_,
                      file_size_),
       base::BindOnce(&CompleteOfflinePageUpgradeTask::InformUpgradeAttemptDone,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr()),
+      CompleteUpgradeStatus::DB_ERROR);
 }
 
 void CompleteOfflinePageUpgradeTask::InformUpgradeAttemptDone(
diff --git a/components/offline_pages/core/model/delete_page_task.cc b/components/offline_pages/core/model/delete_page_task.cc
index 28b421f..14e42ea6 100644
--- a/components/offline_pages/core/model/delete_page_task.cc
+++ b/components/offline_pages/core/model/delete_page_task.cc
@@ -171,8 +171,6 @@
 DeletePageTaskResult DeletePagesByOfflineIdsSync(
     const std::vector<int64_t>& offline_ids,
     sql::Connection* db) {
-  if (!db)
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
   if (offline_ids.empty())
     return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
 
@@ -220,8 +218,6 @@
     sql::Connection* db) {
   std::vector<DeletedPageInfoWrapper> infos;
 
-  if (!db)
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
   if (client_ids.empty())
     return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
 
@@ -272,8 +268,6 @@
     sql::Connection* db) {
   std::vector<DeletedPageInfoWrapper> infos;
 
-  if (!db)
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
   if (client_ids.empty())
     return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
 
@@ -330,9 +324,6 @@
     const std::vector<std::string>& namespaces,
     const UrlPredicate& predicate,
     sql::Connection* db) {
-  if (!db)
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-
   // If you create a transaction but dont Commit() it is automatically
   // rolled back by its destructor when it falls out of scope.
   sql::Transaction transaction(db);
@@ -387,9 +378,6 @@
                                              std::string name_space,
                                              size_t limit,
                                              sql::Connection* db) {
-  if (!db)
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-
   // If the namespace can have unlimited pages per url, just return success.
   if (limit == kUnlimitedPages)
     return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
@@ -502,7 +490,8 @@
 void DeletePageTask::Run() {
   store_->Execute(std::move(func_),
                   base::BindOnce(&DeletePageTask::OnDeletePageDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}));
 }
 
 void DeletePageTask::OnDeletePageDone(DeletePageTaskResult result) {
diff --git a/components/offline_pages/core/model/get_pages_task.cc b/components/offline_pages/core/model/get_pages_task.cc
index 04013ab..9db4474 100644
--- a/components/offline_pages/core/model/get_pages_task.cc
+++ b/components/offline_pages/core/model/get_pages_task.cc
@@ -65,10 +65,6 @@
 
 ReadResult ReadAllPagesSync(sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   static const char kSql[] =
       "SELECT " OFFLINE_PAGE_PROJECTION " FROM offlinepages_v1";
@@ -83,10 +79,6 @@
 ReadResult ReadPagesByClientIdsSync(const std::vector<ClientId>& client_ids,
                                     sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   sql::Transaction transaction(db);
   if (!transaction.Begin())
@@ -131,9 +123,6 @@
     const std::vector<std::string>& namespaces,
     sql::Connection* db) {
   ReadResult result;
-  if (!db)
-    return result;
-
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return result;
@@ -153,10 +142,6 @@
 ReadResult ReadPagesByRequestOriginSync(const std::string& request_origin,
                                         sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   static const char kSql[] = "SELECT " OFFLINE_PAGE_PROJECTION
                              " FROM offlinepages_v1"
@@ -186,10 +171,6 @@
 // while loop.
 ReadResult ReadPagesByUrlSync(const GURL& url, sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   GURL::Replacements remove_fragment;
   remove_fragment.ClearRef();
@@ -218,10 +199,6 @@
 
 ReadResult ReadPagesByOfflineId(int64_t offline_id, sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   static const char kSql[] = "SELECT " OFFLINE_PAGE_PROJECTION
                              " FROM offlinepages_v1"
@@ -237,10 +214,6 @@
 
 ReadResult ReadPagesByGuid(const std::string& guid, sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   static const char kSql[] = "SELECT " OFFLINE_PAGE_PROJECTION
                              " FROM offlinepages_v1"
@@ -258,10 +231,6 @@
                                     const std::string& digest,
                                     sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   static const char kSql[] = "SELECT " OFFLINE_PAGE_PROJECTION
                              " FROM offlinepages_v1"
@@ -286,10 +255,6 @@
 
 ReadResult SelectItemsForUpgrade(sql::Connection* db) {
   ReadResult result;
-  if (!db) {
-    result.success = false;
-    return result;
-  }
 
   static const char kSql[] =
       "SELECT " OFFLINE_PAGE_PROJECTION
@@ -307,7 +272,7 @@
 
 }  // namespace
 
-GetPagesTask::ReadResult::ReadResult() : success(false) {}
+GetPagesTask::ReadResult::ReadResult() {}
 
 GetPagesTask::ReadResult::ReadResult(const ReadResult& other) = default;
 
@@ -449,7 +414,8 @@
 void GetPagesTask::ReadRequests() {
   store_->Execute(std::move(db_work_callback_),
                   base::BindOnce(&GetPagesTask::CompleteWithResult,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  ReadResult());
 }
 
 void GetPagesTask::CompleteWithResult(ReadResult result) {
diff --git a/components/offline_pages/core/model/get_pages_task.h b/components/offline_pages/core/model/get_pages_task.h
index 825199b..f7621f3 100644
--- a/components/offline_pages/core/model/get_pages_task.h
+++ b/components/offline_pages/core/model/get_pages_task.h
@@ -29,7 +29,7 @@
     ReadResult(const ReadResult& other);
     ~ReadResult();
 
-    bool success;
+    bool success = false;
     std::vector<OfflinePageItem> pages;
   };
 
diff --git a/components/offline_pages/core/model/get_thumbnail_task.cc b/components/offline_pages/core/model/get_thumbnail_task.cc
index abdfab1..c58d1ca4 100644
--- a/components/offline_pages/core/model/get_thumbnail_task.cc
+++ b/components/offline_pages/core/model/get_thumbnail_task.cc
@@ -16,8 +16,6 @@
 
 std::unique_ptr<OfflinePageThumbnail> GetThumbnailSync(int64_t offline_id,
                                                        sql::Connection* db) {
-  if (!db)
-    return nullptr;
   std::unique_ptr<OfflinePageThumbnail> result;
   static const char kSql[] =
       "SELECT offline_id, expiration, thumbnail FROM page_thumbnails"
@@ -54,7 +52,8 @@
 void GetThumbnailTask::Run() {
   store_->Execute(base::BindOnce(GetThumbnailSync, std::move(offline_id_)),
                   base::BindOnce(&GetThumbnailTask::Complete,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  std::unique_ptr<OfflinePageThumbnail>());
 }
 
 void GetThumbnailTask::Complete(std::unique_ptr<OfflinePageThumbnail> result) {
diff --git a/components/offline_pages/core/model/has_thumbnail_task.cc b/components/offline_pages/core/model/has_thumbnail_task.cc
index b76f48c..13a60adf 100644
--- a/components/offline_pages/core/model/has_thumbnail_task.cc
+++ b/components/offline_pages/core/model/has_thumbnail_task.cc
@@ -14,8 +14,6 @@
 namespace {
 
 bool ThumbnailExistsSync(int64_t offline_id, sql::Connection* db) {
-  if (!db)
-    return false;
   static const char kSql[] =
       "SELECT 1 FROM page_thumbnails WHERE offline_id = ?";
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -38,7 +36,8 @@
 void HasThumbnailTask::Run() {
   store_->Execute(base::BindOnce(ThumbnailExistsSync, std::move(offline_id_)),
                   base::BindOnce(&HasThumbnailTask::OnThumbnailExists,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  false);
 }
 
 void HasThumbnailTask::OnThumbnailExists(bool exists) {
diff --git a/components/offline_pages/core/model/mark_page_accessed_task.cc b/components/offline_pages/core/model/mark_page_accessed_task.cc
index 457b4036..4e48e95 100644
--- a/components/offline_pages/core/model/mark_page_accessed_task.cc
+++ b/components/offline_pages/core/model/mark_page_accessed_task.cc
@@ -52,9 +52,6 @@
 bool MarkPageAccessedSync(const base::Time& access_time,
                           int64_t offline_id,
                           sql::Connection* db) {
-  if (!db)
-    return false;
-
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return false;
@@ -92,7 +89,8 @@
   store_->Execute(
       base::BindOnce(&MarkPageAccessedSync, access_time_, offline_id_),
       base::BindOnce(&MarkPageAccessedTask::OnMarkPageAccessedDone,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr()),
+      false);
 }
 
 void MarkPageAccessedTask::OnMarkPageAccessedDone(bool result) {
diff --git a/components/offline_pages/core/model/persistent_page_consistency_check_task.cc b/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
index 9dffb84a..648912d 100644
--- a/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
+++ b/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
@@ -120,9 +120,6 @@
     base::Time check_time,
     sql::Connection* db) {
   std::vector<int64_t> download_ids_of_deleted_pages;
-  if (!db)
-    return {SyncOperationResult::INVALID_DB_CONNECTION,
-            download_ids_of_deleted_pages};
 
   sql::Transaction transaction(db);
   if (!transaction.Begin())
@@ -229,7 +226,8 @@
                                  persistent_namespaces, check_time_),
                   base::BindOnce(&PersistentPageConsistencyCheckTask::
                                      OnPersistentPageConsistencyCheckDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  CheckResult{SyncOperationResult::INVALID_DB_CONNECTION, {}});
 }
 
 void PersistentPageConsistencyCheckTask::OnPersistentPageConsistencyCheckDone(
diff --git a/components/offline_pages/core/model/start_offline_page_upgrade_task.cc b/components/offline_pages/core/model/start_offline_page_upgrade_task.cc
index 1737950..9cb4fec 100644
--- a/components/offline_pages/core/model/start_offline_page_upgrade_task.cc
+++ b/components/offline_pages/core/model/start_offline_page_upgrade_task.cc
@@ -21,9 +21,6 @@
     int64_t offline_id,
     const base::FilePath& target_directory,
     sql::Connection* db) {
-  if (!db)
-    return StartUpgradeResult(StartUpgradeStatus::DB_ERROR);
-
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return StartUpgradeResult(StartUpgradeStatus::DB_ERROR);
@@ -93,7 +90,8 @@
       base::BindOnce(&StartOfflinePageUpgradeSync, offline_id_,
                      target_directory_),
       base::BindOnce(&StartOfflinePageUpgradeTask::InformUpgradeAttemptDone,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr()),
+      StartUpgradeResult(StartUpgradeStatus::DB_ERROR));
 }
 
 void StartOfflinePageUpgradeTask::InformUpgradeAttemptDone(
diff --git a/components/offline_pages/core/model/startup_maintenance_task.cc b/components/offline_pages/core/model/startup_maintenance_task.cc
index 4e303fd..56e5fb1 100644
--- a/components/offline_pages/core/model/startup_maintenance_task.cc
+++ b/components/offline_pages/core/model/startup_maintenance_task.cc
@@ -248,9 +248,6 @@
     const base::FilePath& temporary_archives_dir,
     const base::FilePath& private_archives_dir,
     sql::Connection* db) {
-  if (!db)
-    return false;
-
   // Clear temporary pages that are in legacy directory, which is also the
   // directory that serves as the 'private' directory.
   SyncOperationResult result = ClearLegacyPagesInPrivateDirSync(
@@ -304,7 +301,8 @@
                      archive_manager_->GetTemporaryArchivesDir(),
                      archive_manager_->GetPrivateArchivesDir()),
       base::BindOnce(&StartupMaintenanceTask::OnStartupMaintenanceDone,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr()),
+      false);
 }
 
 void StartupMaintenanceTask::OnStartupMaintenanceDone(bool result) {
diff --git a/components/offline_pages/core/model/store_thumbnail_task.cc b/components/offline_pages/core/model/store_thumbnail_task.cc
index 48c1c440..3388325 100644
--- a/components/offline_pages/core/model/store_thumbnail_task.cc
+++ b/components/offline_pages/core/model/store_thumbnail_task.cc
@@ -16,8 +16,6 @@
 
 bool StoreThumbnailSync(const OfflinePageThumbnail& thumbnail,
                         sql::Connection* db) {
-  if (!db)
-    return false;
   static const char kSql[] =
       "INSERT OR REPLACE INTO page_thumbnails (offline_id, expiration, "
       "thumbnail) VALUES (?, ?, ?)";
@@ -44,7 +42,8 @@
 void StoreThumbnailTask::Run() {
   store_->Execute(base::BindOnce(StoreThumbnailSync, std::move(thumbnail_)),
                   base::BindOnce(&StoreThumbnailTask::Complete,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  false);
 }
 
 void StoreThumbnailTask::Complete(bool success) {
diff --git a/components/offline_pages/core/model/update_file_path_task.cc b/components/offline_pages/core/model/update_file_path_task.cc
index a4cc5441..7b7ff7c 100644
--- a/components/offline_pages/core/model/update_file_path_task.cc
+++ b/components/offline_pages/core/model/update_file_path_task.cc
@@ -20,9 +20,6 @@
 bool UpdateFilePathSync(const base::FilePath& new_file_path,
                         int64_t offline_id,
                         sql::Connection* db) {
-  if (!db)
-    return false;
-
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return false;
@@ -66,7 +63,8 @@
 void UpdateFilePathTask::Run() {
   store_->Execute(base::BindOnce(&UpdateFilePathSync, file_path_, offline_id_),
                   base::BindOnce(&UpdateFilePathTask::OnUpdateFilePathDone,
-                                 weak_ptr_factory_.GetWeakPtr()));
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  false);
 }
 
 void UpdateFilePathTask::OnUpdateFilePathDone(bool result) {
diff --git a/components/offline_pages/core/offline_page_metadata_store.h b/components/offline_pages/core/offline_page_metadata_store.h
index b62865b..351d5c5 100644
--- a/components/offline_pages/core/offline_page_metadata_store.h
+++ b/components/offline_pages/core/offline_page_metadata_store.h
@@ -119,18 +119,20 @@
   // its result back to calling thread through |result_callback|.
   // Calling |Execute| when store is NOT_LOADED will cause the store
   // initialization to start.
-  // Store state needs to be LOADED for test task to run, or FAILURE, in which
-  // case the |db| pointer passed to |run_callback| will be null and such case
-  // should be gracefully handled.
+  // Store state needs to be LOADED for |run_callback| to run.
+  // If initialization fails, |result_callback| is invoked with |default_value|.
   template <typename T>
-  void Execute(RunCallback<T> run_callback, ResultCallback<T> result_callback) {
+  void Execute(RunCallback<T> run_callback,
+               ResultCallback<T> result_callback,
+               T default_value) {
     // TODO(fgorski): Add a proper state indicating in progress initialization
     // and CHECK that state.
 
     if (state_ == StoreState::NOT_LOADED) {
       InitializeInternal(base::BindOnce(
           &OfflinePageMetadataStore::Execute<T>, weak_ptr_factory_.GetWeakPtr(),
-          std::move(run_callback), std::move(result_callback)));
+          std::move(run_callback), std::move(result_callback),
+          std::move(default_value)));
       return;
     }
 
@@ -142,7 +144,8 @@
     if (state_ == StoreState::INITIALIZING) {
       pending_commands_.push_back(base::BindOnce(
           &OfflinePageMetadataStore::Execute<T>, weak_ptr_factory_.GetWeakPtr(),
-          std::move(run_callback), std::move(result_callback)));
+          std::move(run_callback), std::move(result_callback),
+          std::move(default_value)));
       TRACE_EVENT_ASYNC_END1("offline_pages", "Metadata Store: task execution",
                              this, "postponed", true);
       return;
@@ -152,7 +155,12 @@
     closing_weak_ptr_factory_.InvalidateWeakPtrs();
 
     sql::Connection* db = state_ == StoreState::LOADED ? db_.get() : nullptr;
-
+    if (!db) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE,
+          base::BindOnce(std::move(result_callback), std::move(default_value)));
+      return;
+    }
     base::PostTaskAndReplyWithResult(
         background_task_runner_.get(), FROM_HERE,
         base::BindOnce(std::move(run_callback), db),
diff --git a/components/offline_pages/core/offline_page_metadata_store_test_util.cc b/components/offline_pages/core/offline_page_metadata_store_test_util.cc
index 67d9518..c02f460 100644
--- a/components/offline_pages/core/offline_page_metadata_store_test_util.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_test_util.cc
@@ -80,7 +80,8 @@
       base::BindOnce(&GetPageCountSync),
       base::BindOnce(
           [](int64_t* out_count, int64_t cb_count) { *out_count = cb_count; },
-          &count));
+          &count),
+      int64_t());
   task_runner_->RunUntilIdle();
   return count;
 }
diff --git a/components/offline_pages/core/offline_page_metadata_store_unittest.cc b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
index 71286a9b..811d3c3 100644
--- a/components/offline_pages/core/offline_page_metadata_store_unittest.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
@@ -519,9 +519,6 @@
 std::vector<OfflinePageItem> GetOfflinePagesSync(sql::Connection* db) {
   std::vector<OfflinePageItem> result;
 
-  if (!db)
-    return result;
-
   static const char kSql[] = "SELECT * FROM " OFFLINE_PAGES_TABLE_V1;
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
 
@@ -659,14 +656,15 @@
 
   template <typename T>
   T ExecuteSync(OfflinePageMetadataStore* store,
-                base::OnceCallback<T(sql::Connection*)> run_callback) {
+                base::OnceCallback<T(sql::Connection*)> run_callback,
+                T default_value) {
     bool called = false;
     T result;
     auto result_callback = base::BindLambdaForTesting([&](T async_result) {
       result = std::move(async_result);
       called = true;
     });
-    store->Execute<T>(std::move(run_callback), result_callback);
+    store->Execute<T>(std::move(run_callback), result_callback, default_value);
     PumpLoop();
     EXPECT_TRUE(called);
     return result;
@@ -677,21 +675,18 @@
       base::OnceCallback<void(std::vector<OfflinePageItem>)> callback) {
     auto run_callback = base::BindOnce(&GetOfflinePagesSync);
     store->Execute<std::vector<OfflinePageItem>>(std::move(run_callback),
-                                                 std::move(callback));
+                                                 std::move(callback), {});
   }
 
   std::vector<OfflinePageItem> GetOfflinePages(
       OfflinePageMetadataStore* store) {
     return ExecuteSync<std::vector<OfflinePageItem>>(
-        store, base::BindOnce(&GetOfflinePagesSync));
+        store, base::BindOnce(&GetOfflinePagesSync), {});
   }
 
   ItemActionStatus AddOfflinePage(OfflinePageMetadataStore* store,
                                   const OfflinePageItem& item) {
     auto result_callback = base::BindLambdaForTesting([&](sql::Connection* db) {
-      if (!db)
-        return ItemActionStatus::STORE_ERROR;
-
       // Using 'INSERT OR FAIL' or 'INSERT OR ABORT' in the query below
       // causes debug builds to DLOG.
       static const char kSql[] =
@@ -730,7 +725,8 @@
         return ItemActionStatus::ALREADY_EXISTS;
       return ItemActionStatus::SUCCESS;
     });
-    return ExecuteSync<ItemActionStatus>(store, result_callback);
+    return ExecuteSync<ItemActionStatus>(store, result_callback,
+                                         ItemActionStatus::SUCCESS);
   }
 
   std::vector<OfflinePageThumbnail> GetThumbnails(
@@ -752,7 +748,8 @@
       EXPECT_TRUE(statement.Succeeded());
       return thumbnails;
     });
-    return ExecuteSync<std::vector<OfflinePageThumbnail>>(store, run_callback);
+    return ExecuteSync<std::vector<OfflinePageThumbnail>>(store, run_callback,
+                                                          {});
   }
 
   void AddThumbnail(OfflinePageMetadataStore* store,
@@ -770,7 +767,7 @@
       EXPECT_TRUE(statement.Run());
       return thumbnails;
     });
-    ExecuteSync<std::vector<OfflinePageThumbnail>>(store, run_callback);
+    ExecuteSync<std::vector<OfflinePageThumbnail>>(store, run_callback, {});
   }
 
  protected:
diff --git a/components/offline_pages/core/prefetch/store/README.md b/components/offline_pages/core/prefetch/store/README.md
index 73453dd..8b95a15 100644
--- a/components/offline_pages/core/prefetch/store/README.md
+++ b/components/offline_pages/core/prefetch/store/README.md
@@ -45,11 +45,12 @@
   // its result back to calling thread through |result_callback|.
   // Calling |Execute| when store is NOT_INITIALIZED will cause the store
   // initialization to start.
-  // Store initialization status needs to be SUCCESS for test task to run, or
-  // FAILURE, in which case the |db| pointer passed to |run_callback| will be
-  // null and such case should be gracefully handled.
+  // Store initialization status needs to be SUCCESS for |run_callback| to run.
+  // If initialization fails, |result_callback| is invoked with |default_value|.
   template <typename T>
-  void Execute(RunCallback<T> run_callback, ResultCallback<T> result_callback);
+  void Execute(RunCallback<T> run_callback,
+               ResultCallback<T> result_callback,
+               T default_value);
 
   // Gets the initialization status of the store.
   InitializationStatus initialization_status() const;
@@ -74,15 +75,10 @@
 
 ```cpp
 bool ExampleRunCallback(sql::Connection* db) {
-  // Run function should start from ensuring that provided `db` pointer is not
-  // nullptr. If it is, there has been an error opening or initializing the DB.
-  // Such case is possible and it would not be appropriate to CHECK/DCHECK in
-  // that case. Code written against PrefetchStore is supposed to handle error
-  // cases like that gracefully.
-  if (!db)
-    return false;
+  // Note that the run function won't be called if the database fails to
+  // initialize, so db is always non-null.
 
-  // Next it's best to start a transaction, which can be aborted without making
+  // It's best to start a transaction, which can be aborted without making
   // changes to the data. This is one of the reasons to go with provided store
   // interface.
   sql::Transaction transaction(db);
@@ -119,6 +115,9 @@
 semantics. This is how result is made available on the foreground thread.
 ResultCallback takes over ownership of the passed in result.
 
+If the database fails to initialize, the RunCallback isn't called and instead,
+the default_value provided to Execute is passed to the ResultCallback.
+
 ```cpp
 void ExampleResultCallback(bool success) {
   if (!success) {
diff --git a/components/pdf_strings.grdp b/components/pdf_strings.grdp
index 14a7c2f..150be9d 100644
--- a/components/pdf_strings.grdp
+++ b/components/pdf_strings.grdp
@@ -60,5 +60,12 @@
          =1 {Page 1}
          other {Page #}}
     </message>
+    <message name="IDS_PDF_SAVE_CALLED_TITLE" desc="Title of the dialog which shows a message warning the user that saving documents directly is not implemented.">
+      Warning
+    </message>
+    <message name="IDS_PDF_SAVE_CALLED_TEXT"
+             desc="Contents of the dialog shown when a save operation is attempted in the PDF viewer. Indicates to the user that the operation is not currently implemented and that they will need to print the PDF and use 'Save as PDF' to create a new PDF with their data.">
+      Saving content entered into PDF forms is currently not supported. Please print the PDF and use the 'Save as PDF' destination to create a new PDF with the entered data.
+    </message>
   </if>
 </grit-part>
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 74796cc0..dafb516c 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -1414,6 +1414,9 @@
 
     // Wipe all the users off of the device.
     DEVICE_WIPE_USERS = 5;
+
+    // Start Chrome Remote Desktop session (limited to Kiosk sessions only).
+    DEVICE_START_CRD_SESSION = 6;
   }
 
   // The command type.
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 3a7820e..24152e3 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -96,6 +96,7 @@
     "driver/async_directory_type_controller.h",
     "driver/backend_migrator.cc",
     "driver/backend_migrator.h",
+    "driver/clear_server_data_events.h",
     "driver/data_type_controller.cc",
     "driver/data_type_controller.h",
     "driver/data_type_encryption_handler.cc",
diff --git a/components/sync/driver/about_sync_util_unittest.cc b/components/sync/driver/about_sync_util_unittest.cc
index 2f42d68f1..e6470b0 100644
--- a/components/sync/driver/about_sync_util_unittest.cc
+++ b/components/sync/driver/about_sync_util_unittest.cc
@@ -21,7 +21,9 @@
     return DISABLE_REASON_UNRECOVERABLE_ERROR;
   }
 
-  bool QueryDetailedSyncStatus(SyncStatus* result) override { return false; }
+  bool QueryDetailedSyncStatus(SyncStatus* result) const override {
+    return false;
+  }
 
   SyncCycleSnapshot GetLastCycleSnapshot() const override {
     return SyncCycleSnapshot();
diff --git a/components/sync/driver/clear_server_data_events.h b/components/sync/driver/clear_server_data_events.h
new file mode 100644
index 0000000..bc6704d
--- /dev/null
+++ b/components/sync/driver/clear_server_data_events.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_CLEAR_SERVER_DATA_EVENTS_H_
+#define COMPONENTS_SYNC_DRIVER_CLEAR_SERVER_DATA_EVENTS_H_
+
+namespace syncer {
+
+// Events in ClearServerData flow to be recorded in histogram. Existing
+// constants should not be deleted or reordered. New ones shold be added at the
+// end, before CLEAR_SERVER_DATA_MAX.
+enum ClearServerDataEvents {
+  // ClearServerData started after user switched to custom passphrase.
+  CLEAR_SERVER_DATA_STARTED,
+  // DataTypeManager reported that catchup configuration failed.
+  CLEAR_SERVER_DATA_CATCHUP_FAILED,
+  // ClearServerData flow restarted after browser restart.
+  CLEAR_SERVER_DATA_RETRIED,
+  // Success.
+  CLEAR_SERVER_DATA_SUCCEEDED,
+  // Client received RECET_LOCAL_SYNC_DATA after custom passphrase was enabled
+  // on different client.
+  CLEAR_SERVER_DATA_RESET_LOCAL_DATA_RECEIVED,
+  CLEAR_SERVER_DATA_MAX
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_DRIVER_CLEAR_SERVER_DATA_EVENTS_H_
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc
index 439459d..a595a8c 100644
--- a/components/sync/driver/fake_sync_service.cc
+++ b/components/sync/driver/fake_sync_service.cc
@@ -104,10 +104,6 @@
 
 void FakeSyncService::SetFirstSetupComplete() {}
 
-bool FakeSyncService::IsFirstSetupInProgress() const {
-  return false;
-}
-
 std::unique_ptr<SyncSetupInProgressHandle>
 FakeSyncService::GetSetupInProgressHandle() {
   return nullptr;
@@ -173,7 +169,7 @@
   return syncer::SyncTokenStatus();
 }
 
-bool FakeSyncService::QueryDetailedSyncStatus(SyncStatus* result) {
+bool FakeSyncService::QueryDetailedSyncStatus(SyncStatus* result) const {
   return false;
 }
 
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h
index 3357f69..2f21e64 100644
--- a/components/sync/driver/fake_sync_service.h
+++ b/components/sync/driver/fake_sync_service.h
@@ -56,7 +56,6 @@
   void OnUserChoseDatatypes(bool sync_everything,
                             ModelTypeSet chosen_types) override;
   void SetFirstSetupComplete() override;
-  bool IsFirstSetupInProgress() const override;
   std::unique_ptr<SyncSetupInProgressHandle> GetSetupInProgressHandle()
       override;
   bool IsSetupInProgress() const override;
@@ -76,7 +75,7 @@
   const LocalDeviceInfoProvider* GetLocalDeviceInfoProvider() const override;
   void ReenableDatatype(ModelType type) override;
   SyncTokenStatus GetSyncTokenStatus() const override;
-  bool QueryDetailedSyncStatus(SyncStatus* result) override;
+  bool QueryDetailedSyncStatus(SyncStatus* result) const override;
   base::Time GetLastSyncedTime() const override;
   SyncCycleSnapshot GetLastCycleSnapshot() const override;
   std::unique_ptr<base::Value> GetTypeStatusMap() override;
diff --git a/components/sync/driver/sync_error_controller.cc b/components/sync/driver/sync_error_controller.cc
index 29116fe5..be083435 100644
--- a/components/sync/driver/sync_error_controller.cc
+++ b/components/sync/driver/sync_error_controller.cc
@@ -15,7 +15,7 @@
 
 SyncErrorController::~SyncErrorController() {}
 
-bool SyncErrorController::HasError() {
+bool SyncErrorController::HasError() const {
   return service_->IsFirstSetupComplete() && service_->IsPassphraseRequired() &&
          service_->IsPassphraseRequiredForDecryption();
 }
diff --git a/components/sync/driver/sync_error_controller.h b/components/sync/driver/sync_error_controller.h
index faca1b4..423e007 100644
--- a/components/sync/driver/sync_error_controller.h
+++ b/components/sync/driver/sync_error_controller.h
@@ -29,7 +29,7 @@
   ~SyncErrorController() override;
 
   // True if there exists an error worth elevating to the user.
-  bool HasError();
+  bool HasError() const;
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/components/sync/driver/sync_service.cc b/components/sync/driver/sync_service.cc
index cb251d3..5272ae7 100644
--- a/components/sync/driver/sync_service.cc
+++ b/components/sync/driver/sync_service.cc
@@ -27,6 +27,10 @@
   return state == State::CONFIGURING || state == State::ACTIVE;
 }
 
+bool SyncService::IsFirstSetupInProgress() const {
+  return !IsFirstSetupComplete() && IsSetupInProgress();
+}
+
 bool SyncService::HasUnrecoverableError() const {
   return HasDisableReason(DISABLE_REASON_UNRECOVERABLE_ERROR);
 }
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index d70be88..bb5eac1 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -40,24 +40,6 @@
 struct SyncStatus;
 struct UserShare;
 
-// Events in ClearServerData flow to be recorded in histogram. Existing
-// constants should not be deleted or reordered. New ones shold be added at the
-// end, before CLEAR_SERVER_DATA_MAX.
-enum ClearServerDataEvents {
-  // ClearServerData started after user switched to custom passphrase.
-  CLEAR_SERVER_DATA_STARTED,
-  // DataTypeManager reported that catchup configuration failed.
-  CLEAR_SERVER_DATA_CATCHUP_FAILED,
-  // ClearServerData flow restarted after browser restart.
-  CLEAR_SERVER_DATA_RETRIED,
-  // Success.
-  CLEAR_SERVER_DATA_SUCCEEDED,
-  // Client received RECET_LOCAL_SYNC_DATA after custom passphrase was enabled
-  // on different client.
-  CLEAR_SERVER_DATA_RESET_LOCAL_DATA_RECEIVED,
-  CLEAR_SERVER_DATA_MAX
-};
-
 // UIs that need to prevent Sync startup should hold an instance of this class
 // until the user has finished modifying sync settings. This is not an inner
 // class of SyncService to enable forward declarations.
@@ -262,7 +244,7 @@
   // if the user is customizing sync after already completing setup once).
   // SyncService uses this to determine if it's OK to start syncing, or if the
   // user is still setting up the initial sync configuration.
-  virtual bool IsFirstSetupInProgress() const = 0;
+  bool IsFirstSetupInProgress() const;
 
   // Called by the UI to notify the SyncService that UI is visible so it will
   // not start syncing. This tells sync whether it's safe to start downloading
@@ -275,7 +257,6 @@
   virtual std::unique_ptr<SyncSetupInProgressHandle>
   GetSetupInProgressHandle() = 0;
 
-  // Used by tests.
   virtual bool IsSetupInProgress() const = 0;
 
   virtual const GoogleServiceAuthError& GetAuthError() const = 0;
@@ -351,7 +332,7 @@
   // Initializes a struct of status indicators with data from the engine.
   // Returns false if the engine was not available for querying; in that case
   // the struct will be filled with default data.
-  virtual bool QueryDetailedSyncStatus(SyncStatus* result) = 0;
+  virtual bool QueryDetailedSyncStatus(SyncStatus* result) const = 0;
 
   // Returns the last synced time.
   virtual base::Time GetLastSyncedTime() const = 0;
diff --git a/components/sync/driver/sync_service_crypto.cc b/components/sync/driver/sync_service_crypto.cc
index 34c6acd..83ff6cf 100644
--- a/components/sync/driver/sync_service_crypto.cc
+++ b/components/sync/driver/sync_service_crypto.cc
@@ -12,6 +12,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/sync/base/nigori.h"
 #include "components/sync/base/sync_prefs.h"
+#include "components/sync/driver/clear_server_data_events.h"
 #include "components/sync/driver/data_type_manager.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/driver/sync_service.h"
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc
index 7efd7c6..c0d6a8be 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync_bookmarks/synced_bookmark_tracker.h"
 
+#include <set>
 #include <utility>
 
 #include "base/base64.h"
@@ -213,10 +214,10 @@
 
 std::vector<const SyncedBookmarkTracker::Entity*>
 SyncedBookmarkTracker::GetEntitiesWithLocalChanges(size_t max_entries) const {
-  // TODO(crbug.com/516866): Reorder local changes to e.g. parent creation
-  // before child creation and the otherway around for deletions.
-  // TODO(crbug.com/516866): Return no more than |max_entries|.
+  // TODO(crbug.com/516866): Return no more than |max_entries| after sorting.
   std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_changes;
+  // Entities with local non deletions should be sorted such that parent
+  // creation/update comes before child creation/update.
   for (const std::pair<const std::string, std::unique_ptr<Entity>>& pair :
        sync_id_to_entities_map_) {
     Entity* entity = pair.second.get();
@@ -229,10 +230,78 @@
       entities_with_local_changes.push_back(entity);
     }
   }
+  std::vector<const SyncedBookmarkTracker::Entity*> ordered_local_changes =
+      ReorderUnsyncedEntitiesExceptDeletions(entities_with_local_changes);
   for (const Entity* tombstone_entity : ordered_local_tombstones_) {
-    entities_with_local_changes.push_back(tombstone_entity);
+    ordered_local_changes.push_back(tombstone_entity);
   }
-  return entities_with_local_changes;
+  return ordered_local_changes;
+}
+
+std::vector<const SyncedBookmarkTracker::Entity*>
+SyncedBookmarkTracker::ReorderUnsyncedEntitiesExceptDeletions(
+    const std::vector<const SyncedBookmarkTracker::Entity*>& entities) const {
+  // This method sorts the entities with local non deletions such that parent
+  // creation/update comes before child creation/update.
+
+  // The algorithm works by constructing a forest of all non-deletion updates
+  // and then traverses each tree in the forest recursively:
+  // 1. Iterate over all entities and collect all nodes in |nodes|.
+  // 2. Iterate over all entities again and node that is a child of another
+  //    node. What's left in |nodes| are the roots of the forest.
+  // 3. Start at each root in |nodes|, emit the update and recurse over its
+  //    children.
+  std::set<const bookmarks::BookmarkNode*> nodes;
+  // Collect nodes with updates
+  for (const SyncedBookmarkTracker::Entity* entity : entities) {
+    DCHECK(entity->IsUnsynced());
+    DCHECK(!entity->metadata()->is_deleted());
+    DCHECK(entity->bookmark_node());
+    nodes.insert(entity->bookmark_node());
+  }
+  // Remove those who are direct children of another node.
+  for (const SyncedBookmarkTracker::Entity* entity : entities) {
+    const bookmarks::BookmarkNode* node = entity->bookmark_node();
+    for (int i = 0; i < node->child_count(); ++i) {
+      nodes.erase(node->GetChild(i));
+    }
+  }
+  // |nodes| contains only roots of all trees in the forest all of which are
+  // ready to be processed because their parents have no pending updates.
+  std::vector<const SyncedBookmarkTracker::Entity*> ordered_entities;
+  for (const bookmarks::BookmarkNode* node : nodes) {
+    TraverseAndAppend(node, &ordered_entities);
+  }
+  return ordered_entities;
+}
+
+void SyncedBookmarkTracker::TraverseAndAppend(
+    const bookmarks::BookmarkNode* node,
+    std::vector<const SyncedBookmarkTracker::Entity*>* ordered_entities) const {
+  const SyncedBookmarkTracker::Entity* entity = GetEntityForBookmarkNode(node);
+  DCHECK(entity->IsUnsynced());
+  DCHECK(!entity->metadata()->is_deleted());
+  ordered_entities->push_back(entity);
+  // Recurse for all children.
+  for (int i = 0; i < node->child_count(); ++i) {
+    const bookmarks::BookmarkNode* child = node->GetChild(i);
+    const SyncedBookmarkTracker::Entity* child_entity =
+        GetEntityForBookmarkNode(child);
+    if (!child_entity->IsUnsynced()) {
+      // If the entity has no local change, no need to check it's children. If
+      // any of the children would have a pending commit, it would be a root for
+      // a separate tree in the forest built in
+      // ReorderEntitiesWithLocalNonDeletions() and will be handled by another
+      // call to TraverseAndAppend().
+      continue;
+    }
+    if (child_entity->metadata()->is_deleted()) {
+      // Deletion are stored sorted in |ordered_local_tombstones_| and will be
+      // added later.
+      continue;
+    }
+    TraverseAndAppend(child, ordered_entities);
+  }
 }
 
 void SyncedBookmarkTracker::UpdateUponCommitResponse(
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h
index 415c5e3..32d12cd 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -149,6 +149,17 @@
   std::size_t TrackedEntitiesCountForTest() const;
 
  private:
+  // Reorders |entities| that represents local non-deletions such that parent
+  // creation/update is before child creation/update. Returns the ordered list.
+  std::vector<const Entity*> ReorderUnsyncedEntitiesExceptDeletions(
+      const std::vector<const Entity*>& entities) const;
+
+  // Recursive method that starting from |node| appends all corresponding
+  // entities with updates in top-down order to |ordered_entities|.
+  void TraverseAndAppend(const bookmarks::BookmarkNode* node,
+                         std::vector<const SyncedBookmarkTracker::Entity*>*
+                             ordered_entities) const;
+
   // A map of sync server ids to sync entities. This should contain entries and
   // metadata for almost everything.
   std::map<std::string, std::unique_ptr<Entity>> sync_id_to_entities_map_;
diff --git a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
index 5fafc83..4db9e25 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -6,7 +6,10 @@
 
 #include "base/base64.h"
 #include "base/sha1.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
 #include "components/sync/base/time.h"
 #include "components/sync/base/unique_position.h"
 #include "components/sync/model/entity_data.h"
@@ -29,6 +32,15 @@
   return specifics;
 }
 
+std::unique_ptr<sync_pb::EntityMetadata> CreateEntityMetadata(
+    const std::string& server_id,
+    bool is_deleted) {
+  auto metadata = std::make_unique<sync_pb::EntityMetadata>();
+  metadata->set_server_id(server_id);
+  metadata->set_is_deleted(is_deleted);
+  return metadata;
+}
+
 TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) {
   SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
                                 std::make_unique<sync_pb::ModelTypeState>());
@@ -155,30 +167,17 @@
   bookmarks::BookmarkNode node0(/*id=*/0, kUrl);
   bookmarks::BookmarkNode node1(/*id=*/1, kUrl);
 
-  auto metadata0 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata0->set_server_id(kId0);
-
-  auto metadata1 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata1->set_server_id(kId1);
-
-  auto metadata2 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata2->set_server_id(kId2);
-  metadata2->set_is_deleted(true);
-
-  auto metadata3 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata3->set_server_id(kId3);
-  metadata3->set_is_deleted(true);
-
-  auto metadata4 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata4->set_server_id(kId4);
-  metadata4->set_is_deleted(true);
-
   std::vector<NodeMetadataPair> node_metadata_pairs;
-  node_metadata_pairs.emplace_back(&node0, std::move(metadata0));
-  node_metadata_pairs.emplace_back(&node1, std::move(metadata1));
-  node_metadata_pairs.emplace_back(nullptr, std::move(metadata2));
-  node_metadata_pairs.emplace_back(nullptr, std::move(metadata3));
-  node_metadata_pairs.emplace_back(nullptr, std::move(metadata4));
+  node_metadata_pairs.emplace_back(
+      &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      nullptr, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/true));
+  node_metadata_pairs.emplace_back(
+      nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true));
+  node_metadata_pairs.emplace_back(
+      nullptr, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/true));
 
   SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
                                 std::make_unique<sync_pb::ModelTypeState>());
@@ -216,27 +215,17 @@
   bookmarks::BookmarkNode node3(/*id=*/3, kUrl);
   bookmarks::BookmarkNode node4(/*id=*/4, kUrl);
 
-  auto metadata0 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata0->set_server_id(kId0);
-
-  auto metadata1 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata1->set_server_id(kId1);
-
-  auto metadata2 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata2->set_server_id(kId2);
-
-  auto metadata3 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata3->set_server_id(kId3);
-
-  auto metadata4 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata4->set_server_id(kId4);
-
   std::vector<NodeMetadataPair> node_metadata_pairs;
-  node_metadata_pairs.emplace_back(&node0, std::move(metadata0));
-  node_metadata_pairs.emplace_back(&node1, std::move(metadata1));
-  node_metadata_pairs.emplace_back(&node2, std::move(metadata2));
-  node_metadata_pairs.emplace_back(&node3, std::move(metadata3));
-  node_metadata_pairs.emplace_back(&node4, std::move(metadata4));
+  node_metadata_pairs.emplace_back(
+      &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      &node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      &node3, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      &node4, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/false));
 
   SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
                                 std::make_unique<sync_pb::ModelTypeState>());
@@ -263,6 +252,68 @@
       Eq(kId1));
 }
 
+TEST(SyncedBookmarkTrackerTest,
+     ShouldOrderParentUpdatesBeforeChildUpdatesAndDeletionsComeLast) {
+  const size_t kMaxEntries = 1000;
+
+  // Construct this structure:
+  // bookmark_bar
+  //  |- node0
+  //    |- node1
+  //      |- node2
+
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+  const bookmarks::BookmarkNode* node0 = bookmark_model->AddFolder(
+      /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0"));
+  const bookmarks::BookmarkNode* node1 = bookmark_model->AddFolder(
+      /*parent=*/node0, /*index=*/0, base::UTF8ToUTF16("node1"));
+  const bookmarks::BookmarkNode* node2 = bookmark_model->AddFolder(
+      /*parent=*/node1, /*index=*/0, base::UTF8ToUTF16("node2"));
+
+  // Server ids.
+  const std::string kId0 = "id0";
+  const std::string kId1 = "id1";
+  const std::string kId2 = "id2";
+  const std::string kId3 = "id3";
+
+  // Prepare the metadata with shuffled order.
+  std::vector<NodeMetadataPair> node_metadata_pairs;
+  node_metadata_pairs.emplace_back(
+      node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true));
+  node_metadata_pairs.emplace_back(
+      node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false));
+  node_metadata_pairs.emplace_back(
+      node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
+
+  SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
+                                std::make_unique<sync_pb::ModelTypeState>());
+
+  // Mark the entities that they have local changes. (in shuffled order just to
+  // verify the tracker doesn't simply maintain the order of updates similar to
+  // with deletions).
+  tracker.IncrementSequenceNumber(kId3);
+  tracker.IncrementSequenceNumber(kId1);
+  tracker.IncrementSequenceNumber(kId2);
+  tracker.IncrementSequenceNumber(kId0);
+
+  std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change =
+      tracker.GetEntitiesWithLocalChanges(kMaxEntries);
+
+  ASSERT_THAT(entities_with_local_change.size(), Eq(4U));
+  // Verify updates are in parent before child order node0 --> node1 --> node2.
+  EXPECT_THAT(entities_with_local_change[0]->metadata()->server_id(), Eq(kId0));
+  EXPECT_THAT(entities_with_local_change[1]->metadata()->server_id(), Eq(kId1));
+  EXPECT_THAT(entities_with_local_change[2]->metadata()->server_id(), Eq(kId2));
+  // Verify that deletion is the last entry.
+  EXPECT_THAT(entities_with_local_change[3]->metadata()->server_id(), Eq(kId3));
+}
+
 }  // namespace
 
 }  // namespace sync_bookmarks
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc
index 5fec0d0c..eb7036d0 100644
--- a/components/unified_consent/unified_consent_service.cc
+++ b/components/unified_consent/unified_consent_service.cc
@@ -90,13 +90,15 @@
 
 void UnifiedConsentService::OnPrimaryAccountCleared(
     const AccountInfo& account_info) {
-  // By design, signing out of Chrome automatically disables the user consent
-  // for making search and browsing better.
-  pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
-                            false);
   // When signing out, the unfied consent is revoked.
   pref_service_->SetBoolean(prefs::kUnifiedConsentGiven, false);
 
+  // By design, signing out of Chrome automatically disables off-by-default
+  // services.
+  pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
+                            false);
+  service_client_->SetSpellCheckEnabled(false);
+
   switch (GetMigrationState()) {
     case MigrationState::NOT_INITIALIZED:
       NOTREACHED();
@@ -152,11 +154,11 @@
   // Inform client to enable non-personalized services.
   service_client_->SetAlternateErrorPagesEnabled(true);
   service_client_->SetMetricsReportingEnabled(true);
-  service_client_->SetSafeBrowsingExtendedReportingEnabled(true);
   service_client_->SetSearchSuggestEnabled(true);
   service_client_->SetSafeBrowsingEnabled(true);
   service_client_->SetSafeBrowsingExtendedReportingEnabled(true);
   service_client_->SetNetworkPredictionEnabled(true);
+  service_client_->SetSpellCheckEnabled(true);
 }
 
 void UnifiedConsentService::SetSyncEverythingIfPossible(bool sync_everything) {
diff --git a/components/unified_consent/unified_consent_service_client.h b/components/unified_consent/unified_consent_service_client.h
index 6eaf95a..8b4a865 100644
--- a/components/unified_consent/unified_consent_service_client.h
+++ b/components/unified_consent/unified_consent_service_client.h
@@ -23,6 +23,8 @@
   virtual void SetSafeBrowsingExtendedReportingEnabled(bool enabled) = 0;
   // Enables/disables prediction of network actions.
   virtual void SetNetworkPredictionEnabled(bool enabled) = 0;
+  // Enables/disables spell check.
+  virtual void SetSpellCheckEnabled(bool enabled) = 0;
 };
 
 }  // namespace unified_consent
diff --git a/components/unified_consent/unified_consent_service_unittest.cc b/components/unified_consent/unified_consent_service_unittest.cc
index ae50e11b..be8948c 100644
--- a/components/unified_consent/unified_consent_service_unittest.cc
+++ b/components/unified_consent/unified_consent_service_unittest.cc
@@ -75,6 +75,9 @@
     void SetSearchSuggestEnabled(bool enabled) override {
       test_->search_suggest_enabled_ = enabled;
     }
+    void SetSpellCheckEnabled(bool enabled) override {
+      test_->spell_check_enabled_ = enabled;
+    }
 
    private:
     UnifiedConsentServiceTest* test_;
@@ -108,6 +111,7 @@
   bool safe_browsing_enabled_ = false;
   bool safe_browsing_extended_reporting_enabled_ = false;
   bool search_suggest_enabled_ = false;
+  bool spell_check_enabled_ = false;
 };
 
 TEST_F(UnifiedConsentServiceTest, DefaultValuesWhenSignedOut) {
@@ -135,6 +139,7 @@
   EXPECT_TRUE(safe_browsing_enabled_);
   EXPECT_TRUE(safe_browsing_extended_reporting_enabled_);
   EXPECT_TRUE(search_suggest_enabled_);
+  EXPECT_TRUE(spell_check_enabled_);
 
   // Disable unified consent does not disable any of the non-personalized
   // features.
@@ -148,6 +153,7 @@
   EXPECT_TRUE(safe_browsing_enabled_);
   EXPECT_TRUE(safe_browsing_extended_reporting_enabled_);
   EXPECT_TRUE(search_suggest_enabled_);
+  EXPECT_TRUE(spell_check_enabled_);
 }
 
 TEST_F(UnifiedConsentServiceTest, EnableUnfiedConsent_SyncNotActive) {
@@ -238,6 +244,7 @@
   EXPECT_TRUE(safe_browsing_enabled_);
   EXPECT_TRUE(safe_browsing_extended_reporting_enabled_);
   EXPECT_TRUE(search_suggest_enabled_);
+  EXPECT_TRUE(spell_check_enabled_);
 
   // Clearing primary account revokes unfied consent and a couple of other
   // non-personalized services.
@@ -245,6 +252,7 @@
   EXPECT_FALSE(pref_service_.GetBoolean(prefs::kUnifiedConsentGiven));
   EXPECT_FALSE(pref_service_.GetBoolean(
       prefs::kUrlKeyedAnonymizedDataCollectionEnabled));
+  EXPECT_FALSE(spell_check_enabled_);
 
   // Consent is not revoked for the following services.
   EXPECT_TRUE(alternate_error_pages_enabled_);
diff --git a/components/viz/client/hit_test_data_provider_draw_quad.cc b/components/viz/client/hit_test_data_provider_draw_quad.cc
index a935252..5d9947b8 100644
--- a/components/viz/client/hit_test_data_provider_draw_quad.cc
+++ b/components/viz/client/hit_test_data_provider_draw_quad.cc
@@ -41,9 +41,9 @@
         // Skip the quad if the FrameSinkId between fallback and primary is not
         // the same, because we don't know which FrameSinkId would be used to
         // draw this quad.
-        if (surface_quad->fallback_surface_id.has_value() &&
-            surface_quad->fallback_surface_id->frame_sink_id() !=
-                surface_quad->primary_surface_id.frame_sink_id()) {
+        if (surface_quad->surface_range.start() &&
+            surface_quad->surface_range.start()->frame_sink_id() !=
+                surface_quad->surface_range.end().frame_sink_id()) {
           continue;
         }
 
@@ -58,7 +58,7 @@
         hit_test_region_list->regions.emplace_back();
         HitTestRegion& hit_test_region = hit_test_region_list->regions.back();
         hit_test_region.frame_sink_id =
-            surface_quad->primary_surface_id.frame_sink_id();
+            surface_quad->surface_range.end().frame_sink_id();
         hit_test_region.flags = HitTestRegionFlags::kHitTestMouse |
                                 HitTestRegionFlags::kHitTestTouch |
                                 HitTestRegionFlags::kHitTestChildSurface;
diff --git a/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc b/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
index e67bbd4..0b6ba471 100644
--- a/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
+++ b/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
@@ -47,9 +47,10 @@
                        1, SkBlendMode::kSrcOver, 0);
 
   auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-  surface_quad->SetNew(pass->shared_quad_state_list.back(), child_rect,
-                       child_rect, child_surface_id, fallback_child_surface_id,
-                       SK_ColorWHITE, false);
+  surface_quad->SetNew(
+      pass->shared_quad_state_list.back(), child_rect, child_rect,
+      SurfaceRange(fallback_child_surface_id, child_surface_id), SK_ColorWHITE,
+      false);
 
   return pass;
 }
diff --git a/components/viz/common/quads/draw_quad_unittest.cc b/components/viz/common/quads/draw_quad_unittest.cc
index 479a1b8..82b9c82 100644
--- a/components/viz/common/quads/draw_quad_unittest.cc
+++ b/components/viz/common/quads/draw_quad_unittest.cc
@@ -283,19 +283,21 @@
       LocalSurfaceId(5678, base::UnguessableToken::Create()));
   CREATE_SHARED_STATE();
 
-  CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect, primary_surface_id,
-                  fallback_surface_id, SK_ColorWHITE, true);
+  CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect,
+                  SurfaceRange(fallback_surface_id, primary_surface_id),
+                  SK_ColorWHITE, true);
   EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
-  EXPECT_EQ(primary_surface_id, copy_quad->primary_surface_id);
-  EXPECT_EQ(fallback_surface_id, copy_quad->fallback_surface_id);
+  EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
+  EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
   EXPECT_TRUE(copy_quad->stretch_content_to_fill_bounds);
 
-  CREATE_QUAD_ALL(SurfaceDrawQuad, primary_surface_id, fallback_surface_id,
+  CREATE_QUAD_ALL(SurfaceDrawQuad,
+                  SurfaceRange(fallback_surface_id, primary_surface_id),
                   SK_ColorWHITE, false);
   EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
-  EXPECT_EQ(primary_surface_id, copy_quad->primary_surface_id);
-  EXPECT_EQ(fallback_surface_id, copy_quad->fallback_surface_id);
+  EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
+  EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
   EXPECT_FALSE(copy_quad->stretch_content_to_fill_bounds);
 }
 
@@ -573,8 +575,9 @@
                        LocalSurfaceId(4321, base::UnguessableToken::Create()));
 
   CREATE_SHARED_STATE();
-  CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect, surface_id, base::nullopt,
-                  SK_ColorWHITE, false);
+  CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect,
+                  SurfaceRange(base::nullopt, surface_id), SK_ColorWHITE,
+                  false);
   EXPECT_EQ(0, IterateAndCount(quad_new));
 }
 
diff --git a/components/viz/common/quads/surface_draw_quad.cc b/components/viz/common/quads/surface_draw_quad.cc
index 4489167..3edad1aa 100644
--- a/components/viz/common/quads/surface_draw_quad.cc
+++ b/components/viz/common/quads/surface_draw_quad.cc
@@ -20,36 +20,30 @@
 SurfaceDrawQuad& SurfaceDrawQuad::operator=(const SurfaceDrawQuad& other) =
     default;
 
-void SurfaceDrawQuad::SetNew(
-    const SharedQuadState* shared_quad_state,
-    const gfx::Rect& rect,
-    const gfx::Rect& visible_rect,
-    const SurfaceId& primary_surface_id,
-    const base::Optional<SurfaceId>& fallback_surface_id,
-    SkColor default_background_color,
-    bool stretch_content_to_fill_bounds) {
+void SurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
+                             const gfx::Rect& rect,
+                             const gfx::Rect& visible_rect,
+                             const SurfaceRange& surface_range,
+                             SkColor default_background_color,
+                             bool stretch_content_to_fill_bounds) {
   bool needs_blending = true;
   DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
                    visible_rect, needs_blending);
-  this->primary_surface_id = primary_surface_id;
-  this->fallback_surface_id = fallback_surface_id;
+  this->surface_range = surface_range;
   this->default_background_color = default_background_color;
   this->stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
 }
 
-void SurfaceDrawQuad::SetAll(
-    const SharedQuadState* shared_quad_state,
-    const gfx::Rect& rect,
-    const gfx::Rect& visible_rect,
-    bool needs_blending,
-    const SurfaceId& primary_surface_id,
-    const base::Optional<SurfaceId>& fallback_surface_id,
-    SkColor default_background_color,
-    bool stretch_content_to_fill_bounds) {
+void SurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
+                             const gfx::Rect& rect,
+                             const gfx::Rect& visible_rect,
+                             bool needs_blending,
+                             const SurfaceRange& surface_range,
+                             SkColor default_background_color,
+                             bool stretch_content_to_fill_bounds) {
   DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
                    visible_rect, needs_blending);
-  this->primary_surface_id = primary_surface_id;
-  this->fallback_surface_id = fallback_surface_id;
+  this->surface_range = surface_range;
   this->default_background_color = default_background_color;
   this->stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
 }
@@ -60,9 +54,7 @@
 }
 
 void SurfaceDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
-  value->SetString("primary_surface_id", primary_surface_id.ToString());
-  if (fallback_surface_id.has_value())
-    value->SetString("fallback_surface_id", fallback_surface_id->ToString());
+  value->SetString("surface_range", surface_range.ToString());
 }
 
 }  // namespace viz
diff --git a/components/viz/common/quads/surface_draw_quad.h b/components/viz/common/quads/surface_draw_quad.h
index c3ee516..d63abc1 100644
--- a/components/viz/common/quads/surface_draw_quad.h
+++ b/components/viz/common/quads/surface_draw_quad.h
@@ -9,7 +9,7 @@
 
 #include "base/optional.h"
 #include "components/viz/common/quads/draw_quad.h"
-#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_range.h"
 #include "components/viz/common/viz_common_export.h"
 #include "third_party/skia/include/core/SkColor.h"
 
@@ -26,8 +26,7 @@
   void SetNew(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
               const gfx::Rect& visible_rect,
-              const SurfaceId& primary_surface_id,
-              const base::Optional<SurfaceId>& fallback_surface_id,
+              const SurfaceRange& surface_range,
               SkColor default_background_color,
               bool stretch_content_to_fill_bounds);
 
@@ -35,13 +34,11 @@
               const gfx::Rect& rect,
               const gfx::Rect& visible_rect,
               bool needs_blending,
-              const SurfaceId& primary_surface_id,
-              const base::Optional<SurfaceId>& fallback_surface_id,
+              const SurfaceRange& surface_range,
               SkColor default_background_color,
               bool stretch_content_to_fill_bounds);
 
-  SurfaceId primary_surface_id;
-  base::Optional<SurfaceId> fallback_surface_id;
+  SurfaceRange surface_range;
   SkColor default_background_color = SK_ColorWHITE;
   bool stretch_content_to_fill_bounds = false;
 
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index 327e77f8..deacc82 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -3277,9 +3277,8 @@
     auto* quad2 = pass->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
     quad2->SetNew(shared_quad_state2, rect2 /* rect */,
                   rect2 /* visible_rect */,
-                  sub_surface_id /* primary_surface_id */,
-                  base::Optional<SurfaceId>() /* fallback_surface_id */,
-                  SK_ColorBLACK, false /* stretch_content_to_fill_bounds */);
+                  SurfaceRange(base::nullopt, sub_surface_id), SK_ColorBLACK,
+                  false /* stretch_content_to_fill_bounds */);
 
     pass_list.push_back(std::move(pass));
     SubmitCompositorFrame(&pass_list, local_surface_id);
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 11aa65e..60b32ff60 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -24,6 +24,7 @@
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 #include "components/viz/common/quads/surface_draw_quad.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/surfaces/surface_range.h"
 #include "components/viz/service/display/display_resource_provider.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_client.h"
@@ -197,7 +198,7 @@
     bool ignore_undamaged,
     gfx::Rect* damage_rect_in_quad_space,
     bool* damage_rect_in_quad_space_valid) {
-  SurfaceId primary_surface_id = surface_quad->primary_surface_id;
+  SurfaceId primary_surface_id = surface_quad->surface_range.end();
   Surface* primary_surface = manager_->GetSurfaceForId(primary_surface_id);
   if (primary_surface && primary_surface->HasActiveFrame()) {
     EmitSurfaceContent(primary_surface, parent_device_scale_factor,
@@ -211,19 +212,19 @@
 
   // If there's no fallback surface ID provided, then simply emit a
   // SolidColorDrawQuad with the provided default background color.
-  if (!surface_quad->fallback_surface_id) {
+  if (!surface_quad->surface_range.start()) {
     EmitDefaultBackgroundColorQuad(surface_quad, target_transform, clip_rect,
                                    dest_pass);
     return;
   }
 
   Surface* fallback_surface = manager_->GetLatestInFlightSurface(
-      primary_surface_id, *surface_quad->fallback_surface_id);
+      primary_surface_id, *surface_quad->surface_range.start());
 
   // If the fallback is specified and missing then that's an error. Report the
   // error to console, and log the UMA.
   if (!fallback_surface || !fallback_surface->HasActiveFrame()) {
-    ReportMissingFallbackSurface(*surface_quad->fallback_surface_id,
+    ReportMissingFallbackSurface(*surface_quad->surface_range.start(),
                                  fallback_surface);
     EmitDefaultBackgroundColorQuad(surface_quad, target_transform, clip_rect,
                                    dest_pass);
@@ -477,8 +478,8 @@
   // If a fallback surface is specified but unavaialble then pick a very bright
   // and obvious color for the SolidColorDrawQuad so developers notice there's
   // an error when debugging.
-  if (surface_quad->fallback_surface_id.has_value() &&
-      surface_quad->fallback_surface_id->is_valid()) {
+  if (surface_quad->surface_range.start() &&
+      surface_quad->surface_range.start()->is_valid()) {
     background_color = SK_ColorMAGENTA;
   }
 #endif
@@ -679,7 +680,7 @@
       // current data.
       last_copied_source_shared_quad_state = nullptr;
 
-      if (!surface_quad->primary_surface_id.is_valid())
+      if (!surface_quad->surface_range.end().is_valid())
         continue;
 
       HandleSurfaceQuad(surface_quad, parent_device_scale_factor,
@@ -876,23 +877,20 @@
     render_pass_dependencies_[parent_pass_id].insert(remapped_pass_id);
 
   struct SurfaceInfo {
-    SurfaceInfo(const SurfaceId& primary_id,
-                const base::Optional<SurfaceId>& fallback_id,
+    SurfaceInfo(const SurfaceRange& surface_range,
                 bool has_moved_pixels,
                 RenderPassId parent_pass_id,
                 const gfx::Transform& target_to_surface_transform,
                 const gfx::Rect& quad_rect,
                 bool stretch_content_to_fill_bounds)
-        : primary_id(primary_id),
-          fallback_id(fallback_id),
+        : surface_range(surface_range),
           has_moved_pixels(has_moved_pixels),
           parent_pass_id(parent_pass_id),
           target_to_surface_transform(target_to_surface_transform),
           quad_rect(quad_rect),
           stretch_content_to_fill_bounds(stretch_content_to_fill_bounds) {}
 
-    SurfaceId primary_id;
-    base::Optional<SurfaceId> fallback_id;
+    SurfaceRange surface_range;
     bool has_moved_pixels;
     RenderPassId parent_pass_id;
     gfx::Transform target_to_surface_transform;
@@ -937,9 +935,9 @@
             render_pass->transform_to_root_target,
             surface_quad->shared_quad_state->quad_to_target_transform);
         child_surfaces.emplace_back(
-            surface_quad->primary_surface_id, surface_quad->fallback_surface_id,
-            in_moved_pixel_pass, remapped_pass_id, target_to_surface_transform,
-            surface_quad->rect, surface_quad->stretch_content_to_fill_bounds);
+            surface_quad->surface_range, in_moved_pixel_pass, remapped_pass_id,
+            target_to_surface_transform, surface_quad->rect,
+            surface_quad->stretch_content_to_fill_bounds);
       } else if (quad->material == DrawQuad::RENDER_PASS) {
         const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
         if (in_moved_pixel_pass) {
@@ -991,32 +989,39 @@
       // are provided and they have the same FrameSinkId and embed token,
       // otherwise the only Surface other than fallback that can be shown is the
       // primary.
-      if (!surface_info.fallback_id ||
-          surface_info.fallback_id->frame_sink_id() !=
-              surface_info.primary_id.frame_sink_id() ||
-          surface_info.fallback_id->local_surface_id().embed_token() !=
-              surface_info.primary_id.local_surface_id().embed_token()) {
-        damage_ranges_[surface_info.primary_id.frame_sink_id()] =
-            std::make_pair(surface_info.primary_id.local_surface_id(),
-                           surface_info.primary_id.local_surface_id());
-      } else if (surface_info.fallback_id != surface_info.primary_id) {
-        damage_ranges_[surface_info.primary_id.frame_sink_id()] =
-            std::make_pair(surface_info.fallback_id->local_surface_id(),
-                           surface_info.primary_id.local_surface_id());
+      if (!surface_info.surface_range.start() ||
+          surface_info.surface_range.start()->frame_sink_id() !=
+              surface_info.surface_range.end().frame_sink_id() ||
+          surface_info.surface_range.start()
+                  ->local_surface_id()
+                  .embed_token() != surface_info.surface_range.end()
+                                        .local_surface_id()
+                                        .embed_token()) {
+        damage_ranges_[surface_info.surface_range.end().frame_sink_id()] =
+            std::make_pair(surface_info.surface_range.end().local_surface_id(),
+                           surface_info.surface_range.end().local_surface_id());
+      } else if (surface_info.surface_range.start() !=
+                 surface_info.surface_range.end()) {
+        damage_ranges_[surface_info.surface_range.end().frame_sink_id()] =
+            std::make_pair(
+                surface_info.surface_range.start()->local_surface_id(),
+                surface_info.surface_range.end().local_surface_id());
       }
     }
-    Surface* child_surface = manager_->GetSurfaceForId(surface_info.primary_id);
+    Surface* child_surface =
+        manager_->GetSurfaceForId(surface_info.surface_range.end());
     gfx::Rect surface_damage;
     if (!child_surface || !child_surface->HasActiveFrame()) {
       // If the primary surface is not available then we assume the damage is
       // the full size of the SurfaceDrawQuad because we might need to introduce
       // gutter.
       surface_damage = surface_info.quad_rect;
-      if (surface_info.fallback_id) {
+      if (surface_info.surface_range.start()) {
         // TODO(fsamuel): Consider caching this value somewhere so that
         // HandleSurfaceQuad doesn't need to call it again.
         Surface* fallback_surface = manager_->GetLatestInFlightSurface(
-            surface_info.primary_id, *surface_info.fallback_id);
+            surface_info.surface_range.end(),
+            *surface_info.surface_range.start());
         if (fallback_surface && fallback_surface->HasActiveFrame())
           child_surface = fallback_surface;
       }
diff --git a/components/viz/service/display/surface_aggregator_perftest.cc b/components/viz/service/display/surface_aggregator_perftest.cc
index 4b815d1..9aa1b37 100644
--- a/components/viz/service/display/surface_aggregator_perftest.cc
+++ b/components/viz/service/display/surface_aggregator_perftest.cc
@@ -93,8 +93,10 @@
         auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
         surface_quad->SetNew(
             sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
-            SurfaceId(FrameSinkId(1, i), LocalSurfaceId(i, kArbitraryToken)),
-            base::nullopt, SK_ColorWHITE, false);
+            SurfaceRange(base::nullopt,
+                         SurfaceId(FrameSinkId(1, i),
+                                   LocalSurfaceId(i, kArbitraryToken))),
+            SK_ColorWHITE, false);
       }
 
       frame_builder.AddRenderPass(std::move(pass));
@@ -115,9 +117,11 @@
       auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
       surface_quad->SetNew(
           sqs, gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 100, 100),
-          SurfaceId(FrameSinkId(1, num_surfaces),
-                    LocalSurfaceId(num_surfaces, kArbitraryToken)),
-          base::nullopt, SK_ColorWHITE, false);
+          SurfaceRange(
+              base::nullopt,
+              SurfaceId(FrameSinkId(1, num_surfaces),
+                        LocalSurfaceId(num_surfaces, kArbitraryToken))),
+          SK_ColorWHITE, false);
 
       pass->output_rect = gfx::Rect(0, 0, 100, 100);
 
diff --git a/components/viz/service/display/surface_aggregator_pixeltest.cc b/components/viz/service/display/surface_aggregator_pixeltest.cc
index 493ba49..46aa050 100644
--- a/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -138,7 +138,8 @@
     auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
     surface_quad->SetNew(pass->shared_quad_state_list.back(),
                          gfx::Rect(child_size), gfx::Rect(child_size),
-                         child_surface_id, base::nullopt, SK_ColorWHITE, false);
+                         SurfaceRange(base::nullopt, child_surface_id),
+                         SK_ColorWHITE, false);
 
     auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
     bool force_anti_aliasing_off = false;
@@ -224,8 +225,8 @@
     auto* left_surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
     left_surface_quad->SetNew(pass->shared_quad_state_list.back(),
                               gfx::Rect(child_size), gfx::Rect(child_size),
-                              left_child_id, base::nullopt, SK_ColorWHITE,
-                              false);
+                              SurfaceRange(base::nullopt, left_child_id),
+                              SK_ColorWHITE, false);
 
     surface_transform.Translate(100, 0);
     CreateAndAppendTestSharedQuadState(pass.get(), surface_transform,
@@ -234,8 +235,8 @@
     auto* right_surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
     right_surface_quad->SetNew(pass->shared_quad_state_list.back(),
                                gfx::Rect(child_size), gfx::Rect(child_size),
-                               right_child_id, base::nullopt, SK_ColorWHITE,
-                               false);
+                               SurfaceRange(base::nullopt, right_child_id),
+                               SK_ColorWHITE, false);
 
     auto root_frame =
         CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index a6ebb85..ebbcce2 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -333,10 +333,11 @@
         pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
     surface_quad->SetNew(
         pass->shared_quad_state_list.back(), primary_surface_rect,
-        primary_surface_rect, primary_surface_id,
-        fallback_surface_id.is_valid()
-            ? base::Optional<SurfaceId>(fallback_surface_id)
-            : base::nullopt,
+        primary_surface_rect,
+        SurfaceRange(fallback_surface_id.is_valid()
+                         ? base::Optional<SurfaceId>(fallback_surface_id)
+                         : base::nullopt,
+                     primary_surface_id),
         default_background_color, stretch_content_to_fill_bounds);
   }
 
@@ -1903,8 +1904,8 @@
       child_one_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   grandchild_surface_quad->SetNew(
       child_one_pass->shared_quad_state_list.back(), gfx::Rect(SurfaceSize()),
-      gfx::Rect(SurfaceSize()), grandchild_surface_id, base::nullopt,
-      SK_ColorWHITE, false);
+      gfx::Rect(SurfaceSize()),
+      SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE, false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
                                  blend_modes[3]);
   QueuePassAsFrame(std::move(child_one_pass), child_one_local_surface_id,
@@ -1930,18 +1931,18 @@
                                  blend_modes[0]);
   auto* child_one_surface_quad =
       root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-  child_one_surface_quad->SetNew(root_pass->shared_quad_state_list.back(),
-                                 gfx::Rect(SurfaceSize()),
-                                 gfx::Rect(SurfaceSize()), child_one_surface_id,
-                                 base::nullopt, SK_ColorWHITE, false);
+  child_one_surface_quad->SetNew(
+      root_pass->shared_quad_state_list.back(), gfx::Rect(SurfaceSize()),
+      gfx::Rect(SurfaceSize()),
+      SurfaceRange(base::nullopt, child_one_surface_id), SK_ColorWHITE, false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(),
                                  blend_modes[4]);
   auto* child_two_surface_quad =
       root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-  child_two_surface_quad->SetNew(root_pass->shared_quad_state_list.back(),
-                                 gfx::Rect(SurfaceSize()),
-                                 gfx::Rect(SurfaceSize()), child_two_surface_id,
-                                 base::nullopt, SK_ColorWHITE, false);
+  child_two_surface_quad->SetNew(
+      root_pass->shared_quad_state_list.back(), gfx::Rect(SurfaceSize()),
+      gfx::Rect(SurfaceSize()),
+      SurfaceRange(base::nullopt, child_two_surface_id), SK_ColorWHITE, false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(),
                                  blend_modes[6]);
 
@@ -3212,7 +3213,8 @@
   if (child_id.is_valid()) {
     auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
     surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
-                         child_id, base::nullopt, SK_ColorWHITE, false);
+                         SurfaceRange(base::nullopt, child_id), SK_ColorWHITE,
+                         false);
   }
 
   for (size_t i = 0u; i < num_resource_ids; ++i) {
@@ -3480,7 +3482,8 @@
     auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
 
     surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
-                         surface1_id, base::nullopt, SK_ColorWHITE, false);
+                         SurfaceRange(base::nullopt, surface1_id),
+                         SK_ColorWHITE, false);
     pass->copy_requests.push_back(CopyOutputRequest::CreateStubForTesting());
 
     CompositorFrame frame =
diff --git a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
index f5578eef3..a555d9a9 100644
--- a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
+++ b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
@@ -110,9 +110,9 @@
         // Skip the quad if the FrameSinkId between fallback and primary is not
         // the same, because we don't know which FrameSinkId would be used to
         // draw this quad.
-        if (surface_quad->fallback_surface_id.has_value() &&
-            surface_quad->fallback_surface_id->frame_sink_id() !=
-                surface_quad->primary_surface_id.frame_sink_id()) {
+        if (surface_quad->surface_range.start() &&
+            surface_quad->surface_range.start()->frame_sink_id() !=
+                surface_quad->surface_range.end().frame_sink_id()) {
           continue;
         }
 
@@ -127,7 +127,7 @@
         hit_test_region_list.regions.emplace_back();
         HitTestRegion* hit_test_region = &hit_test_region_list.regions.back();
         hit_test_region->frame_sink_id =
-            surface_quad->primary_surface_id.frame_sink_id();
+            surface_quad->surface_range.end().frame_sink_id();
         hit_test_region->flags = HitTestRegionFlags::kHitTestMouse |
                                  HitTestRegionFlags::kHitTestTouch |
                                  HitTestRegionFlags::kHitTestChildSurface;
diff --git a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
index d807033..c4c5277 100644
--- a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
+++ b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
@@ -210,9 +210,8 @@
       0.5f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
   auto* quad2 = pass2->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
   quad2->SetNew(shared_quad_state2, rect2 /* rect */, rect2 /* visible_rect */,
-                child_surface_id /* primary_surface_id */,
-                base::Optional<SurfaceId>() /* fallback_surface_id */,
-                SK_ColorBLACK, false /* stretch_content_to_fill_bounds */);
+                SurfaceRange(base::nullopt, child_surface_id), SK_ColorBLACK,
+                false /* stretch_content_to_fill_bounds */);
   pass_list.push_back(std::move(pass2));
 
   auto pass3 = RenderPass::Create();
@@ -252,9 +251,8 @@
       0.5f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
   auto* quad4 = pass4->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
   quad4->SetNew(shared_quad_state4, rect4 /* rect */, rect4 /* visible_rect */,
-                child_surface_id4 /* primary_surface_id */,
-                base::Optional<SurfaceId>() /* fallback_surface_id */,
-                SK_ColorBLACK, false /* stretch_content_to_fill_bounds */);
+                SurfaceRange(base::nullopt, child_surface_id4), SK_ColorBLACK,
+                false /* stretch_content_to_fill_bounds */);
   pass_list.push_back(std::move(pass4));
 
   const auto* hit_test_region_list1 =
diff --git a/components/viz/service/frame_sinks/video_detector_unittest.cc b/components/viz/service/frame_sinks/video_detector_unittest.cc
index d7f76b72..977931a7 100644
--- a/components/viz/service/frame_sinks/video_detector_unittest.cc
+++ b/components/viz/service/frame_sinks/video_detector_unittest.cc
@@ -133,10 +133,10 @@
     for (CompositorFrameSinkSupport* frame_sink : embedded_clients_) {
       SurfaceDrawQuad* quad =
           render_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-      quad->SetNew(shared_quad_state, gfx::Rect(0, 0, 10, 10),
-                   gfx::Rect(0, 0, 5, 5),
-                   frame_sink->last_activated_surface_id(), base::nullopt,
-                   SK_ColorMAGENTA, false);
+      quad->SetNew(
+          shared_quad_state, gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 5, 5),
+          SurfaceRange(base::nullopt, frame_sink->last_activated_surface_id()),
+          SK_ColorMAGENTA, false);
     }
     root_frame_sink_->SubmitCompositorFrame(
         root_frame_sink_->last_activated_local_surface_id(), std::move(frame));
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc
index 2475623..d8914a20 100644
--- a/components/viz/service/main/viz_main_impl.cc
+++ b/components/viz/service/main/viz_main_impl.cc
@@ -40,7 +40,6 @@
 
 #if defined(USE_OZONE)
 #include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/ozone_switches.h"
 #endif
 
 namespace {
@@ -137,10 +136,6 @@
     gpu_init_ = std::make_unique<gpu::GpuInit>();
     gpu_init_->set_sandbox_helper(this);
 
-#if defined(USE_OZONE)
-    command_line->AppendSwitch(switches::kEnableDrmMojo);
-#endif
-
     // TODO(crbug.com/609317): Use InitializeAndStartSandbox() when gpu-mus is
     // split into a separate process.
     gpu_init_->InitializeInProcess(command_line, gpu_preferences);
diff --git a/components/viz/service/surfaces/surface_hittest.cc b/components/viz/service/surfaces/surface_hittest.cc
index 14c50d3..83d97e9 100644
--- a/components/viz/service/surfaces/surface_hittest.cc
+++ b/components/viz/service/surfaces/surface_hittest.cc
@@ -147,7 +147,7 @@
 
         gfx::Transform transform_to_child_space;
         if (GetTargetSurfaceAtPointInternal(
-                surface_quad->primary_surface_id, 0, point_in_quad_space,
+                surface_quad->surface_range.end(), 0, point_in_quad_space,
                 referenced_passes, out_surface_id, &transform_to_child_space,
                 out_query_renderer)) {
           *out_transform = transform_to_child_space * target_to_quad_transform *
@@ -155,7 +155,7 @@
           return true;
         } else if (delegate_ && delegate_->AcceptHitTarget(
                                     surface_quad, point_in_quad_space)) {
-          *out_surface_id = surface_quad->primary_surface_id;
+          *out_surface_id = surface_quad->surface_range.end();
           *out_transform = transform_to_child_space * target_to_quad_transform *
                            transform_from_root_target;
           return true;
@@ -251,7 +251,7 @@
       }
 
       const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
-      if (surface_quad->primary_surface_id == target_surface_id) {
+      if (surface_quad->surface_range.end() == target_surface_id) {
         *out_transform = target_to_quad_transform * transform_from_root_target;
         return true;
       }
@@ -260,7 +260,7 @@
       // find the |target_surface_id| there.
       gfx::Transform transform_to_child_space;
       if (GetTransformToTargetSurfaceInternal(
-              surface_quad->primary_surface_id, target_surface_id, 0,
+              surface_quad->surface_range.end(), target_surface_id, 0,
               referenced_passes, &transform_to_child_space)) {
         *out_transform = transform_to_child_space * target_to_quad_transform *
                          transform_from_root_target;
diff --git a/components/viz/test/surface_hittest_test_helpers.cc b/components/viz/test/surface_hittest_test_helpers.cc
index 8db686f..8f2d32b 100644
--- a/components/viz/test/surface_hittest_test_helpers.cc
+++ b/components/viz/test/surface_hittest_test_helpers.cc
@@ -56,8 +56,8 @@
   SurfaceDrawQuad* surface_quad =
       pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   surface_quad->SetNew(pass->shared_quad_state_list.back(), quad_rect,
-                       quad_rect, surface_id, SurfaceId(), SK_ColorWHITE,
-                       false);
+                       quad_rect, SurfaceRange(base::nullopt, surface_id),
+                       SK_ColorWHITE, false);
 }
 
 void CreateRenderPass(int render_pass_id,
@@ -99,10 +99,10 @@
 bool TestSurfaceHittestDelegate::RejectHitTarget(
     const SurfaceDrawQuad* surface_quad,
     const gfx::Point& point_in_quad_space) {
-  if (!insets_for_reject_.count(surface_quad->primary_surface_id))
+  if (!insets_for_reject_.count(surface_quad->surface_range.end()))
     return false;
   gfx::Rect bounds(surface_quad->rect);
-  bounds.Inset(insets_for_reject_[surface_quad->primary_surface_id]);
+  bounds.Inset(insets_for_reject_[surface_quad->surface_range.end()]);
   // If the point provided falls outside the inset, then we skip this surface.
   if (!bounds.Contains(point_in_quad_space)) {
     if (surface_quad->rect.Contains(point_in_quad_space))
@@ -115,10 +115,10 @@
 bool TestSurfaceHittestDelegate::AcceptHitTarget(
     const SurfaceDrawQuad* surface_quad,
     const gfx::Point& point_in_quad_space) {
-  if (!insets_for_accept_.count(surface_quad->primary_surface_id))
+  if (!insets_for_accept_.count(surface_quad->surface_range.end()))
     return false;
   gfx::Rect bounds(surface_quad->rect);
-  bounds.Inset(insets_for_accept_[surface_quad->primary_surface_id]);
+  bounds.Inset(insets_for_accept_[surface_quad->surface_range.end()]);
   // If the point provided falls outside the inset, then we accept this surface.
   if (!bounds.Contains(point_in_quad_space)) {
     ++accept_target_overrides_;
diff --git a/components/webdata_services/BUILD.gn b/components/webdata_services/BUILD.gn
index c13032c..6efcf74 100644
--- a/components/webdata_services/BUILD.gn
+++ b/components/webdata_services/BUILD.gn
@@ -13,6 +13,7 @@
   deps = [
     "//base",
     "//components/autofill/core/browser",
+    "//components/autofill/core/common",
     "//components/keyed_service/core",
     "//components/password_manager/core/browser",
     "//components/search_engines",
diff --git a/components/webdata_services/DEPS b/components/webdata_services/DEPS
index 25eff77..5f5c911 100644
--- a/components/webdata_services/DEPS
+++ b/components/webdata_services/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
-  "+components/autofill/core/browser/webdata",
+  "+components/autofill/core",
   "+components/keyed_service/core",
   "+components/password_manager/core/browser/webdata",
   "+components/payments/content",
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc
index bc66797..8bcd4d3 100644
--- a/components/webdata_services/web_data_service_wrapper.cc
+++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/password_manager/core/browser/webdata/logins_table.h"
 #include "components/search_engines/keyword_table.h"
 #include "components/search_engines/keyword_web_data_service.h"
@@ -44,7 +45,7 @@
 // TODO(jkrcal): Rename this function when the last webdata sync type get
 // converted to USS, e.g. to InitSyncBridgesOnDBSequence(). Check also other
 // related functions.
-void InitSyncableServicesOnDBSequence(
+void InitSyncableProfileServicesOnDBSequence(
     scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
     const syncer::SyncableService::StartSyncFlare& sync_flare,
     const scoped_refptr<autofill::AutofillWebDataService>& autofill_web_data,
@@ -68,12 +69,22 @@
         autofill_web_data.get())
         ->InjectStartSyncFlare(sync_flare);
   }
+}
 
+void InitSyncableAccountServicesOnDBSequence(
+    scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
+    const syncer::SyncableService::StartSyncFlare& sync_flare,
+    const scoped_refptr<autofill::AutofillWebDataService>& autofill_web_data,
+    const base::FilePath& context_path,
+    const std::string& app_locale,
+    autofill::AutofillWebDataBackend* autofill_backend) {
+  DCHECK(db_task_runner->RunsTasksInCurrentSequence());
   autofill::AutofillWalletSyncableService::CreateForWebDataServiceAndBackend(
       autofill_web_data.get(), autofill_backend, app_locale);
   autofill::AutofillWalletMetadataSyncableService::
       CreateForWebDataServiceAndBackend(autofill_web_data.get(),
                                         autofill_backend, app_locale);
+
   autofill::AutofillWalletSyncableService::FromWebDataService(
       autofill_web_data.get())
       ->InjectStartSyncFlare(sync_flare);
@@ -145,27 +156,40 @@
       ui_task_runner);
 #endif
 
-  profile_autofill_web_data_->GetAutofillBackend(
-      base::Bind(&InitSyncableServicesOnDBSequence, db_task_runner, flare,
-                 profile_autofill_web_data_, context_path, application_locale));
+  profile_autofill_web_data_->GetAutofillBackend(base::Bind(
+      &InitSyncableProfileServicesOnDBSequence, db_task_runner, flare,
+      profile_autofill_web_data_, context_path, application_locale));
 
-  account_database_ =
-      new WebDatabaseService(base::FilePath(WebDatabase::kInMemoryPath),
-                             ui_task_runner, db_task_runner);
-  account_database_->AddTable(std::make_unique<autofill::AutofillTable>());
-  account_database_->LoadDatabase();
+  if (base::FeatureList::IsEnabled(
+          autofill::features::kAutofillEnableAccountWalletStorage)) {
+    account_database_ =
+        new WebDatabaseService(base::FilePath(WebDatabase::kInMemoryPath),
+                               ui_task_runner, db_task_runner);
+    account_database_->AddTable(std::make_unique<autofill::AutofillTable>());
+    account_database_->LoadDatabase();
 
-  account_autofill_web_data_ = new autofill::AutofillWebDataService(
-      account_database_, ui_task_runner, db_task_runner,
-      base::Bind(show_error_callback, ERROR_LOADING_ACCOUNT_AUTOFILL));
-  account_autofill_web_data_->Init();
+    account_autofill_web_data_ = new autofill::AutofillWebDataService(
+        account_database_, ui_task_runner, db_task_runner,
+        base::Bind(show_error_callback, ERROR_LOADING_ACCOUNT_AUTOFILL));
+    account_autofill_web_data_->Init();
+    account_autofill_web_data_->GetAutofillBackend(base::Bind(
+        &InitSyncableAccountServicesOnDBSequence, db_task_runner, flare,
+        account_autofill_web_data_, context_path, application_locale));
+
+  } else {
+    account_autofill_web_data_ = nullptr;
+    profile_autofill_web_data_->GetAutofillBackend(base::Bind(
+        &InitSyncableAccountServicesOnDBSequence, db_task_runner, flare,
+        profile_autofill_web_data_, context_path, application_locale));
+  }
 }
 
 WebDataServiceWrapper::~WebDataServiceWrapper() {}
 
 void WebDataServiceWrapper::Shutdown() {
   profile_autofill_web_data_->ShutdownOnUISequence();
-  account_autofill_web_data_->ShutdownOnUISequence();
+  if (account_autofill_web_data_)
+    account_autofill_web_data_->ShutdownOnUISequence();
   keyword_web_data_->ShutdownOnUISequence();
   token_web_data_->ShutdownOnUISequence();
 
@@ -178,7 +202,8 @@
 #endif
 
   profile_database_->ShutdownDatabase();
-  account_database_->ShutdownDatabase();
+  if (account_database_)
+    account_database_->ShutdownDatabase();
 }
 
 scoped_refptr<autofill::AutofillWebDataService>
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index be1a8e4..58882960 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -69,6 +69,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/web_mouse_event.h"
 #include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -2994,6 +2995,81 @@
   ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
 }
 
+// A download initiated by the user via alt-click on a link should download,
+// even when redirected cross origin.
+//
+// Alt-click doesn't make sense on Android, and download a HTML file results
+// in an intent, so just skip.
+#if !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+                       DownloadAttributeSameOriginRedirectAltClick) {
+  net::EmbeddedTestServer origin_one;
+  net::EmbeddedTestServer origin_two;
+  ASSERT_TRUE(origin_one.InitializeAndListen());
+  ASSERT_TRUE(origin_two.InitializeAndListen());
+
+  // The download-attribute.html page contains an anchor element whose href is
+  // set to the value of the query parameter (specified as |target| in the URL
+  // below). The suggested filename for the anchor is 'suggested-filename'. We
+  // will later send a "real" click to the anchor, triggering a download of the
+  // target URL.
+  //
+  // We construct two test servers; origin_one and origin_two. Once started, the
+  // server URLs will differ by the port number. Therefore they will be in
+  // different origins.
+  GURL download_url = origin_one.GetURL("/ping");
+  GURL referrer_url = origin_one.GetURL(
+      std::string("/download-attribute.html?noclick=") + download_url.spec());
+  origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
+
+  // <origin_one>/download-attribute.html initiates a download of
+  // <origin_one>/ping, which redirects to <origin_two>/download. The latter
+  // serves an HTML document.
+  origin_one.RegisterRequestHandler(
+      CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
+  origin_two.RegisterRequestHandler(
+      CreateBasicResponseHandler("/download", net::HTTP_OK, base::StringPairs(),
+                                 "text/html", "<title>hello</title>"));
+
+  origin_one.StartAcceptingConnections();
+  origin_two.StartAcceptingConnections();
+
+  std::unique_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
+  NavigateToURL(shell(), referrer_url);
+
+  // Alt-click the link.
+  blink::WebMouseEvent mouse_event(
+      blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kAltKey,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  mouse_event.button = blink::WebMouseEvent::Button::kLeft;
+  mouse_event.SetPositionInWidget(15, 15);
+  mouse_event.click_count = 1;
+  shell()->web_contents()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
+  mouse_event.SetType(blink::WebInputEvent::kMouseUp);
+  shell()->web_contents()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
+
+  observer->WaitForFinished();
+  EXPECT_EQ(
+      1u, observer->NumDownloadsSeenInState(download::DownloadItem::COMPLETE));
+
+  std::vector<download::DownloadItem*> downloads;
+  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+  ASSERT_EQ(1u, downloads.size());
+#if defined(OS_WIN)
+  EXPECT_EQ(FILE_PATH_LITERAL("download.htm"),
+            downloads[0]->GetTargetFilePath().BaseName().value());
+#else
+  EXPECT_EQ(FILE_PATH_LITERAL("download.html"),
+            downloads[0]->GetTargetFilePath().BaseName().value());
+#endif
+
+  ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
+  ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
+}
+#endif  // !defined(OS_ANDROID)
+
 // Test that the suggested filename for data: URLs works.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeDataUrl) {
   net::EmbeddedTestServer server;
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9771a22..a687303 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -239,7 +239,6 @@
     switches::kShowMacOverlayBorders,
 #endif
 #if defined(USE_OZONE)
-    switches::kEnableDrmMojo,
     switches::kOzonePlatform,
     switches::kOzoneDumpFile,
 #endif
@@ -830,9 +829,7 @@
   // possible to ensure the latter always has a valid device. crbug.com/608839
   // When running with mus, the OzonePlatform may not have been created yet. So
   // defer the callback until OzonePlatform instance is created.
-  base::CommandLine* browser_command_line =
-      base::CommandLine::ForCurrentProcess();
-  if (browser_command_line->HasSwitch(switches::kEnableDrmMojo)) {
+  if (features::IsOzoneDrmMojo()) {
     // TODO(rjkroege): Remove the legacy IPC code paths when no longer
     // necessary. https://crbug.com/806092
     auto interface_binder = base::BindRepeating(&GpuProcessHost::BindInterface,
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 48dd293..8317c80 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -170,7 +170,7 @@
 bool RenderWidgetHostInputEventRouter::HittestDelegate::RejectHitTarget(
     const viz::SurfaceDrawQuad* surface_quad,
     const gfx::Point& point_in_quad_space) {
-  auto it = hittest_data_.find(surface_quad->primary_surface_id);
+  auto it = hittest_data_.find(surface_quad->surface_range.end());
   if (it != hittest_data_.end() && it->second.ignored_for_hittest)
     return true;
   return false;
@@ -179,7 +179,7 @@
 bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget(
     const viz::SurfaceDrawQuad* surface_quad,
     const gfx::Point& point_in_quad_space) {
-  auto it = hittest_data_.find(surface_quad->primary_surface_id);
+  auto it = hittest_data_.find(surface_quad->surface_range.end());
   if (it != hittest_data_.end() && !it->second.ignored_for_hittest)
     return true;
   return false;
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 1d5a283..e6935c6 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -1777,12 +1777,15 @@
 }
 
 #if defined(USE_AURA)
-IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, RootWindowTransform) {
+// TODO(https://crbug.com/865945): Fix this test.
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+                       DISABLED_RootWindowTransform) {
   HitTestRootWindowTransform(shell(), embedded_test_server());
 }
 
+// TODO(https://crbug.com/865945): Fix this test.
 IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
-                       RootWindowTransform) {
+                       DISABLED_RootWindowTransform) {
   HitTestRootWindowTransform(shell(), embedded_test_server());
 }
 #endif  // defined(USE_AURA)
diff --git a/content/public/test/layouttest_support.h b/content/public/test/layouttest_support.h
index 12ecd31..06de084 100644
--- a/content/public/test/layouttest_support.h
+++ b/content/public/test/layouttest_support.h
@@ -24,7 +24,6 @@
 class WebURL;
 class WebURLRequest;
 class WebView;
-class WebWidget;
 }
 
 namespace gfx {
@@ -79,21 +78,7 @@
 // Enable injecting of a WebViewTestProxy between WebViews and RenderViews,
 // WebWidgetTestProxy between WebWidgets and RenderWidgets and WebFrameTestProxy
 // between WebFrames and RenderFrames.
-// |view_proxy_creation_callback| is invoked after creating WebViewTestProxy.
-// |widget_proxy_creation_callback| is invoked after creating
-// WebWidgetTestProxy.
-// |frame_proxy_creation_callback| is called after creating WebFrameTestProxy.
-using ViewProxyCreationCallback =
-    base::Callback<void(RenderView*, test_runner::WebViewTestProxyBase*)>;
-using WidgetProxyCreationCallback =
-    base::Callback<void(blink::WebWidget*,
-                        test_runner::WebWidgetTestProxyBase*)>;
-using FrameProxyCreationCallback =
-    base::Callback<void(RenderFrame*, test_runner::WebFrameTestProxyBase*)>;
-void EnableWebTestProxyCreation(
-    const ViewProxyCreationCallback& view_proxy_creation_callback,
-    const WidgetProxyCreationCallback& widget_proxy_creation_callback,
-    const FrameProxyCreationCallback& frame_proxy_creation_callback);
+void EnableWebTestProxyCreation();
 
 typedef base::OnceCallback<void(const GURL&, const blink::Manifest&)>
     FetchManifestCallback;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index d0a99af..6c6ac67e 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -1031,7 +1031,10 @@
 
 # See comment at the top of //content/BUILD.gn for how this works.
 group("for_content_tests") {
-  visibility = [ "//content/test/*" ]
+  visibility = [
+    "//content/shell/test_runner",
+    "//content/test/*",
+  ]
 
   if (!is_component_build) {
     public_deps = [
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index 24c569e..558e0ff 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -313,8 +313,10 @@
         SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
     surface_quad->SetNew(
         shared_quad_state, gfx::Rect(child_size), gfx::Rect(child_size),
-        viz::SurfaceId(kChildFrameSinkId, child_local_surface_id_),
-        base::nullopt, SK_ColorWHITE, false);
+        viz::SurfaceRange(
+            base::nullopt,
+            viz::SurfaceId(kChildFrameSinkId, child_local_surface_id_)),
+        SK_ColorWHITE, false);
 
     child_support_->SubmitCompositorFrame(child_local_surface_id_,
                                           std::move(frame));
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index f8ea74d..403e6a4 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -1548,6 +1548,106 @@
 }
 
 webrtc::RTCErrorOr<std::unique_ptr<blink::WebRTCRtpTransceiver>>
+RTCPeerConnectionHandler::AddTransceiverWithTrack(
+    const blink::WebMediaStreamTrack& web_track,
+    const webrtc::RtpTransceiverInit& init) {
+  DCHECK_EQ(sdp_semantics_, blink::WebRTCSdpSemantics::kUnifiedPlan);
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref =
+      track_adapter_map_->GetOrCreateLocalTrackAdapter(web_track);
+  TransceiverStateSurfacer transceiver_state_surfacer(task_runner_,
+                                                      signaling_thread());
+  webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>
+      error_or_transceiver;
+  RunSynchronousClosureOnSignalingThread(
+      base::BindRepeating(
+          &RTCPeerConnectionHandler::AddTransceiverWithTrackOnSignalingThread,
+          base::Unretained(this), base::RetainedRef(track_ref->webrtc_track()),
+          base::ConstRef(init), base::Unretained(&transceiver_state_surfacer),
+          base::Unretained(&error_or_transceiver)),
+      "AddTransceiverWithTrackOnSignalingThread");
+  if (!error_or_transceiver.ok()) {
+    // Don't leave the surfacer in a pending state.
+    transceiver_state_surfacer.ObtainStates();
+    return error_or_transceiver.MoveError();
+  }
+
+  auto transceiver_states = transceiver_state_surfacer.ObtainStates();
+  auto transceiver =
+      CreateOrUpdateTransceiver(std::move(transceiver_states[0]));
+  std::unique_ptr<blink::WebRTCRtpTransceiver> web_transceiver =
+      std::move(transceiver);
+  return std::move(web_transceiver);
+}
+
+void RTCPeerConnectionHandler::AddTransceiverWithTrackOnSignalingThread(
+    rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track,
+    webrtc::RtpTransceiverInit init,
+    TransceiverStateSurfacer* transceiver_state_surfacer,
+    webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>*
+        error_or_transceiver) {
+  *error_or_transceiver =
+      native_peer_connection_->AddTransceiver(webrtc_track, init);
+  std::vector<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> transceivers;
+  if (error_or_transceiver->ok())
+    transceivers.push_back(error_or_transceiver->value());
+  transceiver_state_surfacer->Initialize(track_adapter_map_, transceivers);
+}
+
+webrtc::RTCErrorOr<std::unique_ptr<blink::WebRTCRtpTransceiver>>
+RTCPeerConnectionHandler::AddTransceiverWithKind(
+    std::string kind,
+    const webrtc::RtpTransceiverInit& init) {
+  DCHECK_EQ(sdp_semantics_, blink::WebRTCSdpSemantics::kUnifiedPlan);
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  cricket::MediaType media_type;
+  if (kind == webrtc::MediaStreamTrackInterface::kAudioKind) {
+    media_type = cricket::MEDIA_TYPE_AUDIO;
+  } else {
+    DCHECK_EQ(kind, webrtc::MediaStreamTrackInterface::kVideoKind);
+    media_type = cricket::MEDIA_TYPE_VIDEO;
+  }
+  TransceiverStateSurfacer transceiver_state_surfacer(task_runner_,
+                                                      signaling_thread());
+  webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>
+      error_or_transceiver;
+  RunSynchronousClosureOnSignalingThread(
+      base::BindRepeating(&RTCPeerConnectionHandler::
+                              AddTransceiverWithMediaTypeOnSignalingThread,
+                          base::Unretained(this), base::ConstRef(media_type),
+                          base::ConstRef(init),
+                          base::Unretained(&transceiver_state_surfacer),
+                          base::Unretained(&error_or_transceiver)),
+      "AddTransceiverWithMediaTypeOnSignalingThread");
+  if (!error_or_transceiver.ok()) {
+    // Don't leave the surfacer in a pending state.
+    transceiver_state_surfacer.ObtainStates();
+    return error_or_transceiver.MoveError();
+  }
+
+  auto transceiver_states = transceiver_state_surfacer.ObtainStates();
+  auto transceiver =
+      CreateOrUpdateTransceiver(std::move(transceiver_states[0]));
+  std::unique_ptr<blink::WebRTCRtpTransceiver> web_transceiver =
+      std::move(transceiver);
+  return std::move(web_transceiver);
+}
+
+void RTCPeerConnectionHandler::AddTransceiverWithMediaTypeOnSignalingThread(
+    cricket::MediaType media_type,
+    webrtc::RtpTransceiverInit init,
+    TransceiverStateSurfacer* transceiver_state_surfacer,
+    webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>*
+        error_or_transceiver) {
+  *error_or_transceiver =
+      native_peer_connection_->AddTransceiver(media_type, init);
+  std::vector<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> transceivers;
+  if (error_or_transceiver->ok())
+    transceivers.push_back(error_or_transceiver->value());
+  transceiver_state_surfacer->Initialize(track_adapter_map_, transceivers);
+}
+
+webrtc::RTCErrorOr<std::unique_ptr<blink::WebRTCRtpTransceiver>>
 RTCPeerConnectionHandler::AddTrack(
     const blink::WebMediaStreamTrack& track,
     const blink::WebVector<blink::WebMediaStream>& streams) {
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
index 9a82246..dfe3049 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -146,6 +146,12 @@
   void GetStats(const blink::WebRTCStatsRequest& request) override;
   void GetStats(
       std::unique_ptr<blink::WebRTCStatsReportCallback> callback) override;
+  webrtc::RTCErrorOr<std::unique_ptr<blink::WebRTCRtpTransceiver>>
+  AddTransceiverWithTrack(const blink::WebMediaStreamTrack& web_track,
+                          const webrtc::RtpTransceiverInit& init) override;
+  webrtc::RTCErrorOr<std::unique_ptr<blink::WebRTCRtpTransceiver>>
+  AddTransceiverWithKind(std::string kind,
+                         const webrtc::RtpTransceiverInit& init) override;
   webrtc::RTCErrorOr<std::unique_ptr<blink::WebRTCRtpTransceiver>> AddTrack(
       const blink::WebMediaStreamTrack& web_track,
       const blink::WebVector<blink::WebMediaStream>& web_streams) override;
@@ -242,6 +248,18 @@
   void ReportFirstSessionDescriptions(const FirstSessionDescription& local,
                                       const FirstSessionDescription& remote);
 
+  void AddTransceiverWithTrackOnSignalingThread(
+      rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track,
+      webrtc::RtpTransceiverInit init,
+      TransceiverStateSurfacer* transceiver_state_surfacer,
+      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>*
+          error_or_transceiver);
+  void AddTransceiverWithMediaTypeOnSignalingThread(
+      cricket::MediaType media_type,
+      webrtc::RtpTransceiverInit init,
+      TransceiverStateSurfacer* transceiver_state_surfacer,
+      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>*
+          error_or_transceiver);
   void AddTrackOnSignalingThread(
       rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
       std::vector<std::string> stream_ids,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 5a227671..d7d39dc 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6168,7 +6168,7 @@
     blink::mojom::BlobURLTokenPtrInfo blob_url_token =
         CloneBlobURLToken(info.blob_url_token.get());
     DownloadURL(info.url_request,
-                blink::WebLocalFrameClient::CrossOriginRedirects::kNavigate,
+                blink::WebLocalFrameClient::CrossOriginRedirects::kFollow,
                 blob_url_token.PassHandle());
   } else {
     OpenURL(info, /*send_referrer=*/true,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index cb5ffc5..efc7005 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -248,8 +248,7 @@
   // Just like RenderFrame::FromWebFrame but returns the implementation.
   static RenderFrameImpl* FromWebFrame(blink::WebFrame* web_frame);
 
-  // Used by content_layouttest_support to hook into the creation of
-  // RenderFrameImpls.
+  // Constructor parameters are bundled into a struct.
   struct CONTENT_EXPORT CreateParams {
     CreateParams(
         RenderViewImpl* render_view,
diff --git a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
index 860c551..64ef9de 100644
--- a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
+++ b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
@@ -61,75 +61,8 @@
 
 namespace content {
 
-namespace {
-
-void WebViewTestProxyCreated(RenderView* render_view,
-                             test_runner::WebViewTestProxyBase* proxy) {
-  test_runner::WebTestInterfaces* interfaces =
-      LayoutTestRenderThreadObserver::GetInstance()->test_interfaces();
-
-  BlinkTestRunner* test_runner = new BlinkTestRunner(render_view);
-  // TODO(lukasza): Using the 1st BlinkTestRunner as the main delegate is wrong,
-  // but it is difficult to change because this behavior has been baked for a
-  // long time into test assumptions (i.e. which PrintMessage gets delivered to
-  // the browser depends on this).
-  static bool first_test_runner = true;
-  if (first_test_runner) {
-    first_test_runner = false;
-    interfaces->SetDelegate(test_runner);
-  }
-
-  auto* test_interfaces =
-      LayoutTestRenderThreadObserver::GetInstance()->test_interfaces();
-
-  proxy->set_delegate(test_runner);
-
-  std::unique_ptr<test_runner::WebViewTestClient> view_test_client =
-      test_interfaces->CreateWebViewTestClient(proxy, nullptr);
-  proxy->set_view_test_client(std::move(view_test_client));
-  std::unique_ptr<test_runner::WebWidgetTestClient> widget_test_client =
-      test_interfaces->CreateWebWidgetTestClient(
-          proxy->web_widget_test_proxy_base());
-  proxy->web_widget_test_proxy_base()->set_widget_test_client(
-      std::move(widget_test_client));
-  proxy->SetInterfaces(interfaces);
-  proxy->SetUpWidgetClient();
-}
-
-void WebWidgetTestProxyCreated(blink::WebWidget* web_widget,
-                               test_runner::WebWidgetTestProxyBase* proxy) {
-  CHECK(web_widget->IsWebFrameWidget());
-  proxy->set_web_widget(web_widget);
-  blink::WebFrameWidget* web_frame_widget =
-      static_cast<blink::WebFrameWidget*>(web_widget);
-  blink::WebView* web_view = web_frame_widget->LocalRoot()->View();
-  RenderView* render_view = RenderView::FromWebView(web_view);
-  test_runner::WebViewTestProxyBase* view_proxy =
-      GetWebViewTestProxyBase(render_view);
-  std::unique_ptr<test_runner::WebWidgetTestClient> widget_test_client =
-      LayoutTestRenderThreadObserver::GetInstance()
-          ->test_interfaces()
-          ->CreateWebWidgetTestClient(proxy);
-  proxy->set_web_view_test_proxy_base(view_proxy);
-  proxy->set_widget_test_client(std::move(widget_test_client));
-}
-
-void WebFrameTestProxyCreated(RenderFrame* render_frame,
-                              test_runner::WebFrameTestProxyBase* proxy) {
-  test_runner::WebViewTestProxyBase* web_view_test_proxy_base =
-      GetWebViewTestProxyBase(render_frame->GetRenderView());
-  proxy->set_test_client(
-      LayoutTestRenderThreadObserver::GetInstance()
-          ->test_interfaces()
-          ->CreateWebFrameTestClient(web_view_test_proxy_base, proxy));
-}
-
-}  // namespace
-
 LayoutTestContentRendererClient::LayoutTestContentRendererClient() {
-  EnableWebTestProxyCreation(base::Bind(&WebViewTestProxyCreated),
-                             base::Bind(&WebWidgetTestProxyCreated),
-                             base::Bind(&WebFrameTestProxyCreated));
+  EnableWebTestProxyCreation();
   SetWorkerRewriteURLFunction(RewriteLayoutTestsURL);
 }
 
diff --git a/content/shell/test_runner/BUILD.gn b/content/shell/test_runner/BUILD.gn
index 1b5c11a..6419cce 100644
--- a/content/shell/test_runner/BUILD.gn
+++ b/content/shell/test_runner/BUILD.gn
@@ -11,6 +11,12 @@
 component("test_runner") {
   testonly = true
 
+  # See comment at the top of //content/BUILD.gn for why this is disabled in
+  # component builds.
+  if (is_component_build) {
+    check_includes = false
+  }
+
   defines = [ "TEST_RUNNER_IMPLEMENTATION" ]
 
   sources = [
@@ -98,6 +104,7 @@
     "//content/public/common",
     "//content/public/common:service_names",
     "//content/public/renderer",
+    "//content/renderer:for_content_tests",
     "//content/shell:layout_test_switches",
     "//content/test:test_runner_support",
     "//device/base/synchronization",
diff --git a/content/shell/test_runner/DEPS b/content/shell/test_runner/DEPS
index 61d85b0..8796790 100644
--- a/content/shell/test_runner/DEPS
+++ b/content/shell/test_runner/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+cc",
   "+content/public/test",
+  "+content/renderer",
   "+device/gamepad/public/cpp",
   "+device/gamepad/public/mojom",
   "+gin",
diff --git a/content/shell/test_runner/web_frame_test_proxy.cc b/content/shell/test_runner/web_frame_test_proxy.cc
index 48c717f..0adaee59 100644
--- a/content/shell/test_runner/web_frame_test_proxy.cc
+++ b/content/shell/test_runner/web_frame_test_proxy.cc
@@ -4,9 +4,237 @@
 
 #include "content/shell/test_runner/web_frame_test_proxy.h"
 
+#include "content/shell/test_runner/web_test_interfaces.h"
+#include "content/shell/test_runner/web_view_test_proxy.h"
+
 namespace test_runner {
 
-WebFrameTestProxyBase::WebFrameTestProxyBase() : web_frame_(nullptr) {}
-WebFrameTestProxyBase::~WebFrameTestProxyBase() {}
+WebFrameTestProxy::~WebFrameTestProxy() = default;
+
+void WebFrameTestProxy::Initialize(
+    WebTestInterfaces* interfaces,
+    content::RenderViewImpl* render_view_for_frame) {
+  // The RenderViewImpl will also be a test proxy type.
+  auto* view_proxy_for_frame =
+      static_cast<WebViewTestProxy*>(render_view_for_frame);
+
+  test_client_ =
+      interfaces->CreateWebFrameTestClient(view_proxy_for_frame, this);
+}
+
+// WebLocalFrameClient implementation.
+blink::WebPlugin* WebFrameTestProxy::CreatePlugin(
+    const blink::WebPluginParams& params) {
+  blink::WebPlugin* plugin = test_client_->CreatePlugin(params);
+  if (plugin)
+    return plugin;
+  return RenderFrameImpl::CreatePlugin(params);
+}
+
+void WebFrameTestProxy::DidAddMessageToConsole(
+    const blink::WebConsoleMessage& message,
+    const blink::WebString& source_name,
+    unsigned source_line,
+    const blink::WebString& stack_trace) {
+  test_client_->DidAddMessageToConsole(message, source_name, source_line,
+                                       stack_trace);
+  RenderFrameImpl::DidAddMessageToConsole(message, source_name, source_line,
+                                          stack_trace);
+}
+
+void WebFrameTestProxy::DownloadURL(
+    const blink::WebURLRequest& request,
+    blink::WebLocalFrameClient::CrossOriginRedirects
+        cross_origin_redirect_behavior,
+    mojo::ScopedMessagePipeHandle blob_url_token) {
+  test_client_->DownloadURL(request, cross_origin_redirect_behavior,
+                            mojo::ScopedMessagePipeHandle());
+  RenderFrameImpl::DownloadURL(request, cross_origin_redirect_behavior,
+                               std::move(blob_url_token));
+}
+
+void WebFrameTestProxy::DidStartProvisionalLoad(
+    blink::WebDocumentLoader* document_loader,
+    blink::WebURLRequest& request) {
+  test_client_->DidStartProvisionalLoad(document_loader, request);
+  RenderFrameImpl::DidStartProvisionalLoad(document_loader, request);
+}
+
+void WebFrameTestProxy::DidFailProvisionalLoad(
+    const blink::WebURLError& error,
+    blink::WebHistoryCommitType commit_type) {
+  test_client_->DidFailProvisionalLoad(error, commit_type);
+  // If the test finished, don't notify the embedder of the failed load,
+  // as we already destroyed the document loader.
+  if (!web_frame()->GetProvisionalDocumentLoader())
+    return;
+  RenderFrameImpl::DidFailProvisionalLoad(error, commit_type);
+}
+
+void WebFrameTestProxy::DidCommitProvisionalLoad(
+    const blink::WebHistoryItem& item,
+    blink::WebHistoryCommitType commit_type,
+    blink::WebGlobalObjectReusePolicy global_object_reuse_policy) {
+  test_client_->DidCommitProvisionalLoad(item, commit_type,
+                                         global_object_reuse_policy);
+  RenderFrameImpl::DidCommitProvisionalLoad(item, commit_type,
+                                            global_object_reuse_policy);
+}
+
+void WebFrameTestProxy::DidFinishSameDocumentNavigation(
+    const blink::WebHistoryItem& item,
+    blink::WebHistoryCommitType commit_type,
+    bool content_initiated) {
+  test_client_->DidFinishSameDocumentNavigation(item, commit_type,
+                                                content_initiated);
+  RenderFrameImpl::DidFinishSameDocumentNavigation(item, commit_type,
+                                                   content_initiated);
+}
+
+void WebFrameTestProxy::DidReceiveTitle(const blink::WebString& title,
+                                        blink::WebTextDirection direction) {
+  test_client_->DidReceiveTitle(title, direction);
+  RenderFrameImpl::DidReceiveTitle(title, direction);
+}
+
+void WebFrameTestProxy::DidChangeIcon(blink::WebIconURL::Type icon_type) {
+  test_client_->DidChangeIcon(icon_type);
+  RenderFrameImpl::DidChangeIcon(icon_type);
+}
+
+void WebFrameTestProxy::DidFinishDocumentLoad() {
+  test_client_->DidFinishDocumentLoad();
+  RenderFrameImpl::DidFinishDocumentLoad();
+}
+
+void WebFrameTestProxy::DidHandleOnloadEvents() {
+  test_client_->DidHandleOnloadEvents();
+  RenderFrameImpl::DidHandleOnloadEvents();
+}
+
+void WebFrameTestProxy::DidFailLoad(const blink::WebURLError& error,
+                                    blink::WebHistoryCommitType commit_type) {
+  test_client_->DidFailLoad(error, commit_type);
+  RenderFrameImpl::DidFailLoad(error, commit_type);
+}
+
+void WebFrameTestProxy::DidFinishLoad() {
+  RenderFrameImpl::DidFinishLoad();
+  test_client_->DidFinishLoad();
+}
+
+void WebFrameTestProxy::DidStopLoading() {
+  RenderFrameImpl::DidStopLoading();
+  test_client_->DidStopLoading();
+}
+
+void WebFrameTestProxy::DidChangeSelection(bool is_selection_empty) {
+  test_client_->DidChangeSelection(is_selection_empty);
+  RenderFrameImpl::DidChangeSelection(is_selection_empty);
+}
+
+void WebFrameTestProxy::DidChangeContents() {
+  test_client_->DidChangeContents();
+  RenderFrameImpl::DidChangeContents();
+}
+
+blink::WebEffectiveConnectionType
+WebFrameTestProxy::GetEffectiveConnectionType() {
+  if (test_client_->GetEffectiveConnectionType() !=
+      blink::WebEffectiveConnectionType::kTypeUnknown) {
+    return test_client_->GetEffectiveConnectionType();
+  }
+  return RenderFrameImpl::GetEffectiveConnectionType();
+}
+
+void WebFrameTestProxy::RunModalAlertDialog(const blink::WebString& message) {
+  test_client_->RunModalAlertDialog(message);
+}
+
+bool WebFrameTestProxy::RunModalConfirmDialog(const blink::WebString& message) {
+  return test_client_->RunModalConfirmDialog(message);
+}
+
+bool WebFrameTestProxy::RunModalPromptDialog(
+    const blink::WebString& message,
+    const blink::WebString& default_value,
+    blink::WebString* actual_value) {
+  return test_client_->RunModalPromptDialog(message, default_value,
+                                            actual_value);
+}
+
+bool WebFrameTestProxy::RunModalBeforeUnloadDialog(bool is_reload) {
+  return test_client_->RunModalBeforeUnloadDialog(is_reload);
+}
+
+void WebFrameTestProxy::ShowContextMenu(
+    const blink::WebContextMenuData& context_menu_data) {
+  test_client_->ShowContextMenu(context_menu_data);
+  RenderFrameImpl::ShowContextMenu(context_menu_data);
+}
+
+void WebFrameTestProxy::DidDetectXSS(const blink::WebURL& insecure_url,
+                                     bool did_block_entire_page) {
+  // This is not implemented in RenderFrameImpl, so need to explicitly call
+  // into the base proxy.
+  test_client_->DidDetectXSS(insecure_url, did_block_entire_page);
+  RenderFrameImpl::DidDetectXSS(insecure_url, did_block_entire_page);
+}
+
+void WebFrameTestProxy::DidDispatchPingLoader(const blink::WebURL& url) {
+  // This is not implemented in RenderFrameImpl, so need to explicitly call
+  // into the base proxy.
+  test_client_->DidDispatchPingLoader(url);
+  RenderFrameImpl::DidDispatchPingLoader(url);
+}
+
+void WebFrameTestProxy::WillSendRequest(blink::WebURLRequest& request) {
+  RenderFrameImpl::WillSendRequest(request);
+  test_client_->WillSendRequest(request);
+}
+
+void WebFrameTestProxy::DidReceiveResponse(
+    const blink::WebURLResponse& response) {
+  test_client_->DidReceiveResponse(response);
+  RenderFrameImpl::DidReceiveResponse(response);
+}
+
+blink::WebNavigationPolicy WebFrameTestProxy::DecidePolicyForNavigation(
+    const blink::WebLocalFrameClient::NavigationPolicyInfo& info) {
+  blink::WebNavigationPolicy policy =
+      test_client_->DecidePolicyForNavigation(info);
+  if (policy == blink::kWebNavigationPolicyIgnore)
+    return policy;
+
+  return RenderFrameImpl::DecidePolicyForNavigation(info);
+}
+
+void WebFrameTestProxy::PostAccessibilityEvent(const blink::WebAXObject& object,
+                                               blink::WebAXEvent event) {
+  test_client_->PostAccessibilityEvent(object, event);
+  // Guard against the case where |this| was deleted as a result of an
+  // accessibility listener detaching a frame. If that occurs, the
+  // WebAXObject will be detached.
+  if (object.IsDetached())
+    return;  // |this| is invalid.
+  RenderFrameImpl::PostAccessibilityEvent(object, event);
+}
+
+void WebFrameTestProxy::CheckIfAudioSinkExistsAndIsAuthorized(
+    const blink::WebString& sink_id,
+    blink::WebSetSinkIdCallbacks* web_callbacks) {
+  test_client_->CheckIfAudioSinkExistsAndIsAuthorized(sink_id, web_callbacks);
+}
+
+void WebFrameTestProxy::DidClearWindowObject() {
+  test_client_->DidClearWindowObject();
+  RenderFrameImpl::DidClearWindowObject();
+}
+
+bool WebFrameTestProxy::RunFileChooser(
+    const blink::WebFileChooserParams& params,
+    blink::WebFileChooserCompletion* completion) {
+  return test_client_->RunFileChooser(params, completion);
+}
 
 }  // namespace test_runner
diff --git a/content/shell/test_runner/web_frame_test_proxy.h b/content/shell/test_runner/web_frame_test_proxy.h
index fe1f701..9338c7e 100644
--- a/content/shell/test_runner/web_frame_test_proxy.h
+++ b/content/shell/test_runner/web_frame_test_proxy.h
@@ -9,10 +9,8 @@
 #include <string>
 #include <utility>
 
-#include "base/command_line.h"
-#include "base/logging.h"
 #include "base/macros.h"
-#include "content/public/common/content_switches.h"
+#include "content/renderer/render_frame_impl.h"
 #include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_frame_test_client.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
@@ -20,16 +18,15 @@
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_local_frame_client.h"
 
+namespace content {
+class RenderViewImpl;
+}
+
 namespace test_runner {
+class WebTestInterfaces;
 
 class TEST_RUNNER_EXPORT WebFrameTestProxyBase {
  public:
-  void set_test_client(std::unique_ptr<WebFrameTestClient> client) {
-    DCHECK(client);
-    DCHECK(!test_client_);
-    test_client_ = std::move(client);
-  }
-
   blink::WebLocalFrame* web_frame() const { return web_frame_; }
   void set_web_frame(blink::WebLocalFrame* frame) {
     DCHECK(frame);
@@ -38,237 +35,88 @@
   }
 
  protected:
-  WebFrameTestProxyBase();
-  ~WebFrameTestProxyBase();
-  blink::WebLocalFrameClient* test_client() { return test_client_.get(); }
+  WebFrameTestProxyBase() = default;
+  ~WebFrameTestProxyBase() = default;
 
  private:
-  std::unique_ptr<WebFrameTestClient> test_client_;
-  blink::WebLocalFrame* web_frame_;
+  blink::WebLocalFrame* web_frame_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(WebFrameTestProxyBase);
 };
 
-// WebFrameTestProxy is used during LayoutTests and always instantiated, at time
-// of writing with Base=RenderFrameImpl. It does not directly inherit from it
-// for layering purposes.
-template <class Base>
-class WebFrameTestProxy : public Base, public WebFrameTestProxyBase {
+// WebFrameTestProxy is used during LayoutTests instead of a RenderFrameImpl to
+// inject test-only behaviour by overriding methods in the base class.
+class TEST_RUNNER_EXPORT WebFrameTestProxy : public content::RenderFrameImpl,
+                                             public WebFrameTestProxyBase {
  public:
   template <typename... Args>
   explicit WebFrameTestProxy(Args&&... args)
-      : Base(std::forward<Args>(args)...) {}
+      : RenderFrameImpl(std::forward<Args>(args)...) {}
+  ~WebFrameTestProxy() override;
 
-  virtual ~WebFrameTestProxy() {}
+  void Initialize(WebTestInterfaces* interfaces,
+                  content::RenderViewImpl* render_view_for_frame);
 
   // WebLocalFrameClient implementation.
-  blink::WebPlugin* CreatePlugin(
-      const blink::WebPluginParams& params) override {
-    blink::WebPlugin* plugin = test_client()->CreatePlugin(params);
-    if (plugin)
-      return plugin;
-    return Base::CreatePlugin(params);
-  }
-
+  blink::WebPlugin* CreatePlugin(const blink::WebPluginParams& params) override;
   void DidAddMessageToConsole(const blink::WebConsoleMessage& message,
                               const blink::WebString& source_name,
                               unsigned source_line,
-                              const blink::WebString& stack_trace) override {
-    test_client()->DidAddMessageToConsole(message, source_name, source_line,
-                                          stack_trace);
-    Base::DidAddMessageToConsole(message, source_name, source_line,
-                                 stack_trace);
-  }
-
+                              const blink::WebString& stack_trace) override;
   void DownloadURL(const blink::WebURLRequest& request,
                    blink::WebLocalFrameClient::CrossOriginRedirects
                        cross_origin_redirect_behavior,
-                   mojo::ScopedMessagePipeHandle blob_url_token) override {
-    test_client()->DownloadURL(request, cross_origin_redirect_behavior,
-                               mojo::ScopedMessagePipeHandle());
-    Base::DownloadURL(request, cross_origin_redirect_behavior,
-                      std::move(blob_url_token));
-  }
-
-
+                   mojo::ScopedMessagePipeHandle blob_url_token) override;
   void DidStartProvisionalLoad(blink::WebDocumentLoader* document_loader,
-                               blink::WebURLRequest& request) override {
-    test_client()->DidStartProvisionalLoad(document_loader, request);
-    Base::DidStartProvisionalLoad(document_loader, request);
-  }
-
-  void DidFailProvisionalLoad(
-      const blink::WebURLError& error,
-      blink::WebHistoryCommitType commit_type) override {
-    test_client()->DidFailProvisionalLoad(error, commit_type);
-    // If the test finished, don't notify the embedder of the failed load,
-    // as we already destroyed the document loader.
-    if (!web_frame()->GetProvisionalDocumentLoader())
-      return;
-    Base::DidFailProvisionalLoad(error, commit_type);
-  }
-
+                               blink::WebURLRequest& request) override;
+  void DidFailProvisionalLoad(const blink::WebURLError& error,
+                              blink::WebHistoryCommitType commit_type) override;
   void DidCommitProvisionalLoad(
       const blink::WebHistoryItem& item,
       blink::WebHistoryCommitType commit_type,
-      blink::WebGlobalObjectReusePolicy global_object_reuse_policy) override {
-    test_client()->DidCommitProvisionalLoad(item, commit_type,
-                                            global_object_reuse_policy);
-    Base::DidCommitProvisionalLoad(item, commit_type,
-                                   global_object_reuse_policy);
-  }
-
+      blink::WebGlobalObjectReusePolicy global_object_reuse_policy) override;
   void DidFinishSameDocumentNavigation(const blink::WebHistoryItem& item,
                                        blink::WebHistoryCommitType commit_type,
-                                       bool content_initiated) {
-    test_client()->DidFinishSameDocumentNavigation(item, commit_type,
-                                                   content_initiated);
-    Base::DidFinishSameDocumentNavigation(item, commit_type, content_initiated);
-  }
-
+                                       bool content_initiated) override;
   void DidReceiveTitle(const blink::WebString& title,
-                       blink::WebTextDirection direction) override {
-    test_client()->DidReceiveTitle(title, direction);
-    Base::DidReceiveTitle(title, direction);
-  }
-
-  void DidChangeIcon(blink::WebIconURL::Type icon_type) override {
-    test_client()->DidChangeIcon(icon_type);
-    Base::DidChangeIcon(icon_type);
-  }
-
-  void DidFinishDocumentLoad() override {
-    test_client()->DidFinishDocumentLoad();
-    Base::DidFinishDocumentLoad();
-  }
-
-  void DidHandleOnloadEvents() override {
-    test_client()->DidHandleOnloadEvents();
-    Base::DidHandleOnloadEvents();
-  }
-
+                       blink::WebTextDirection direction) override;
+  void DidChangeIcon(blink::WebIconURL::Type icon_type) override;
+  void DidFinishDocumentLoad() override;
+  void DidHandleOnloadEvents() override;
   void DidFailLoad(const blink::WebURLError& error,
-                   blink::WebHistoryCommitType commit_type) override {
-    test_client()->DidFailLoad(error, commit_type);
-    Base::DidFailLoad(error, commit_type);
-  }
-
-  void DidFinishLoad() override {
-    Base::DidFinishLoad();
-    test_client()->DidFinishLoad();
-  }
-
-  void DidStopLoading() override {
-    Base::DidStopLoading();
-    test_client()->DidStopLoading();
-  }
-
-  void DidChangeSelection(bool is_selection_empty) override {
-    test_client()->DidChangeSelection(is_selection_empty);
-    Base::DidChangeSelection(is_selection_empty);
-  }
-
-  void DidChangeContents() override {
-    test_client()->DidChangeContents();
-    Base::DidChangeContents();
-  }
-
-  blink::WebEffectiveConnectionType GetEffectiveConnectionType() override {
-    if (test_client()->GetEffectiveConnectionType() !=
-        blink::WebEffectiveConnectionType::kTypeUnknown) {
-      return test_client()->GetEffectiveConnectionType();
-    }
-    return Base::GetEffectiveConnectionType();
-  }
-
-  void RunModalAlertDialog(const blink::WebString& message) override {
-    test_client()->RunModalAlertDialog(message);
-  }
-
-  bool RunModalConfirmDialog(const blink::WebString& message) override {
-    return test_client()->RunModalConfirmDialog(message);
-  }
-
+                   blink::WebHistoryCommitType commit_type) override;
+  void DidFinishLoad() override;
+  void DidStopLoading() override;
+  void DidChangeSelection(bool is_selection_empty) override;
+  void DidChangeContents() override;
+  blink::WebEffectiveConnectionType GetEffectiveConnectionType() override;
+  void RunModalAlertDialog(const blink::WebString& message) override;
+  bool RunModalConfirmDialog(const blink::WebString& message) override;
   bool RunModalPromptDialog(const blink::WebString& message,
                             const blink::WebString& default_value,
-                            blink::WebString* actual_value) override {
-    return test_client()->RunModalPromptDialog(message, default_value,
-                                               actual_value);
-  }
-
-  bool RunModalBeforeUnloadDialog(bool is_reload) override {
-    return test_client()->RunModalBeforeUnloadDialog(is_reload);
-  }
-
+                            blink::WebString* actual_value) override;
+  bool RunModalBeforeUnloadDialog(bool is_reload) override;
   void ShowContextMenu(
-      const blink::WebContextMenuData& context_menu_data) override {
-    test_client()->ShowContextMenu(context_menu_data);
-    Base::ShowContextMenu(context_menu_data);
-  }
-
+      const blink::WebContextMenuData& context_menu_data) override;
   void DidDetectXSS(const blink::WebURL& insecure_url,
-                    bool did_block_entire_page) override {
-    // This is not implemented in RenderFrameImpl, so need to explicitly call
-    // into the base proxy.
-    test_client()->DidDetectXSS(insecure_url, did_block_entire_page);
-    Base::DidDetectXSS(insecure_url, did_block_entire_page);
-  }
-
-  void DidDispatchPingLoader(const blink::WebURL& url) override {
-    // This is not implemented in RenderFrameImpl, so need to explicitly call
-    // into the base proxy.
-    test_client()->DidDispatchPingLoader(url);
-    Base::DidDispatchPingLoader(url);
-  }
-
-  void WillSendRequest(blink::WebURLRequest& request) override {
-    Base::WillSendRequest(request);
-    test_client()->WillSendRequest(request);
-  }
-
-  void DidReceiveResponse(const blink::WebURLResponse& response) override {
-    test_client()->DidReceiveResponse(response);
-    Base::DidReceiveResponse(response);
-  }
-
+                    bool did_block_entire_page) override;
+  void DidDispatchPingLoader(const blink::WebURL& url) override;
+  void WillSendRequest(blink::WebURLRequest& request) override;
+  void DidReceiveResponse(const blink::WebURLResponse& response) override;
   blink::WebNavigationPolicy DecidePolicyForNavigation(
-      const blink::WebLocalFrameClient::NavigationPolicyInfo& info) override {
-    blink::WebNavigationPolicy policy =
-        test_client()->DecidePolicyForNavigation(info);
-    if (policy == blink::kWebNavigationPolicyIgnore)
-      return policy;
-
-    return Base::DecidePolicyForNavigation(info);
-  }
-
+      const blink::WebLocalFrameClient::NavigationPolicyInfo& info) override;
   void PostAccessibilityEvent(const blink::WebAXObject& object,
-                              blink::WebAXEvent event) override {
-    test_client()->PostAccessibilityEvent(object, event);
-    // Guard against the case where |this| was deleted as a result of an
-    // accessibility listener detaching a frame. If that occurs, the
-    // WebAXObject will be detached.
-    if (object.IsDetached())
-      return;  // |this| is invalid.
-    Base::PostAccessibilityEvent(object, event);
-  }
-
+                              blink::WebAXEvent event) override;
   void CheckIfAudioSinkExistsAndIsAuthorized(
       const blink::WebString& sink_id,
-      blink::WebSetSinkIdCallbacks* web_callbacks) override {
-    test_client()->CheckIfAudioSinkExistsAndIsAuthorized(sink_id,
-                                                         web_callbacks);
-  }
-
-  void DidClearWindowObject() override {
-    test_client()->DidClearWindowObject();
-    Base::DidClearWindowObject();
-  }
+      blink::WebSetSinkIdCallbacks* web_callbacks) override;
+  void DidClearWindowObject() override;
   bool RunFileChooser(const blink::WebFileChooserParams& params,
-                      blink::WebFileChooserCompletion* completion) override {
-    return test_client()->RunFileChooser(params, completion);
-  }
+                      blink::WebFileChooserCompletion* completion) override;
 
  private:
+  std::unique_ptr<WebFrameTestClient> test_client_;
+
   DISALLOW_COPY_AND_ASSIGN(WebFrameTestProxy);
 };
 
diff --git a/content/shell/test_runner/web_view_test_proxy.cc b/content/shell/test_runner/web_view_test_proxy.cc
index edfc35e..04c192d 100644
--- a/content/shell/test_runner/web_view_test_proxy.cc
+++ b/content/shell/test_runner/web_view_test_proxy.cc
@@ -147,13 +147,8 @@
   // want to do a real drag-and-drop.
 }
 
-WebViewTestProxyBase::WebViewTestProxyBase(
-    blink::WebWidgetClient* base_class_widget_client)
-    : test_interfaces_(nullptr),
-      delegate_(nullptr),
-      web_view_(nullptr),
-      base_class_widget_client_(base_class_widget_client),
-      accessibility_controller_(new AccessibilityController(this)),
+WebViewTestProxyBase::WebViewTestProxyBase()
+    : accessibility_controller_(new AccessibilityController(this)),
       text_input_controller_(new TextInputController(this)),
       view_test_runner_(new TestRunnerForSpecificView(this)) {
   WebWidgetTestProxyBase::set_web_view_test_proxy_base(this);
@@ -165,11 +160,6 @@
     test_interfaces_->SetDelegate(nullptr);
 }
 
-void WebViewTestProxyBase::SetInterfaces(WebTestInterfaces* interfaces) {
-  test_interfaces_ = interfaces->GetTestInterfaces();
-  test_interfaces_->WindowOpened(this);
-}
-
 void WebViewTestProxyBase::Reset() {
   accessibility_controller_->Reset();
   // text_input_controller_ doesn't have any state to reset.
@@ -189,4 +179,63 @@
   view_test_runner_->Install(frame);
 }
 
+void WebViewTestProxy::Initialize(WebTestInterfaces* interfaces,
+                                  WebTestDelegate* delegate) {
+  // On WebViewTestProxyBase.
+  set_delegate(delegate);
+
+  std::unique_ptr<WebWidgetTestClient> web_widget_client =
+      interfaces->CreateWebWidgetTestClient(web_widget_test_proxy_base());
+  view_test_client_ = interfaces->CreateWebViewTestClient(this, nullptr);
+  // This uses the widget_test_client set above on WebWidgetTestProxyBase.
+  proxy_widget_client_ = std::make_unique<ProxyWebWidgetClient>(
+      RenderViewImpl::WidgetClient(), web_widget_client.get());
+
+  // On WebWidgetTestProxyBase.
+  // It's weird that the WebView has the proxy client, but the
+  // WebWidgetProxyBase has the test one only, but that's because the
+  // WebWidgetTestProxyBase does not itself use the WebWidgetClient, only its
+  // subclasses do.
+  web_widget_test_proxy_base()->set_widget_test_client(
+      std::move(web_widget_client));
+
+  // On WebViewTestProxyBase.
+  set_test_interfaces(interfaces->GetTestInterfaces());
+  test_interfaces()->WindowOpened(this);
+}
+
+blink::WebView* WebViewTestProxy::CreateView(
+    blink::WebLocalFrame* creator,
+    const blink::WebURLRequest& request,
+    const blink::WebWindowFeatures& features,
+    const blink::WebString& frame_name,
+    blink::WebNavigationPolicy policy,
+    bool suppress_opener,
+    blink::WebSandboxFlags sandbox_flags) {
+  if (!view_test_client_->CreateView(creator, request, features, frame_name,
+                                     policy, suppress_opener, sandbox_flags))
+    return nullptr;
+  return RenderViewImpl::CreateView(creator, request, features, frame_name,
+                                    policy, suppress_opener, sandbox_flags);
+}
+
+void WebViewTestProxy::PrintPage(blink::WebLocalFrame* frame) {
+  view_test_client_->PrintPage(frame);
+}
+
+blink::WebString WebViewTestProxy::AcceptLanguages() {
+  return view_test_client_->AcceptLanguages();
+}
+
+void WebViewTestProxy::DidFocus(blink::WebLocalFrame* calling_frame) {
+  view_test_client_->DidFocus(calling_frame);
+  RenderViewImpl::DidFocus(calling_frame);
+}
+
+blink::WebWidgetClient* WebViewTestProxy::WidgetClient() {
+  return proxy_widget_client_.get();
+}
+
+WebViewTestProxy::~WebViewTestProxy() = default;
+
 }  // namespace test_runner
diff --git a/content/shell/test_runner/web_view_test_proxy.h b/content/shell/test_runner/web_view_test_proxy.h
index 52aca28b..43c5c89 100644
--- a/content/shell/test_runner/web_view_test_proxy.h
+++ b/content/shell/test_runner/web_view_test_proxy.h
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "content/renderer/render_view_impl.h"
 #include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_view_test_client.h"
 #include "content/shell/test_runner/web_widget_test_client.h"
@@ -124,35 +125,11 @@
     web_view_ = view;
   }
 
-  void set_view_test_client(
-      std::unique_ptr<WebViewTestClient> view_test_client) {
-    DCHECK(view_test_client);
-    DCHECK(!view_test_client_);
-    view_test_client_ = std::move(view_test_client);
-  }
-
-  // To be called once the WebWidgetTestClient has been set up, to build the
-  // indirection used by this class.
-  void SetUpWidgetClient() {
-    DCHECK(widget_test_client());
-    proxy_widget_client_ = std::make_unique<ProxyWebWidgetClient>(
-        base_class_widget_client_, widget_test_client());
-  }
-
   WebTestDelegate* delegate() { return delegate_; }
-  void set_delegate(WebTestDelegate* delegate) {
-    DCHECK(delegate);
-    DCHECK(!delegate_);
-    delegate_ = delegate;
-  }
-
   TestInterfaces* test_interfaces() { return test_interfaces_; }
-  void SetInterfaces(WebTestInterfaces* web_test_interfaces);
-
   AccessibilityController* accessibility_controller() {
     return accessibility_controller_.get();
   }
-
   TestRunnerForSpecificView* view_test_runner() {
     return view_test_runner_.get();
   }
@@ -165,29 +142,19 @@
   WebWidgetTestProxyBase* web_widget_test_proxy_base() { return this; }
 
  protected:
-  explicit WebViewTestProxyBase(
-      blink::WebWidgetClient* base_class_widget_client);
+  WebViewTestProxyBase();
   ~WebViewTestProxyBase();
 
-  blink::WebViewClient* view_test_client() { return view_test_client_.get(); }
-  // Wraps the widget_test_client() and the base class' WidgetClient().
-  blink::WebWidgetClient* proxy_widget_client() {
-    return proxy_widget_client_.get();
+  void set_delegate(WebTestDelegate* delegate) { delegate_ = delegate; }
+  void set_test_interfaces(TestInterfaces* interfaces) {
+    test_interfaces_ = interfaces;
   }
 
  private:
-  // Hide widget_test_client(), the proxy_widget_client() should be used
-  // instead. Which decides to redirect some calls to the widget_test_client()
-  // as needed.
-  using WebWidgetTestProxyBase::widget_test_client;
-
-  TestInterfaces* test_interfaces_;
-  WebTestDelegate* delegate_;
-  blink::WebView* web_view_;
-  blink::WebWidget* web_widget_;
-  blink::WebWidgetClient* base_class_widget_client_;
-  std::unique_ptr<ProxyWebWidgetClient> proxy_widget_client_;
-  std::unique_ptr<WebViewTestClient> view_test_client_;
+  TestInterfaces* test_interfaces_ = nullptr;
+  WebTestDelegate* delegate_ = nullptr;
+  blink::WebView* web_view_ = nullptr;
+  blink::WebWidget* web_widget_ = nullptr;
   std::unique_ptr<AccessibilityController> accessibility_controller_;
   std::unique_ptr<TextInputController> text_input_controller_;
   std::unique_ptr<TestRunnerForSpecificView> view_test_runner_;
@@ -195,11 +162,10 @@
   DISALLOW_COPY_AND_ASSIGN(WebViewTestProxyBase);
 };
 
-// WebViewTestProxy is used during LayoutTests and always instantiated, at time
-// of writing with Base=RenderViewImpl. It does not directly inherit from it for
-// layering purposes.
-// The intent of that class is to wrap RenderViewImpl for tests purposes in
-// order to reduce the amount of test specific code in the production code.
+// WebViewTestProxy is used during LayoutTests. The intent of that class is to
+// wrap RenderViewImpl for tests purposes in order to reduce the amount of test
+// specific code in the production code.
+//
 // WebViewTestProxy is only doing the glue between RenderViewImpl and
 // WebViewTestProxyBase, that means that there is no logic living in this class
 // except deciding which base class should be called (could be both).
@@ -212,13 +178,13 @@
 //    override RenderViewImpl's getter and call a getter from
 //    WebViewTestProxyBase instead. In addition, WebViewTestProxyBase will have
 //    a public setter that could be called from the TestRunner.
-template <class Base>
-class WebViewTestProxy : public Base, public WebViewTestProxyBase {
+class TEST_RUNNER_EXPORT WebViewTestProxy : public content::RenderViewImpl,
+                                            public WebViewTestProxyBase {
  public:
   template <typename... Args>
   explicit WebViewTestProxy(Args&&... args)
-      : Base(std::forward<Args>(args)...),
-        WebViewTestProxyBase(Base::WidgetClient()) {}
+      : RenderViewImpl(std::forward<Args>(args)...) {}
+  void Initialize(WebTestInterfaces* interfaces, WebTestDelegate* delegate);
 
   // WebViewClient implementation.
   blink::WebView* CreateView(blink::WebLocalFrame* creator,
@@ -227,29 +193,18 @@
                              const blink::WebString& frame_name,
                              blink::WebNavigationPolicy policy,
                              bool suppress_opener,
-                             blink::WebSandboxFlags sandbox_flags) override {
-    if (!view_test_client()->CreateView(creator, request, features, frame_name,
-                                        policy, suppress_opener, sandbox_flags))
-      return nullptr;
-    return Base::CreateView(creator, request, features, frame_name, policy,
-                            suppress_opener, sandbox_flags);
-  }
-  void PrintPage(blink::WebLocalFrame* frame) override {
-    view_test_client()->PrintPage(frame);
-  }
-  blink::WebString AcceptLanguages() override {
-    return view_test_client()->AcceptLanguages();
-  }
-  void DidFocus(blink::WebLocalFrame* calling_frame) override {
-    view_test_client()->DidFocus(calling_frame);
-    Base::DidFocus(calling_frame);
-  }
-  blink::WebWidgetClient* WidgetClient() override {
-    return proxy_widget_client();
-  }
+                             blink::WebSandboxFlags sandbox_flags) override;
+  void PrintPage(blink::WebLocalFrame* frame) override;
+  blink::WebString AcceptLanguages() override;
+  void DidFocus(blink::WebLocalFrame* calling_frame) override;
+  blink::WebWidgetClient* WidgetClient() override;
 
  private:
-  virtual ~WebViewTestProxy() {}
+  // RenderViewImpl has no public destructor.
+  ~WebViewTestProxy() override;
+
+  std::unique_ptr<ProxyWebWidgetClient> proxy_widget_client_;
+  std::unique_ptr<WebViewTestClient> view_test_client_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewTestProxy);
 };
diff --git a/content/shell/test_runner/web_widget_test_proxy.cc b/content/shell/test_runner/web_widget_test_proxy.cc
index f50f9c5b..65ce1c1b 100644
--- a/content/shell/test_runner/web_widget_test_proxy.cc
+++ b/content/shell/test_runner/web_widget_test_proxy.cc
@@ -5,15 +5,15 @@
 #include "content/shell/test_runner/web_widget_test_proxy.h"
 
 #include "content/shell/test_runner/event_sender.h"
+#include "content/shell/test_runner/web_test_interfaces.h"
+#include "content/shell/test_runner/web_view_test_proxy.h"
 
 namespace test_runner {
 
 WebWidgetTestProxyBase::WebWidgetTestProxyBase()
-    : web_widget_(nullptr),
-      web_view_test_proxy_base_(nullptr),
-      event_sender_(new EventSender(this)) {}
+    : event_sender_(std::make_unique<EventSender>(this)) {}
 
-WebWidgetTestProxyBase::~WebWidgetTestProxyBase() {}
+WebWidgetTestProxyBase::~WebWidgetTestProxyBase() = default;
 
 void WebWidgetTestProxyBase::Reset() {
   event_sender_->Reset();
@@ -23,4 +23,64 @@
   event_sender_->Install(frame);
 }
 
+void WebWidgetTestProxy::Initialize(
+    WebTestInterfaces* interfaces,
+    blink::WebWidget* web_widget,
+    content::RenderViewImpl* render_view_for_local_root) {
+  // The RenderViewImpl will also be a test proxy type.
+  auto* view_proxy_for_local_root =
+      static_cast<WebViewTestProxy*>(render_view_for_local_root);
+
+  // On WebWidgetTestProxyBase.
+  set_web_widget(web_widget);
+  set_web_view_test_proxy_base(view_proxy_for_local_root);
+  set_widget_test_client(interfaces->CreateWebWidgetTestClient(this));
+}
+
+blink::WebScreenInfo WebWidgetTestProxy::GetScreenInfo() {
+  blink::WebScreenInfo info = RenderWidget::GetScreenInfo();
+  blink::WebScreenInfo test_info = widget_test_client()->GetScreenInfo();
+  if (test_info.orientation_type != blink::kWebScreenOrientationUndefined) {
+    info.orientation_type = test_info.orientation_type;
+    info.orientation_angle = test_info.orientation_angle;
+  }
+  return info;
+}
+
+void WebWidgetTestProxy::ScheduleAnimation() {
+  RenderWidget::ScheduleAnimation();
+  widget_test_client()->ScheduleAnimation();
+}
+
+bool WebWidgetTestProxy::RequestPointerLock() {
+  return widget_test_client()->RequestPointerLock();
+}
+
+void WebWidgetTestProxy::RequestPointerUnlock() {
+  widget_test_client()->RequestPointerUnlock();
+}
+
+bool WebWidgetTestProxy::IsPointerLocked() {
+  return widget_test_client()->IsPointerLocked();
+}
+
+void WebWidgetTestProxy::SetToolTipText(const blink::WebString& text,
+                                        blink::WebTextDirection hint) {
+  RenderWidget::SetToolTipText(text, hint);
+  widget_test_client()->SetToolTipText(text, hint);
+}
+
+void WebWidgetTestProxy::StartDragging(blink::WebReferrerPolicy policy,
+                                       const blink::WebDragData& data,
+                                       blink::WebDragOperationsMask mask,
+                                       const SkBitmap& drag_image,
+                                       const blink::WebPoint& image_offset) {
+  widget_test_client()->StartDragging(policy, data, mask, drag_image,
+                                      image_offset);
+  // Don't forward this call to RenderWidget because we don't want to do a
+  // real drag-and-drop.
+}
+
+WebWidgetTestProxy::~WebWidgetTestProxy() = default;
+
 }  // namespace test_runner
diff --git a/content/shell/test_runner/web_widget_test_proxy.h b/content/shell/test_runner/web_widget_test_proxy.h
index 7976c5e..873ec237 100644
--- a/content/shell/test_runner/web_widget_test_proxy.h
+++ b/content/shell/test_runner/web_widget_test_proxy.h
@@ -9,6 +9,7 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include "content/renderer/render_widget.h"
 #include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_widget_test_client.h"
 #include "third_party/blink/public/web/web_widget_client.h"
@@ -19,9 +20,14 @@
 class WebWidget;
 }
 
+namespace content {
+class RenderViewImpl;
+}
+
 namespace test_runner {
 
 class EventSender;
+class WebTestInterfaces;
 class WebViewTestProxyBase;
 
 class TEST_RUNNER_EXPORT WebWidgetTestProxyBase {
@@ -64,19 +70,18 @@
   }
 
  private:
-  blink::WebWidget* web_widget_;
-  WebViewTestProxyBase* web_view_test_proxy_base_;
+  blink::WebWidget* web_widget_ = nullptr;
+  WebViewTestProxyBase* web_view_test_proxy_base_ = nullptr;
   std::unique_ptr<WebWidgetTestClient> widget_test_client_;
   std::unique_ptr<EventSender> event_sender_;
 
   DISALLOW_COPY_AND_ASSIGN(WebWidgetTestProxyBase);
 };
 
-// WebWidgetTestProxy is used during LayoutTests and always instantiated, at
-// time of writing with Base=RenderWidget. It does not directly inherit from it
-// for layering purposes.
-// The intent of that class is to wrap RenderWidget for tests purposes in
-// order to reduce the amount of test specific code in the production code.
+// WebWidgetTestProxy is used during LayoutTests. The intent of the class is to
+// wrap RenderWidget for tests purposes in order to reduce the amount of test
+// specific code in the production code.
+//
 // WebWidgetTestProxy is only doing the glue between RenderWidget and
 // WebWidgetTestProxyBase, that means that there is no logic living in this
 // class except deciding which base class should be called (could be both).
@@ -89,57 +94,33 @@
 //    override RenderViewImpl's getter and call a getter from
 //    WebWidgetTestProxyBase instead. In addition, WebWidgetTestProxyBase will
 //    have a public setter that could be called from the TestRunner.
-template <class Base>
-class WebWidgetTestProxy : public Base, public WebWidgetTestProxyBase {
+class TEST_RUNNER_EXPORT WebWidgetTestProxy : public content::RenderWidget,
+                                              public WebWidgetTestProxyBase {
  public:
   template <typename... Args>
   explicit WebWidgetTestProxy(Args&&... args)
-      : Base(std::forward<Args>(args)...) {}
+      : RenderWidget(std::forward<Args>(args)...) {}
+  void Initialize(WebTestInterfaces* interfaces,
+                  blink::WebWidget* web_widget,
+                  content::RenderViewImpl* render_view_for_local_root);
 
   // WebWidgetClient implementation.
-  blink::WebLayerTreeView* InitializeLayerTreeView() override {
-    return Base::InitializeLayerTreeView();
-  }
-  blink::WebScreenInfo GetScreenInfo() override {
-    blink::WebScreenInfo info = Base::GetScreenInfo();
-    blink::WebScreenInfo test_info = widget_test_client()->GetScreenInfo();
-    if (test_info.orientation_type != blink::kWebScreenOrientationUndefined) {
-      info.orientation_type = test_info.orientation_type;
-      info.orientation_angle = test_info.orientation_angle;
-    }
-    return info;
-  }
-  void ScheduleAnimation() override {
-    Base::ScheduleAnimation();
-    widget_test_client()->ScheduleAnimation();
-  }
-  bool RequestPointerLock() override {
-    return widget_test_client()->RequestPointerLock();
-  }
-  void RequestPointerUnlock() override {
-    widget_test_client()->RequestPointerUnlock();
-  }
-  bool IsPointerLocked() override {
-    return widget_test_client()->IsPointerLocked();
-  }
+  blink::WebScreenInfo GetScreenInfo() override;
+  void ScheduleAnimation() override;
+  bool RequestPointerLock() override;
+  void RequestPointerUnlock() override;
+  bool IsPointerLocked() override;
   void SetToolTipText(const blink::WebString& text,
-                      blink::WebTextDirection hint) override {
-    Base::SetToolTipText(text, hint);
-    widget_test_client()->SetToolTipText(text, hint);
-  }
+                      blink::WebTextDirection hint) override;
   void StartDragging(blink::WebReferrerPolicy policy,
                      const blink::WebDragData& data,
                      blink::WebDragOperationsMask mask,
                      const SkBitmap& drag_image,
-                     const blink::WebPoint& image_offset) override {
-    widget_test_client()->StartDragging(policy, data, mask, drag_image,
-                                        image_offset);
-    // Don't forward this call to Base because we don't want to do a real
-    // drag-and-drop.
-  }
+                     const blink::WebPoint& image_offset) override;
 
  private:
-  virtual ~WebWidgetTestProxy() {}
+  // RenderWidet does not have a public destructor.
+  ~WebWidgetTestProxy() override;
 
   DISALLOW_COPY_AND_ASSIGN(WebWidgetTestProxy);
 };
diff --git a/content/test/data/download/download-attribute.html b/content/test/data/download/download-attribute.html
index 4fd070d..01f4c96 100644
--- a/content/test/data/download/download-attribute.html
+++ b/content/test/data/download/download-attribute.html
@@ -6,7 +6,8 @@
   var anchorElement = document.querySelector('a[download]');
   url = window.location.href;
   anchorElement.href = url.substr(url.indexOf('=') + 1);
-  anchorElement.click();
+  if (url.indexOf('noclick') == -1)
+    anchorElement.click();
 </script>
 </body>
 </html>
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 4a93632..2678156 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -45,6 +45,10 @@
     self.Fail('Pixel_ScissorTestWithPreserveDrawingBuffer',
         ['android'], bug=521588)
 
+    # Tests crashing on marshmallow bot
+    self.Fail('Pixel_CanvasLowLatency2D', ['android'], bug=865957)
+    self.Fail('Pixel_CanvasUnacceleratedLowLatency2D', ['android'], bug=865957)
+
     # TODO(vmiura) check / generate reference images for Android devices
     self.Fail('Pixel_SolidColorBackground', ['mac', 'android'], bug=624256)
 
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 9c93ff9..37bce60 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -88,13 +88,6 @@
     # ========================
     # Fails on all platforms
 
-    # Need to forbid mipmap generation with this extension.
-    # Uncomment suppressions below when re-enabling. (Or remove them?
-    # Were the failures caused by this gray area in the spec, now
-    # forbidden?)
-    self.Fail('conformance/extensions/ext-sRGB.html',
-        ['linux', 'mac', 'win', 'android'], bug=769989)
-
     # Need to implement new lifetime/deletion semantics.
     self.Fail('conformance/extensions/oes-vertex-array-object.html', bug=739604)
 
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 4702a006..6081a4f 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/lazy_instance.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -44,8 +43,11 @@
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/shell/common/layout_test/layout_test_switches.h"
 #include "content/shell/common/shell_switches.h"
+#include "content/shell/renderer/layout_test/blink_test_runner.h"
+#include "content/shell/renderer/layout_test/layout_test_render_thread_observer.h"
 #include "content/shell/test_runner/test_common.h"
 #include "content/shell/test_runner/web_frame_test_proxy.h"
+#include "content/shell/test_runner/web_test_interfaces.h"
 #include "content/shell/test_runner/web_view_test_proxy.h"
 #include "content/shell/test_runner/web_widget_test_proxy.h"
 #include "gpu/ipc/service/image_transport_surface.h"
@@ -83,25 +85,26 @@
 
 namespace {
 
-base::LazyInstance<ViewProxyCreationCallback>::Leaky
-    g_view_test_proxy_callback = LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<WidgetProxyCreationCallback>::Leaky
-    g_widget_test_proxy_callback = LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<FrameProxyCreationCallback>::Leaky
-    g_frame_test_proxy_callback = LAZY_INSTANCE_INITIALIZER;
-
-using WebViewTestProxyType = test_runner::WebViewTestProxy<RenderViewImpl>;
-using WebWidgetTestProxyType = test_runner::WebWidgetTestProxy<RenderWidget>;
-using WebFrameTestProxyType = test_runner::WebFrameTestProxy<RenderFrameImpl>;
-
 RenderViewImpl* CreateWebViewTestProxy(CompositorDependencies* compositor_deps,
                                        const mojom::CreateViewParams& params) {
-  WebViewTestProxyType* render_view_proxy = new WebViewTestProxyType(
+  test_runner::WebTestInterfaces* interfaces =
+      LayoutTestRenderThreadObserver::GetInstance()->test_interfaces();
+
+  auto* render_view_proxy = new test_runner::WebViewTestProxy(
       compositor_deps, params, base::ThreadTaskRunnerHandle::Get());
-  if (g_view_test_proxy_callback.IsCreated())
-    g_view_test_proxy_callback.Get().Run(render_view_proxy, render_view_proxy);
+
+  BlinkTestRunner* test_runner = new BlinkTestRunner(render_view_proxy);
+  // TODO(lukasza): Using the 1st BlinkTestRunner as the main delegate is wrong,
+  // but it is difficult to change because this behavior has been baked for a
+  // long time into test assumptions (i.e. which PrintMessage gets delivered to
+  // the browser depends on this).
+  static bool first_test_runner = true;
+  if (first_test_runner) {
+    first_test_runner = false;
+    interfaces->SetDelegate(test_runner);
+  }
+
+  render_view_proxy->Initialize(interfaces, test_runner);
   return render_view_proxy;
 }
 
@@ -112,28 +115,44 @@
                                        bool swapped_out,
                                        bool hidden,
                                        bool never_visible) {
-  WebWidgetTestProxyType* render_widget_proxy = new WebWidgetTestProxyType(
+  auto* render_widget_proxy = new test_runner::WebWidgetTestProxy(
       routing_id, compositor_deps, popup_type, screen_info, swapped_out, hidden,
       never_visible, base::ThreadTaskRunnerHandle::Get());
   return render_widget_proxy;
 }
 
 void RenderWidgetInitialized(RenderWidget* render_widget) {
-  WebWidgetTestProxyType* render_widget_proxy =
-      static_cast<WebWidgetTestProxyType*>(render_widget);
-  if (!g_widget_test_proxy_callback.Get().is_null()) {
-    g_widget_test_proxy_callback.Get().Run(render_widget->GetWebWidget(),
-                                           render_widget_proxy);
-  }
+  test_runner::WebTestInterfaces* interfaces =
+      LayoutTestRenderThreadObserver::GetInstance()->test_interfaces();
+
+  blink::WebWidget* web_widget = render_widget->GetWebWidget();
+  // This callback is run only for RenderWidgets that are for a frame.
+  CHECK(web_widget->IsWebFrameWidget());
+  auto* web_frame_widget = static_cast<blink::WebFrameWidget*>(web_widget);
+  // RenderWidgets for a frame will have a local root with a RenderView.
+  blink::WebView* web_view = web_frame_widget->LocalRoot()->View();
+  RenderView* render_view = content::RenderView::FromWebView(web_view);
+  // RenderViews are always RenderViewImpls internally.
+  auto* render_view_impl = static_cast<RenderViewImpl*>(render_view);
+
+  // We are here because CreateWebWidgetTestProxy() was used to make the
+  // RenderWidget, and it creates a WebWidgetTestProxy instead, which is-a
+  // RenderWidget.
+  auto* render_widget_proxy =
+      static_cast<test_runner::WebWidgetTestProxy*>(render_widget);
+  render_widget_proxy->Initialize(interfaces, web_widget, render_view_impl);
 }
 
 RenderFrameImpl* CreateWebFrameTestProxy(RenderFrameImpl::CreateParams params) {
-  WebFrameTestProxyType* render_frame_proxy =
-      new WebFrameTestProxyType(std::move(params));
-  if (g_frame_test_proxy_callback.IsCreated()) {
-    g_frame_test_proxy_callback.Get().Run(render_frame_proxy,
-                                          render_frame_proxy);
-  }
+  test_runner::WebTestInterfaces* interfaces =
+      LayoutTestRenderThreadObserver::GetInstance()->test_interfaces();
+
+  // RenderFrameImpl always has a RenderViewImpl for it.
+  RenderViewImpl* render_view_impl = params.render_view;
+
+  auto* render_frame_proxy =
+      new test_runner::WebFrameTestProxy(std::move(params));
+  render_frame_proxy->Initialize(interfaces, render_view_impl);
   return render_frame_proxy;
 }
 
@@ -158,15 +177,15 @@
 
 test_runner::WebViewTestProxyBase* GetWebViewTestProxyBase(
     RenderView* render_view) {
-  WebViewTestProxyType* render_view_proxy =
-      static_cast<WebViewTestProxyType*>(render_view);
+  auto* render_view_proxy =
+      static_cast<test_runner::WebViewTestProxy*>(render_view);
   return static_cast<test_runner::WebViewTestProxyBase*>(render_view_proxy);
 }
 
 test_runner::WebFrameTestProxyBase* GetWebFrameTestProxyBase(
     RenderFrame* render_frame) {
-  WebFrameTestProxyType* render_frame_proxy =
-      static_cast<WebFrameTestProxyType*>(render_frame);
+  auto* render_frame_proxy =
+      static_cast<test_runner::WebFrameTestProxy*>(render_frame);
   return static_cast<test_runner::WebFrameTestProxyBase*>(render_frame_proxy);
 }
 
@@ -187,8 +206,8 @@
     RenderWidget* render_widget =
         static_cast<RenderFrameImpl*>(local_root)->GetRenderWidget();
     DCHECK(render_widget);
-    WebWidgetTestProxyType* render_widget_proxy =
-        static_cast<WebWidgetTestProxyType*>(render_widget);
+    auto* render_widget_proxy =
+        static_cast<test_runner::WebWidgetTestProxy*>(render_widget);
     auto* web_widget_test_proxy_base =
         static_cast<test_runner::WebWidgetTestProxyBase*>(render_widget_proxy);
     DCHECK(web_widget_test_proxy_base->web_widget()->IsWebFrameWidget());
@@ -205,14 +224,14 @@
   if (widget->IsWebView()) {
     test_runner::WebViewTestProxyBase* render_view_proxy_base =
         web_widget_test_proxy_base->web_view_test_proxy_base();
-    WebViewTestProxyType* render_view_proxy =
-        static_cast<WebViewTestProxyType*>(render_view_proxy_base);
+    auto* render_view_proxy =
+        static_cast<test_runner::WebViewTestProxy*>(render_view_proxy_base);
     RenderViewImpl* render_view_impl =
         static_cast<RenderViewImpl*>(render_view_proxy);
     return render_view_impl->GetWidget();
   } else if (widget->IsWebFrameWidget()) {
-    WebWidgetTestProxyType* render_widget_proxy =
-        static_cast<WebWidgetTestProxyType*>(web_widget_test_proxy_base);
+    auto* render_widget_proxy = static_cast<test_runner::WebWidgetTestProxy*>(
+        web_widget_test_proxy_base);
     return static_cast<RenderWidget*>(render_widget_proxy);
   } else {
     NOTREACHED();
@@ -220,13 +239,7 @@
   }
 }
 
-void EnableWebTestProxyCreation(
-    const ViewProxyCreationCallback& view_proxy_creation_callback,
-    const WidgetProxyCreationCallback& widget_proxy_creation_callback,
-    const FrameProxyCreationCallback& frame_proxy_creation_callback) {
-  g_view_test_proxy_callback.Get() = view_proxy_creation_callback;
-  g_widget_test_proxy_callback.Get() = widget_proxy_creation_callback;
-  g_frame_test_proxy_callback.Get() = frame_proxy_creation_callback;
+void EnableWebTestProxyCreation() {
   RenderViewImpl::InstallCreateHook(CreateWebViewTestProxy);
   RenderWidget::InstallCreateHook(CreateWebWidgetTestProxy,
                                   RenderWidgetInitialized);
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 9265476..2e2a85a 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -285,6 +285,8 @@
       "bluetooth/bluetooth_low_energy_win_fake.h",
       "bluetooth/test/fake_bluetooth_adapter_winrt.cc",
       "bluetooth/test/fake_bluetooth_adapter_winrt.h",
+      "bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.cc",
+      "bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h",
       "bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.cc",
       "bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h",
       "bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.cc",
@@ -293,6 +295,8 @@
       "bluetooth/test/fake_bluetooth_le_advertisement_winrt.h",
       "bluetooth/test/fake_bluetooth_le_device_winrt.cc",
       "bluetooth/test/fake_bluetooth_le_device_winrt.h",
+      "bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.cc",
+      "bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h",
       "bluetooth/test/fake_device_information_winrt.cc",
       "bluetooth/test/fake_device_information_winrt.h",
       "bluetooth/test/fake_gatt_characteristic_winrt.cc",
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index b18288d..4fd41efe 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -103,8 +103,6 @@
     "bluetooth_adapter_win.h",
     "bluetooth_advertisement.cc",
     "bluetooth_advertisement.h",
-    "bluetooth_advertisement_mac.h",
-    "bluetooth_advertisement_mac.mm",
     "bluetooth_channel_mac.h",
     "bluetooth_channel_mac.mm",
     "bluetooth_classic_device_mac.h",
@@ -148,8 +146,6 @@
     "bluetooth_local_gatt_descriptor.h",
     "bluetooth_local_gatt_service.cc",
     "bluetooth_local_gatt_service.h",
-    "bluetooth_low_energy_advertisement_manager_mac.h",
-    "bluetooth_low_energy_advertisement_manager_mac.mm",
     "bluetooth_low_energy_central_manager_delegate.h",
     "bluetooth_low_energy_central_manager_delegate.mm",
     "bluetooth_low_energy_defs_win.cc",
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h
index 3c13e213..2dd3692 100644
--- a/device/bluetooth/bluetooth_adapter_mac.h
+++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -21,7 +21,6 @@
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_discovery_manager_mac.h"
 #include "device/bluetooth/bluetooth_export.h"
-#include "device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h"
 #include "device/bluetooth/bluetooth_low_energy_device_mac.h"
 #include "device/bluetooth/bluetooth_low_energy_discovery_manager_mac.h"
 #include "device/bluetooth/bluetooth_uuid.h"
@@ -31,7 +30,6 @@
 @class NSArray;
 @class NSDate;
 
-@class BluetoothAdvertisementMac;
 @class BluetoothLowEnergyCentralManagerDelegate;
 @class BluetoothLowEnergyPeripheralManagerDelegate;
 
@@ -216,10 +214,6 @@
   // Updates |devices_| when there is a change to the CBCentralManager's state.
   void LowEnergyCentralManagerUpdatedState();
 
-  // Updates |advertisements_| when there is a change to the
-  // CBPeripheralManager's state.
-  void LowEnergyPeripheralManagerUpdatedState();
-
   // Updates |devices_| to include the currently paired devices and notifies
   // observers.
   void AddPairedDevices();
@@ -270,10 +264,6 @@
   std::unique_ptr<BluetoothLowEnergyDiscoveryManagerMac>
       low_energy_discovery_manager_;
 
-  // Advertisement manager for Bluetooth Low Energy.
-  std::unique_ptr<BluetoothLowEnergyAdvertisementManagerMac>
-      low_energy_advertisement_manager_;
-
   // Underlying CoreBluetooth CBCentralManager and its delegate.
   base::scoped_nsobject<CBCentralManager> low_energy_central_manager_;
   base::scoped_nsobject<BluetoothLowEnergyCentralManagerDelegate>
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index 74c3a2b..c9377b7d 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -25,7 +25,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "device/bluetooth/bluetooth_adapter_mac_metrics.h"
-#include "device/bluetooth/bluetooth_advertisement_mac.h"
 #include "device/bluetooth/bluetooth_classic_device_mac.h"
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
@@ -138,18 +137,12 @@
                    queue:dispatch_get_main_queue()]);
     low_energy_discovery_manager_->SetCentralManager(
         low_energy_central_manager_);
-
-    low_energy_advertisement_manager_.reset(
-        new BluetoothLowEnergyAdvertisementManagerMac());
     low_energy_peripheral_manager_delegate_.reset(
         [[BluetoothLowEnergyPeripheralManagerDelegate alloc]
-            initWithAdvertisementManager:low_energy_advertisement_manager_.get()
-                              andAdapter:this]);
+            initWithAdapter:this]);
     low_energy_peripheral_manager_.reset([[CBPeripheralManager alloc]
         initWithDelegate:low_energy_peripheral_manager_delegate_
                    queue:dispatch_get_main_queue()]);
-    low_energy_advertisement_manager_->SetPeripheralManager(
-        low_energy_peripheral_manager_);
   }
   DCHECK(classic_discovery_manager_);
 }
@@ -279,8 +272,8 @@
     std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
     const CreateAdvertisementCallback& callback,
     const AdvertisementErrorCallback& error_callback) {
-  low_energy_advertisement_manager_->RegisterAdvertisement(
-      std::move(advertisement_data), callback, error_callback);
+  NOTIMPLEMENTED();
+  error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
 }
 
 BluetoothLocalGattService* BluetoothAdapterMac::GetGattService(
diff --git a/device/bluetooth/bluetooth_adapter_winrt.cc b/device/bluetooth/bluetooth_adapter_winrt.cc
index 7660b563..25acbc2 100644
--- a/device/bluetooth/bluetooth_adapter_winrt.cc
+++ b/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -6,10 +6,12 @@
 
 #include <windows.foundation.collections.h>
 #include <windows.foundation.h>
+#include <windows.storage.streams.h>
 #include <wrl/event.h>
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -18,6 +20,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -38,18 +41,28 @@
 using ABI::Windows::Devices::Bluetooth::BluetoothAdapter;
 }  // namespace uwp
 using ABI::Windows::Devices::Bluetooth::Advertisement::
+    BluetoothLEAdvertisementDataSection;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
+    BluetoothLEAdvertisementFlags;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
     BluetoothLEAdvertisementWatcherStatus;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     BluetoothLEAdvertisementWatcherStatus_Aborted;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
+    BluetoothLEManufacturerData;
 using ABI::Windows::Devices::Bluetooth::Advertisement::BluetoothLEScanningMode;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     BluetoothLEScanningMode_Active;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     IBluetoothLEAdvertisement;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
+    IBluetoothLEAdvertisementDataSection;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
     IBluetoothLEAdvertisementReceivedEventArgs;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     IBluetoothLEAdvertisementWatcher;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
+    IBluetoothLEManufacturerData;
 using ABI::Windows::Devices::Bluetooth::IBluetoothAdapter;
 using ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics;
 using ABI::Windows::Devices::Enumeration::DeviceInformation;
@@ -67,7 +80,13 @@
 using ABI::Windows::Devices::Radios::RadioState_Off;
 using ABI::Windows::Devices::Radios::RadioState_On;
 using ABI::Windows::Foundation::Collections::IVector;
+using ABI::Windows::Foundation::Collections::IVectorView;
 using ABI::Windows::Foundation::IAsyncOperation;
+using ABI::Windows::Foundation::IReference;
+using ABI::Windows::Storage::Streams::IBuffer;
+using ABI::Windows::Storage::Streams::IDataReader;
+using ABI::Windows::Storage::Streams::IDataReaderStatics;
+using Microsoft::WRL::Callback;
 using Microsoft::WRL::ComPtr;
 
 bool ResolveCoreWinRT() {
@@ -92,39 +111,287 @@
   return "";
 }
 
-base::Optional<BluetoothDevice::UUIDList> ExtractAdvertisedUUIDs(
+template <typename VectorView, typename T>
+bool ToStdVector(VectorView* view, std::vector<T>* vector) {
+  unsigned size;
+  HRESULT hr = view->get_Size(&size);
+  if (FAILED(hr)) {
+    VLOG(2) << "get_Size() failed: " << logging::SystemErrorCodeToString(hr);
+    return false;
+  }
+
+  vector->resize(size);
+  for (size_t i = 0; i < size; ++i) {
+    hr = view->GetAt(i, &(*vector)[i]);
+    DCHECK(SUCCEEDED(hr)) << "GetAt(" << i << ") failed: "
+                          << logging::SystemErrorCodeToString(hr);
+  }
+
+  return true;
+}
+
+base::Optional<std::vector<uint8_t>> ExtractVector(IBuffer* buffer) {
+  ComPtr<IDataReaderStatics> data_reader_statics;
+  HRESULT hr = base::win::GetActivationFactory<
+      IDataReaderStatics, RuntimeClass_Windows_Storage_Streams_DataReader>(
+      &data_reader_statics);
+  if (FAILED(hr)) {
+    VLOG(2) << "Getting DataReaderStatics Activation Factory failed: "
+            << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  ComPtr<IDataReader> data_reader;
+  hr = data_reader_statics->FromBuffer(buffer, &data_reader);
+  if (FAILED(hr)) {
+    VLOG(2) << "FromBuffer() failed: " << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  uint32_t buffer_length;
+  hr = buffer->get_Length(&buffer_length);
+  if (FAILED(hr)) {
+    VLOG(2) << "get_Length() failed: " << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  std::vector<uint8_t> bytes(buffer_length);
+  hr = data_reader->ReadBytes(buffer_length, bytes.data());
+  if (FAILED(hr)) {
+    VLOG(2) << "ReadBytes() failed: " << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  return bytes;
+}
+
+base::Optional<uint8_t> ExtractFlags(IBluetoothLEAdvertisement* advertisement) {
+  if (!advertisement)
+    return base::nullopt;
+
+  ComPtr<IReference<BluetoothLEAdvertisementFlags>> flags_ref;
+  HRESULT hr = advertisement->get_Flags(&flags_ref);
+  if (FAILED(hr)) {
+    VLOG(2) << "get_Flags() failed: " << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  if (!flags_ref) {
+    VLOG(2) << "No advertisement flags found.";
+    return base::nullopt;
+  }
+
+  BluetoothLEAdvertisementFlags flags;
+  hr = flags_ref->get_Value(&flags);
+  if (FAILED(hr)) {
+    VLOG(2) << "get_Value() failed: " << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  return flags;
+}
+
+BluetoothDevice::UUIDList ExtractAdvertisedUUIDs(
     IBluetoothLEAdvertisement* advertisement) {
+  if (!advertisement)
+    return {};
+
   ComPtr<IVector<GUID>> service_uuids;
   HRESULT hr = advertisement->get_ServiceUuids(&service_uuids);
   if (FAILED(hr)) {
     VLOG(2) << "get_ServiceUuids() failed: "
             << logging::SystemErrorCodeToString(hr);
-    return base::nullopt;
+    return {};
   }
 
-  unsigned num_service_uuids;
-  hr = service_uuids->get_Size(&num_service_uuids);
-  if (FAILED(hr)) {
-    VLOG(2) << "get_Size() failed: " << logging::SystemErrorCodeToString(hr);
-    return base::nullopt;
-  }
+  std::vector<GUID> guids;
+  if (!ToStdVector(service_uuids.Get(), &guids))
+    return {};
 
   BluetoothDevice::UUIDList advertised_uuids;
-  for (size_t i = 0; i < num_service_uuids; ++i) {
-    GUID service_uuid;
-    hr = service_uuids->GetAt(i, &service_uuid);
-    if (FAILED(hr)) {
-      VLOG(2) << "GetAt(" << i
-              << ") failed: " << logging::SystemErrorCodeToString(hr);
-      return base::nullopt;
-    }
-
-    advertised_uuids.emplace_back(service_uuid);
-  }
+  advertised_uuids.reserve(guids.size());
+  for (const auto& guid : guids)
+    advertised_uuids.emplace_back(guid);
 
   return advertised_uuids;
 }
 
+// This method populates service data for a particular sized UUID. Given the
+// lack of tailored platform APIs, we need to parse the raw advertisement data
+// sections ourselves. These data sections are effectively a list of blobs,
+// where each blob starts with the corresponding UUID in little endian order,
+// followed by the corresponding service data.
+void PopulateServiceData(
+    BluetoothDevice::ServiceDataMap* service_data,
+    const std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>>&
+        data_sections,
+    size_t num_bytes_uuid) {
+  for (const auto& data_section : data_sections) {
+    ComPtr<IBuffer> buffer;
+    HRESULT hr = data_section->get_Data(&buffer);
+    if (FAILED(hr)) {
+      VLOG(2) << "get_Data() failed: " << logging::SystemErrorCodeToString(hr);
+      continue;
+    }
+
+    auto bytes = ExtractVector(buffer.Get());
+    if (!bytes)
+      continue;
+
+    auto bytes_span = base::make_span(*bytes);
+    if (bytes_span.size() < num_bytes_uuid) {
+      VLOG(2) << "Buffer Length is too small: " << bytes_span.size() << " vs. "
+              << num_bytes_uuid;
+      continue;
+    }
+
+    auto uuid_span = bytes_span.first(num_bytes_uuid);
+    // The UUID is specified in little endian format, thus we reverse the bytes
+    // here.
+    std::vector<uint8_t> uuid_bytes(uuid_span.rbegin(), uuid_span.rend());
+
+    // HexEncode the bytes and add dashes as required.
+    std::string uuid_str;
+    for (char c : base::HexEncode(uuid_bytes.data(), uuid_bytes.size())) {
+      const size_t size = uuid_str.size();
+      if (size == 8 || size == 13 || size == 18 || size == 23)
+        uuid_str.push_back('-');
+      uuid_str.push_back(c);
+    }
+
+    auto service_data_span = bytes_span.subspan(num_bytes_uuid);
+    auto result = service_data->emplace(
+        BluetoothUUID(uuid_str), std::vector<uint8_t>(service_data_span.begin(),
+                                                      service_data_span.end()));
+    // Check that an insertion happened.
+    DCHECK(result.second);
+    // Check that the inserted UUID is valid.
+    DCHECK(result.first->first.IsValid());
+  }
+}
+
+BluetoothDevice::ServiceDataMap ExtractServiceData(
+    IBluetoothLEAdvertisement* advertisement) {
+  BluetoothDevice::ServiceDataMap service_data;
+  if (!advertisement)
+    return service_data;
+
+  static constexpr std::pair<uint8_t, size_t> kServiceDataTypesAndNumBits[] = {
+      {BluetoothDeviceWinrt::k16BitServiceDataSection, 16},
+      {BluetoothDeviceWinrt::k32BitServiceDataSection, 32},
+      {BluetoothDeviceWinrt::k128BitServiceDataSection, 128},
+  };
+
+  for (const auto& data_type_and_num_bits : kServiceDataTypesAndNumBits) {
+    ComPtr<IVectorView<BluetoothLEAdvertisementDataSection*>> data_sections;
+    HRESULT hr = advertisement->GetSectionsByType(data_type_and_num_bits.first,
+                                                  &data_sections);
+    if (FAILED(hr)) {
+      VLOG(2) << "GetSectionsByType() failed: "
+              << logging::SystemErrorCodeToString(hr);
+      continue;
+    }
+
+    std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> vector;
+    if (!ToStdVector(data_sections.Get(), &vector))
+      continue;
+
+    PopulateServiceData(&service_data, vector,
+                        data_type_and_num_bits.second / 8);
+  }
+
+  return service_data;
+}
+
+BluetoothDevice::ManufacturerDataMap ExtractManufacturerData(
+    IBluetoothLEAdvertisement* advertisement) {
+  if (!advertisement)
+    return {};
+
+  ComPtr<IVector<BluetoothLEManufacturerData*>> manufacturer_data_ptr;
+  HRESULT hr = advertisement->get_ManufacturerData(&manufacturer_data_ptr);
+  if (FAILED(hr)) {
+    VLOG(2) << "GetManufacturerData() failed: "
+            << logging::SystemErrorCodeToString(hr);
+    return {};
+  }
+
+  std::vector<ComPtr<IBluetoothLEManufacturerData>> manufacturer_data;
+  if (!ToStdVector(manufacturer_data_ptr.Get(), &manufacturer_data))
+    return {};
+
+  BluetoothDevice::ManufacturerDataMap manufacturer_data_map;
+  for (const auto& manufacturer_datum : manufacturer_data) {
+    uint16_t company_id;
+    hr = manufacturer_datum->get_CompanyId(&company_id);
+    if (FAILED(hr)) {
+      VLOG(2) << "get_CompanyId() failed: "
+              << logging::SystemErrorCodeToString(hr);
+      continue;
+    }
+
+    ComPtr<IBuffer> buffer;
+    hr = manufacturer_datum->get_Data(&buffer);
+    if (FAILED(hr)) {
+      VLOG(2) << "get_Data() failed: " << logging::SystemErrorCodeToString(hr);
+      continue;
+    }
+
+    auto bytes = ExtractVector(buffer.Get());
+    if (!bytes)
+      continue;
+
+    manufacturer_data_map.emplace(company_id, std::move(*bytes));
+  }
+
+  return manufacturer_data_map;
+}
+
+// Similarly to extracting the service data Windows does not provide a specific
+// API to extract the tx power. Thus we also parse the raw data sections here.
+// If present, we expect a single entry for tx power with a blob of size 1 byte.
+base::Optional<int8_t> ExtractTxPower(
+    IBluetoothLEAdvertisement* advertisement) {
+  if (!advertisement)
+    return base::nullopt;
+
+  ComPtr<IVectorView<BluetoothLEAdvertisementDataSection*>> data_sections;
+  HRESULT hr = advertisement->GetSectionsByType(
+      BluetoothDeviceWinrt::kTxPowerLevelDataSection, &data_sections);
+  if (FAILED(hr)) {
+    VLOG(2) << "GetSectionsByType() failed: "
+            << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> vector;
+  if (!ToStdVector(data_sections.Get(), &vector) || vector.empty())
+    return base::nullopt;
+
+  if (vector.size() != 1u) {
+    VLOG(2) << "Unexpected number of data sections: " << vector.size();
+    return base::nullopt;
+  }
+
+  ComPtr<IBuffer> buffer;
+  hr = vector.front()->get_Data(&buffer);
+  if (FAILED(hr)) {
+    VLOG(2) << "get_Data() failed: " << logging::SystemErrorCodeToString(hr);
+    return base::nullopt;
+  }
+
+  auto bytes = ExtractVector(buffer.Get());
+  if (!bytes)
+    return base::nullopt;
+
+  if (bytes->size() != 1) {
+    VLOG(2) << "Unexpected number of bytes: " << bytes->size();
+    return base::nullopt;
+  }
+
+  return bytes->front();
+}
+
 ComPtr<IBluetoothLEAdvertisement> GetAdvertisement(
     IBluetoothLEAdvertisementReceivedEventArgs* received) {
   ComPtr<IBluetoothLEAdvertisement> advertisement;
@@ -157,28 +424,19 @@
 void ExtractAndUpdateAdvertisementData(
     IBluetoothLEAdvertisementReceivedEventArgs* received,
     BluetoothDevice* device) {
-  int16_t rssi;
+  int16_t rssi = 0;
   HRESULT hr = received->get_RawSignalStrengthInDBm(&rssi);
   if (FAILED(hr)) {
     VLOG(2) << "get_RawSignalStrengthInDBm() failed: "
             << logging::SystemErrorCodeToString(hr);
-    return;
   }
 
   ComPtr<IBluetoothLEAdvertisement> advertisement = GetAdvertisement(received);
-  if (!advertisement)
-    return;
-
-  auto advertised_uuids = ExtractAdvertisedUUIDs(advertisement.Get());
-  if (!advertised_uuids)
-    return;
-
-  // TODO(https://crbug.com/821766): Implement extraction of flags, tx power,
-  // service data and manufacturer data.
-  device->UpdateAdvertisementData(
-      rssi, base::nullopt /* flags */, std::move(*advertised_uuids),
-      base::nullopt /* tx_power */, BluetoothDevice::ServiceDataMap(),
-      BluetoothDevice::ManufacturerDataMap());
+  device->UpdateAdvertisementData(rssi, ExtractFlags(advertisement.Get()),
+                                  ExtractAdvertisedUUIDs(advertisement.Get()),
+                                  ExtractTxPower(advertisement.Get()),
+                                  ExtractServiceData(advertisement.Get()),
+                                  ExtractManufacturerData(advertisement.Get()));
 }
 
 }  // namespace
@@ -237,8 +495,7 @@
 }
 
 bool BluetoothAdapterWinrt::IsDiscovering() const {
-  NOTIMPLEMENTED();
-  return false;
+  return num_discovery_sessions_ != 0;
 }
 
 BluetoothAdapter::UUIDList BluetoothAdapterWinrt::GetUUIDs() const {
diff --git a/device/bluetooth/bluetooth_advertisement.h b/device/bluetooth/bluetooth_advertisement.h
index 8cdb02c..d379f72 100644
--- a/device/bluetooth/bluetooth_advertisement.h
+++ b/device/bluetooth/bluetooth_advertisement.h
@@ -38,12 +38,10 @@
                                          // is not registered.
     ERROR_ADVERTISEMENT_INVALID_LENGTH,  // Advertisement is not of a valid
                                          // length.
-    ERROR_STARTING_ADVERTISEMENT,  // Error when starting the advertisement
-                                   // through a platform API.
-    ERROR_RESET_ADVERTISING,       // Error while resetting advertising.
 #if defined(OS_LINUX)
     ERROR_INVALID_ADVERTISEMENT_INTERVAL,  // Advertisement interval specified
                                            // is out of valid range.
+    ERROR_RESET_ADVERTISING,               // Error while resetting advertising.
 #endif
     INVALID_ADVERTISEMENT_ERROR_CODE
   };
diff --git a/device/bluetooth/bluetooth_advertisement_mac.h b/device/bluetooth/bluetooth_advertisement_mac.h
deleted file mode 100644
index 824748bb..0000000
--- a/device/bluetooth/bluetooth_advertisement_mac.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_MAC_H_
-#define DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_MAC_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "dbus/object_path.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_advertisement.h"
-#include "device/bluetooth/bluetooth_export.h"
-
-namespace device {
-
-class BluetoothLowEnergyAdvertisementManagerMac;
-
-// Simple implementation of BluetoothAdvertisement for Mac. The primary logic is
-// currently handled in BluetoothLowEnergyAdvertisementManagerMac.
-class DEVICE_BLUETOOTH_EXPORT BluetoothAdvertisementMac
-    : public BluetoothAdvertisement {
- public:
-  enum Status {
-    WAITING_FOR_PERIPHERAL_MANAGER,
-    ADVERTISEMENT_PENDING,
-    ADVERTISING,
-    ERROR_ADVERTISING,
-    UNREGISTERED,
-  };
-
-  BluetoothAdvertisementMac(
-      std::unique_ptr<BluetoothAdvertisement::UUIDList> service_uuids,
-      const BluetoothAdapter::CreateAdvertisementCallback& callback,
-      const BluetoothAdapter::AdvertisementErrorCallback& error_callback,
-      BluetoothLowEnergyAdvertisementManagerMac* advertisement_manager);
-
-  // BluetoothAdvertisement overrides:
-  void Unregister(const SuccessCallback& success_callback,
-                  const ErrorCallback& error_callback) override;
-
-  Status status() const { return status_; }
-
-  BluetoothAdvertisement::UUIDList service_uuids() { return *service_uuids_; }
-
- private:
-  friend class BluetoothLowEnergyAdvertisementManagerMac;
-
-  ~BluetoothAdvertisementMac() override;
-
-  // Called by BluetoothLowEnergyAdvertisementManagerMac.
-  void OnAdvertisementPending();
-  void OnAdvertisementError(BluetoothAdvertisement::ErrorCode error_code);
-  void OnAdvertisementSuccess();
-
-  BluetoothAdapter::CreateAdvertisementCallback success_callback() {
-    return success_callback_;
-  }
-
-  std::unique_ptr<BluetoothAdvertisement::UUIDList> service_uuids_;
-  BluetoothAdapter::CreateAdvertisementCallback success_callback_;
-  BluetoothAdapter::AdvertisementErrorCallback error_callback_;
-  BluetoothLowEnergyAdvertisementManagerMac* advertisement_manager_;
-  Status status_;
-
-  DISALLOW_COPY_AND_ASSIGN(BluetoothAdvertisementMac);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_BLUETOOTH_BLUETOOTH_ADVERTISEMENT_MAC_H_
diff --git a/device/bluetooth/bluetooth_advertisement_mac.mm b/device/bluetooth/bluetooth_advertisement_mac.mm
deleted file mode 100644
index 62e8b9a3..0000000
--- a/device/bluetooth/bluetooth_advertisement_mac.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/bluetooth/bluetooth_advertisement_mac.h"
-
-#import <IOBluetooth/objc/IOBluetoothDevice.h>
-#import <IOBluetooth/objc/IOBluetoothHostController.h>
-
-#include "device/bluetooth/bluetooth_adapter_mac.h"
-
-namespace device {
-
-BluetoothAdvertisementMac::BluetoothAdvertisementMac(
-    std::unique_ptr<BluetoothAdvertisement::UUIDList> service_uuids,
-    const BluetoothAdapter::CreateAdvertisementCallback& success_callback,
-    const BluetoothAdapter::AdvertisementErrorCallback& error_callback,
-    BluetoothLowEnergyAdvertisementManagerMac* advertisement_manager)
-    : service_uuids_(std::move(service_uuids)),
-      success_callback_(success_callback),
-      error_callback_(error_callback),
-      advertisement_manager_(advertisement_manager),
-      status_(BluetoothAdvertisementMac::WAITING_FOR_PERIPHERAL_MANAGER) {}
-
-void BluetoothAdvertisementMac::Unregister(
-    const SuccessCallback& success_callback,
-    const ErrorCallback& error_callback) {
-  if (status_ == Status::UNREGISTERED) {
-    success_callback.Run();
-    return;
-  }
-
-  status_ = Status::UNREGISTERED;
-  advertisement_manager_->UnregisterAdvertisement(this, success_callback,
-                                                  error_callback);
-}
-
-BluetoothAdvertisementMac::~BluetoothAdvertisementMac() {
-  // This object should be owned by BluetoothLowEnergyAdvertisementManagerMac,
-  // and will be cleaned up there.
-}
-
-void BluetoothAdvertisementMac::OnAdvertisementPending() {
-  status_ = Status::ADVERTISEMENT_PENDING;
-}
-
-void BluetoothAdvertisementMac::OnAdvertisementError(
-    BluetoothAdvertisement::ErrorCode error_code) {
-  status_ = Status::ERROR_ADVERTISING;
-  error_callback_.Run(error_code);
-}
-
-void BluetoothAdvertisementMac::OnAdvertisementSuccess() {
-  status_ = Status::ADVERTISING;
-  success_callback_.Run(this);
-}
-
-}  // namespace device
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index e0044d6..3dc3f99d 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -356,8 +356,7 @@
   // Returns Advertising Data Flags.
   // Returns cached value if the adapter is not discovering.
   //
-  // TODO(crbug.com/661814) Support this on platforms that don't use BlueZ.
-  // Only Chrome OS supports this now. Upstream BlueZ has this feature
+  // Only Chrome OS and WinRT support this now. Upstream BlueZ has this feature
   // as experimental. This method returns base::nullopt on platforms that don't
   // support this feature.
   base::Optional<uint8_t> GetAdvertisingDataFlags() const;
diff --git a/device/bluetooth/bluetooth_device_unittest.cc b/device/bluetooth/bluetooth_device_unittest.cc
index 83924cb6..b1f61fa 100644
--- a/device/bluetooth/bluetooth_device_unittest.cc
+++ b/device/bluetooth/bluetooth_device_unittest.cc
@@ -151,7 +151,11 @@
 #define MAYBE_GetServiceDataUUIDs_GetServiceDataForUUID \
   DISABLED_GetServiceDataUUIDs_GetServiceDataForUUID
 #endif
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrtOnly, GetServiceDataUUIDs_GetServiceDataForUUID) {
+#else
 TEST_F(BluetoothTest, MAYBE_GetServiceDataUUIDs_GetServiceDataForUUID) {
+#endif
   if (!PlatformSupportsLowEnergy()) {
     LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
     return;
@@ -166,6 +170,7 @@
 
   // Receive Advertisement with empty service data.
   BluetoothDevice* device1 = SimulateLowEnergyDevice(4);
+  EXPECT_FALSE(device1->GetAdvertisingDataFlags().has_value());
   EXPECT_TRUE(device1->GetServiceData().empty());
   EXPECT_TRUE(device1->GetServiceDataUUIDs().empty());
   EXPECT_TRUE(device1->GetManufacturerData().empty());
@@ -173,6 +178,10 @@
   // Receive Advertisement with service data.
   BluetoothDevice* device2 = SimulateLowEnergyDevice(1);
 
+#if defined(OS_WIN)
+  EXPECT_TRUE(device2->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x04, device2->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(ServiceDataMap({{BluetoothUUID(kTestUUIDHeartRate), {1}}}),
             device2->GetServiceData());
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDHeartRate)}),
@@ -181,7 +190,7 @@
             *device2->GetServiceDataForUUID(BluetoothUUID(kTestUUIDHeartRate)));
   EXPECT_EQ(std::vector<uint8_t>({1, 2, 3, 4}),
             *device2->GetManufacturerDataForID(kTestManufacturerId));
-  // Receive Advertisement with no service and manufacturer data.
+  // Receive Advertisement with no flags and no service and manufacturer data.
   SimulateLowEnergyDevice(3);
 
 // TODO(crbug.com/707039): Remove #if once the BlueZ caching behavior is
@@ -198,6 +207,7 @@
   EXPECT_EQ(std::vector<uint8_t>({1}),
             *device2->GetServiceDataForUUID(BluetoothUUID(kTestUUIDHeartRate)));
 #else
+  EXPECT_FALSE(device2->GetAdvertisingDataFlags().has_value());
   EXPECT_TRUE(device2->GetServiceData().empty());
   EXPECT_TRUE(device2->GetServiceDataUUIDs().empty());
   EXPECT_TRUE(device2->GetManufacturerData().empty());
@@ -208,6 +218,10 @@
   // Receive Advertisement with new service data and empty manufacturer data.
   SimulateLowEnergyDevice(2);
 
+#if defined(OS_WIN)
+  EXPECT_TRUE(device2->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x05, device2->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(ServiceDataMap(
                 {{BluetoothUUID(kTestUUIDHeartRate), std::vector<uint8_t>({})},
                  {BluetoothUUID(kTestUUIDImmediateAlert), {0, 2}}}),
@@ -229,9 +243,11 @@
   // Stop discovery.
   discovery_sessions_[0]->Stop(GetCallback(Call::EXPECTED),
                                GetErrorCallback(Call::NOT_EXPECTED));
+  base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(adapter_->IsDiscovering());
   ASSERT_FALSE(discovery_sessions_[0]->IsActive());
 
+  EXPECT_FALSE(device2->GetAdvertisingDataFlags().has_value());
   EXPECT_TRUE(device2->GetServiceData().empty());
   EXPECT_TRUE(device2->GetServiceDataUUIDs().empty());
   EXPECT_EQ(nullptr,
@@ -248,7 +264,11 @@
 #endif
 // Tests that the Advertisement Data fields are correctly updated during
 // discovery.
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrtOnly, AdvertisementData_Discovery) {
+#else
 TEST_F(BluetoothTest, MAYBE_AdvertisementData_Discovery) {
+#endif
   if (!PlatformSupportsLowEnergy()) {
     LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
     return;
@@ -259,6 +279,7 @@
   // Start Discovery Session and receive Advertisement, should
   // not notify of device changed because the device is new.
   //  - GetInquiryRSSI: Should return the packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return advertised flags.
   //  - GetUUIDs: Should return Advertised UUIDs.
   //  - GetServiceData: Should return advertised Service Data.
   //  - GetInquiryTxPower: Should return the packet's advertised Tx Power.
@@ -268,6 +289,10 @@
   EXPECT_EQ(0, observer.device_changed_count());
 
   EXPECT_EQ(ToInt8(TestRSSI::LOWEST), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x04, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDGenericAccess),
                      BluetoothUUID(kTestUUIDGenericAttribute)}),
             device->GetUUIDs());
@@ -277,9 +302,10 @@
             device->GetManufacturerData());
   EXPECT_EQ(ToInt8(TestTxPower::LOWEST), device->GetInquiryTxPower().value());
 
-  // Receive Advertisement with no UUIDs, Service Data, or Tx Power, should
-  // notify device changed.
+  // Receive Advertisement with no flags, no UUIDs, Service Data, or Tx Power,
+  // should notify device changed.
   //  - GetInquiryRSSI: Should return packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return nullopt because of no flags.
   //  - GetUUIDs: Should return no UUIDs.
   //  - GetServiceData: Should return empty map.
   //  - GetInquiryTxPower: Should return nullopt because of no Tx Power.
@@ -287,6 +313,7 @@
   EXPECT_EQ(1, observer.device_changed_count());
 
   EXPECT_EQ(ToInt8(TestRSSI::LOW), device->GetInquiryRSSI().value());
+  EXPECT_FALSE(device->GetAdvertisingDataFlags().has_value());
   EXPECT_TRUE(device->GetUUIDs().empty());
   EXPECT_TRUE(device->GetServiceData().empty());
   EXPECT_TRUE(device->GetManufacturerData().empty());
@@ -295,6 +322,7 @@
   // Receive Advertisement with different UUIDs, Service Data, and Tx Power,
   // should notify device changed.
   //  - GetInquiryRSSI: Should return last packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return last advertised flags.
   //  - GetUUIDs: Should return latest Advertised UUIDs.
   //  - GetServiceData: Should return last advertised Service Data.
   //  - GetInquiryTxPower: Should return last advertised Tx Power.
@@ -302,6 +330,10 @@
   EXPECT_EQ(2, observer.device_changed_count());
 
   EXPECT_EQ(ToInt8(TestRSSI::LOWER), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x05, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDImmediateAlert),
                      BluetoothUUID(kTestUUIDLinkLoss)}),
             device->GetUUIDs());
@@ -317,6 +349,7 @@
   // Stop discovery session, should notify of device changed.
   //  - GetInquiryRSSI: Should return nullopt because we are no longer
   //    discovering.
+  //  - GetAdvertisingDataFlags: Should return no flags.
   //  - GetUUIDs: Should not return any UUIDs.
   //  - GetServiceData: Should return empty map.
   //  - GetMAnufacturerData: Should return empty map.
@@ -324,12 +357,14 @@
   //    discovering.
   discovery_sessions_[0]->Stop(GetCallback(Call::EXPECTED),
                                GetErrorCallback(Call::NOT_EXPECTED));
+  base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(adapter_->IsDiscovering());
   ASSERT_FALSE(discovery_sessions_[0]->IsActive());
 
   EXPECT_EQ(3, observer.device_changed_count());
 
   EXPECT_FALSE(device->GetInquiryRSSI());
+  EXPECT_FALSE(device->GetAdvertisingDataFlags().has_value());
   EXPECT_TRUE(device->GetUUIDs().empty());
   EXPECT_TRUE(device->GetServiceData().empty());
   EXPECT_TRUE(device->GetManufacturerData().empty());
@@ -338,6 +373,7 @@
   // Discover the device again with different UUIDs, should notify of device
   // changed.
   //  - GetInquiryRSSI: Should return last packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return last advertised flags.
   //  - GetUUIDs: Should return only the latest Advertised UUIDs.
   //  - GetServiceData: Should return last advertise Service Data.
   //  - GetInquiryTxPower: Should return last advertised Tx Power.
@@ -347,6 +383,10 @@
   EXPECT_EQ(4, observer.device_changed_count());
 
   EXPECT_EQ(ToInt8(TestRSSI::LOWEST), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x04, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDGenericAccess),
                      BluetoothUUID(kTestUUIDGenericAttribute)}),
             device->GetUUIDs());
@@ -558,7 +598,11 @@
 #endif
 // Tests Advertisement Data is updated correctly when we start discovery
 // during a connection.
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrtOnly, AdvertisementData_DiscoveryDuringConnection) {
+#else
 TEST_F(BluetoothTest, MAYBE_AdvertisementData_DiscoveryDuringConnection) {
+#endif
   if (!PlatformSupportsLowEnergy()) {
     LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
     return;
@@ -575,6 +619,7 @@
             device->GetUUIDs());
   discovery_sessions_[0]->Stop(GetCallback(Call::EXPECTED),
                                GetErrorCallback(Call::NOT_EXPECTED));
+  base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(adapter_->IsDiscovering());
   ASSERT_FALSE(discovery_sessions_[0]->IsActive());
   ASSERT_EQ(0u, device->GetUUIDs().size());
@@ -592,6 +637,7 @@
   // Start Discovery and receive advertisement during connection,
   // should notify of device changed.
   //  - GetInquiryRSSI: Should return the packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return last advertised flags.
   //  - GetUUIDs: Should return only Advertised UUIDs since services haven't
   //    been discovered yet.
   //  - GetServiceData: Should return last advertised Service Data.
@@ -607,10 +653,12 @@
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDGenericAccess),
                      BluetoothUUID(kTestUUIDGenericAttribute)}),
             device->GetUUIDs());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x04, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(ServiceDataMap({{BluetoothUUID(kTestUUIDHeartRate), {1}}}),
             device->GetServiceData());
-#endif  // defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ToInt8(TestTxPower::LOWEST), device->GetInquiryTxPower().value());
 
   // Discover services, should notify of device changed.
@@ -629,6 +677,7 @@
 
   // Receive advertisement again, notify of device changed.
   //  - GetInquiryRSSI: Should return last packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return last advertised flags.
   //  - GetUUIDs: Should return only new Advertised UUIDs and Service UUIDs.
   //  - GetServiceData: Should return last advertised Service Data.
   //  - GetInquiryTxPower: Should return the last packet's advertised Tx Power.
@@ -636,21 +685,25 @@
 
   EXPECT_EQ(3, observer.device_changed_count());
   EXPECT_EQ(ToInt8(TestRSSI::LOWER), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x05, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDLinkLoss),
                      BluetoothUUID(kTestUUIDImmediateAlert),
                      BluetoothUUID(kTestUUIDHeartRate)}),
             device->GetUUIDs());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ServiceDataMap(
                 {{BluetoothUUID(kTestUUIDHeartRate), std::vector<uint8_t>({})},
                  {BluetoothUUID(kTestUUIDImmediateAlert), {0, 2}}}),
             device->GetServiceData());
-#endif  // defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ToInt8(TestTxPower::LOWER), device->GetInquiryTxPower().value());
 
   // Stop discovery session, should notify of device changed.
   //  - GetInquiryRSSI: Should return nullopt because we are no longer
   //    discovering.
+  //  - GetAdvertisingDataFlags: Should return no flags since we are no longer
+  //    discovering.
   //  - GetUUIDs: Should only return Service UUIDs.
   //  - GetServiceData: Should return an empty map since we are no longer
   //    discovering.
@@ -658,15 +711,15 @@
   //    discovering.
   discovery_sessions_[0]->Stop(GetCallback(Call::EXPECTED),
                                GetErrorCallback(Call::NOT_EXPECTED));
+  base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(adapter_->IsDiscovering());
   ASSERT_FALSE(discovery_sessions_[0]->IsActive());
 
   EXPECT_EQ(4, observer.device_changed_count());
   EXPECT_FALSE(device->GetInquiryRSSI());
+  EXPECT_FALSE(device->GetAdvertisingDataFlags().has_value());
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDHeartRate)}), device->GetUUIDs());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ServiceDataMap(), device->GetServiceData());
-#endif  // defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_FALSE(device->GetInquiryTxPower());
 
   // Disconnect device, should notify of device changed.
@@ -688,7 +741,11 @@
 #define MAYBE_AdvertisementData_ConnectionDuringDiscovery \
   DISABLED_AdvertisementData_ConnectionDuringDiscovery
 #endif
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrtOnly, AdvertisementData_ConnectionDuringDiscovery) {
+#else
 TEST_F(BluetoothTest, MAYBE_AdvertisementData_ConnectionDuringDiscovery) {
+#endif
   // Tests that the Advertisement Data is correctly updated when
   // the device connects during discovery.
   if (!PlatformSupportsLowEnergy()) {
@@ -702,6 +759,7 @@
   // Start discovery session and receive and advertisement. No device changed
   // notification because it's a new device.
   //  - GetInquiryRSSI: Should return the packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return advertised flags.
   //  - GetUUIDs: Should return Advertised UUIDs.
   //  - GetServiceData: Should return advertised Service Data.
   //  - GetInquiryTxPower: Should return the packet's advertised Tx Power.
@@ -712,13 +770,15 @@
 
   EXPECT_EQ(0, observer.device_changed_count());
   EXPECT_EQ(ToInt8(TestRSSI::LOWEST), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x04, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDGenericAccess),
                      BluetoothUUID(kTestUUIDGenericAttribute)}),
             device->GetUUIDs());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ServiceDataMap({{BluetoothUUID(kTestUUIDHeartRate), {1}}}),
             device->GetServiceData());
-#endif  // defined(OS_MACOSX)
   EXPECT_EQ(ToInt8(TestTxPower::LOWEST), device->GetInquiryTxPower().value());
 
   // Connect, should notify of device changed.
@@ -736,6 +796,7 @@
 
   // Receive Advertisement with new UUIDs, should notify of device changed.
   //  - GetInquiryRSSI: Should return the packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return advertised flags.
   //  - GetUUIDs: Should return new Advertised UUIDs.
   //  - GetServiceData: Should return new advertised Service Data.
   //  - GetInquiryTxPower: Should return the packet's advertised Tx Power.
@@ -743,15 +804,17 @@
 
   EXPECT_EQ(1, observer.device_changed_count());
   EXPECT_EQ(ToInt8(TestRSSI::LOWER), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x05, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDLinkLoss),
                      BluetoothUUID(kTestUUIDImmediateAlert)}),
             device->GetUUIDs());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ServiceDataMap(
                 {{BluetoothUUID(kTestUUIDHeartRate), std::vector<uint8_t>({})},
                  {BluetoothUUID(kTestUUIDImmediateAlert), {0, 2}}}),
             device->GetServiceData());
-#endif  // defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ToInt8(TestTxPower::LOWER), device->GetInquiryTxPower().value());
 
   // Discover Services, should notify of device changed.
@@ -770,6 +833,7 @@
 
   // Disconnect, should notify of device changed.
   //  - GetInquiryRSSI: Should return last packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return same advertised flags.
   //  - GetUUIDs: Should return only Advertised UUIDs.
   //  - GetServiceData: Should still return same advertised Service Data.
   //  - GetInquiryTxPower: Should return the last packet's advertised Tx Power.
@@ -780,20 +844,23 @@
 
   EXPECT_EQ(3, observer.device_changed_count());
   EXPECT_EQ(ToInt8(TestRSSI::LOWER), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x05, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDLinkLoss),
                      BluetoothUUID(kTestUUIDImmediateAlert)}),
             device->GetUUIDs());
 
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ServiceDataMap(
                 {{BluetoothUUID(kTestUUIDHeartRate), std::vector<uint8_t>({})},
                  {BluetoothUUID(kTestUUIDImmediateAlert), {0, 2}}}),
             device->GetServiceData());
-#endif  // defined(OS_MACOSX)
   EXPECT_EQ(ToInt8(TestTxPower::LOWER), device->GetInquiryTxPower().value());
 
   // Receive Advertisement with new UUIDs, should notify of device changed.
   //  - GetInquiryRSSI: Should return last packet's rssi.
+  //  - GetAdvertisingDataFlags: Should return the new advertised flags.
   //  - GetUUIDs: Should return only new Advertised UUIDs.
   //  - GetServiceData: Should return only new advertised Service Data.
   //  - GetInquiryTxPower: Should return the last packet's advertised Tx Power.
@@ -801,18 +868,22 @@
 
   EXPECT_EQ(4, observer.device_changed_count());
   EXPECT_EQ(ToInt8(TestRSSI::LOWEST), device->GetInquiryRSSI().value());
+#if defined(OS_WIN)
+  EXPECT_TRUE(device->GetAdvertisingDataFlags().has_value());
+  EXPECT_EQ(0x04, device->GetAdvertisingDataFlags().value());
+#endif
   EXPECT_EQ(UUIDSet({BluetoothUUID(kTestUUIDGenericAccess),
                      BluetoothUUID(kTestUUIDGenericAttribute)}),
             device->GetUUIDs());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ServiceDataMap({{BluetoothUUID(kTestUUIDHeartRate), {1}}}),
             device->GetServiceData());
-#endif  // defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_EQ(ToInt8(TestTxPower::LOWEST), device->GetInquiryTxPower().value());
 
   // Stop discovery session, should notify of device changed.
   //  - GetInquiryRSSI: Should return nullopt because we are no longer
   //    discovering.
+  //  - GetAdvertisingDataFlags: Should return no advertised flags since we are
+  //    no longer discovering.
   //  - GetUUIDs: Should return no UUIDs.
   //  - GetServiceData: Should return no UUIDs since we are no longer
   //    discovering.
@@ -820,13 +891,13 @@
   //    discovering.
   discovery_sessions_[0]->Stop(GetCallback(Call::EXPECTED),
                                GetErrorCallback(Call::NOT_EXPECTED));
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(5, observer.device_changed_count());
 
   EXPECT_FALSE(device->GetInquiryRSSI());
+  EXPECT_FALSE(device->GetAdvertisingDataFlags().has_value());
   EXPECT_TRUE(device->GetUUIDs().empty());
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
   EXPECT_TRUE(device->GetServiceData().empty());
-#endif  // defined(OS_MACOSX)  || defined(OS_ANDROID)
   EXPECT_FALSE(device->GetInquiryTxPower());
 }
 
diff --git a/device/bluetooth/bluetooth_device_winrt.h b/device/bluetooth/bluetooth_device_winrt.h
index 2b7b43789..1f00c86 100644
--- a/device/bluetooth/bluetooth_device_winrt.h
+++ b/device/bluetooth/bluetooth_device_winrt.h
@@ -28,6 +28,14 @@
 
 class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
  public:
+  // Constants required to extract the tx power level and service data from the
+  // raw advertisementment data. Reference:
+  // https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
+  static constexpr uint8_t kTxPowerLevelDataSection = 0x0A;
+  static constexpr uint8_t k16BitServiceDataSection = 0x16;
+  static constexpr uint8_t k32BitServiceDataSection = 0x20;
+  static constexpr uint8_t k128BitServiceDataSection = 0x21;
+
   BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
                        uint64_t raw_address,
                        base::Optional<std::string> local_name);
diff --git a/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h b/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h
deleted file mode 100644
index f7c7229..0000000
--- a/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_ADVERTISEMENT_MANAGER_MAC_H_
-#define DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_ADVERTISEMENT_MANAGER_MAC_H_
-
-#include "base/mac/sdk_forward_declarations.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "device/bluetooth/bluetooth_advertisement_mac.h"
-
-namespace device {
-
-// Class used by BluetoothAdapterMac to manage LE advertisements.
-// Currently, only a single concurrent BLE advertisement is supported. Future
-// work will add support for multiple concurrent and rotating advertisements.
-class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyAdvertisementManagerMac {
- public:
-  BluetoothLowEnergyAdvertisementManagerMac();
-  ~BluetoothLowEnergyAdvertisementManagerMac();
-
-  // Registers a new BLE advertisement.
-  void RegisterAdvertisement(
-      std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
-      const BluetoothAdapter::CreateAdvertisementCallback& callback,
-      const BluetoothAdapter::AdvertisementErrorCallback& error_callback);
-
-  // Unregisters an existing BLE advertisement.
-  void UnregisterAdvertisement(
-      BluetoothAdvertisementMac* advertisement,
-      const BluetoothAdvertisementMac::SuccessCallback& success_callback,
-      const BluetoothAdvertisementMac::ErrorCallback& error_callback);
-
-  // Tries to start the active advertisement if the adapter is ready.
-  void TryStartAdvertisement();
-
-  // Called when advertisement starts with success or failure.
-  void DidStartAdvertising(NSError* error);
-
-  // Sets the CBPeripheralManager instance.
-  void SetPeripheralManager(CBPeripheralManager* peripheral_manager);
-
- private:
-  CBPeripheralManager* peripheral_manager_;
-
-  scoped_refptr<BluetoothAdvertisementMac> active_advertisement_;
-
-  DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyAdvertisementManagerMac);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_ADVERTISEMENT_MANAGER_MAC_H_
diff --git a/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm b/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm
deleted file mode 100644
index 1502317..0000000
--- a/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h"
-
-#include "base/strings/sys_string_conversions.h"
-#include "device/bluetooth/bluetooth_advertisement.h"
-
-namespace device {
-
-BluetoothLowEnergyAdvertisementManagerMac::
-    BluetoothLowEnergyAdvertisementManagerMac()
-    : active_advertisement_(nullptr) {}
-
-BluetoothLowEnergyAdvertisementManagerMac::
-    ~BluetoothLowEnergyAdvertisementManagerMac() {}
-
-void BluetoothLowEnergyAdvertisementManagerMac::TryStartAdvertisement() {
-  if (!active_advertisement_ ||
-      active_advertisement_->status() !=
-          BluetoothAdvertisementMac::WAITING_FOR_PERIPHERAL_MANAGER) {
-    return;
-  }
-
-  if ([peripheral_manager_ state] < CBPeripheralManagerStatePoweredOn) {
-    return;
-  }
-
-  NSMutableArray* service_uuid_array = [[NSMutableArray alloc] init];
-  for (const std::string& service_uuid :
-       active_advertisement_->service_uuids()) {
-    NSString* uuid_string =
-        [NSString stringWithCString:service_uuid.c_str()
-                           encoding:[NSString defaultCStringEncoding]];
-    [service_uuid_array addObject:[CBUUID UUIDWithString:uuid_string]];
-  }
-
-  active_advertisement_->OnAdvertisementPending();
-  [peripheral_manager_ startAdvertising:@{
-    CBAdvertisementDataServiceUUIDsKey : service_uuid_array
-  }];
-}
-
-void BluetoothLowEnergyAdvertisementManagerMac::RegisterAdvertisement(
-    std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
-    const BluetoothAdapter::CreateAdvertisementCallback& callback,
-    const BluetoothAdapter::AdvertisementErrorCallback& error_callback) {
-  std::unique_ptr<BluetoothAdvertisement::UUIDList> service_uuids =
-      advertisement_data->service_uuids();
-  if (!service_uuids || advertisement_data->manufacturer_data() ||
-      advertisement_data->solicit_uuids() ||
-      advertisement_data->service_data()) {
-    LOG(ERROR) << "macOS only supports advertising service UUIDs.";
-    error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
-    return;
-  }
-
-  if (active_advertisement_ && active_advertisement_->status() !=
-                                   BluetoothAdvertisementMac::UNREGISTERED) {
-    LOG(ERROR) << "Only one active BLE advertisement is currently supported.";
-    error_callback.Run(
-        BluetoothAdvertisement::ERROR_ADVERTISEMENT_ALREADY_EXISTS);
-    return;
-  }
-
-  active_advertisement_ = new BluetoothAdvertisementMac(
-      std::move(service_uuids), callback, error_callback, this);
-  TryStartAdvertisement();
-}
-
-void BluetoothLowEnergyAdvertisementManagerMac::UnregisterAdvertisement(
-    BluetoothAdvertisementMac* advertisement,
-    const BluetoothAdvertisement::SuccessCallback& success_callback,
-    const BluetoothAdvertisement::ErrorCallback& error_callback) {
-  if (advertisement != active_advertisement_.get()) {
-    LOG(ERROR) << "Only one active advertisement is supported currently.";
-    error_callback.Run(BluetoothAdvertisement::ERROR_RESET_ADVERTISING);
-    return;
-  }
-
-  active_advertisement_ = nullptr;
-  [peripheral_manager_ stopAdvertising];
-}
-
-void BluetoothLowEnergyAdvertisementManagerMac::DidStartAdvertising(
-    NSError* error) {
-  if (!active_advertisement_ ||
-      active_advertisement_->status() !=
-          BluetoothAdvertisementMac::ADVERTISEMENT_PENDING) {
-    return;
-  }
-
-  if (error != nil) {
-    LOG(ERROR) << "Error advertising: "
-               << base::SysNSStringToUTF8(error.localizedDescription);
-    active_advertisement_->OnAdvertisementError(
-        BluetoothAdvertisement::ERROR_STARTING_ADVERTISEMENT);
-    return;
-  }
-
-  active_advertisement_->OnAdvertisementSuccess();
-}
-
-void BluetoothLowEnergyAdvertisementManagerMac::SetPeripheralManager(
-    CBPeripheralManager* peripheral_manager) {
-  peripheral_manager_ = peripheral_manager;
-}
-
-}  // device
diff --git a/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.h b/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.h
index 5c931364..7e0b612 100644
--- a/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.h
+++ b/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.h
@@ -17,7 +17,6 @@
 
 namespace device {
 class BluetoothAdapterMac;
-class BluetoothLowEnergyAdvertisementManagerMac;
 class BluetoothLowEnergyPeripheralManagerBridge;
 }  // namespace device
 
@@ -26,10 +25,7 @@
   std::unique_ptr<device::BluetoothLowEnergyPeripheralManagerBridge> bridge_;
 }
 
-- (id)initWithAdvertisementManager:
-          (device::BluetoothLowEnergyAdvertisementManagerMac*)
-              advertisement_manager
-                        andAdapter:(device::BluetoothAdapterMac*)adapter;
+- (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter;
 
 @end
 
diff --git a/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.mm b/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.mm
index 066b292..a2866d9 100644
--- a/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.mm
+++ b/device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.mm
@@ -12,17 +12,17 @@
 // CBPeripheralManagerDelegate class and our BluetoothAdapterMac classes.
 class BluetoothLowEnergyPeripheralManagerBridge {
  public:
-  BluetoothLowEnergyPeripheralManagerBridge(
-      BluetoothLowEnergyAdvertisementManagerMac* advertisement_manager,
-      BluetoothAdapterMac* adapter)
-      : advertisement_manager_(advertisement_manager), adapter_(adapter) {}
+  BluetoothLowEnergyPeripheralManagerBridge(BluetoothAdapterMac* adapter)
+      : adapter_(adapter) {}
 
   ~BluetoothLowEnergyPeripheralManagerBridge() {}
 
-  void UpdatedState() { advertisement_manager_->TryStartAdvertisement(); }
+  void UpdatedState() {
+    // TODO(tengs): Hook this up to BluetoothAdapterMac.
+  }
 
   void DidStartAdvertising(NSError* error) {
-    advertisement_manager_->DidStartAdvertising(error);
+    // TODO(tengs): Hook this up to BluetoothAdapterMac.
   }
 
   CBPeripheralManager* GetPeripheralManager() {
@@ -30,7 +30,6 @@
   }
 
  private:
-  BluetoothLowEnergyAdvertisementManagerMac* advertisement_manager_;
   BluetoothAdapterMac* adapter_;
 };
 
@@ -38,13 +37,10 @@
 
 @implementation BluetoothLowEnergyPeripheralManagerDelegate
 
-- (id)initWithAdvertisementManager:
-          (device::BluetoothLowEnergyAdvertisementManagerMac*)
-              advertisement_manager
-                        andAdapter:(device::BluetoothAdapterMac*)adapter {
+- (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter {
   if ((self = [super init])) {
-    bridge_.reset(new device::BluetoothLowEnergyPeripheralManagerBridge(
-        advertisement_manager, adapter));
+    bridge_.reset(
+        new device::BluetoothLowEnergyPeripheralManagerBridge(adapter));
   }
   return self;
 }
diff --git a/device/bluetooth/test/bluetooth_test.cc b/device/bluetooth/test/bluetooth_test.cc
index 6245bbb..b0cdb67 100644
--- a/device/bluetooth/test/bluetooth_test.cc
+++ b/device/bluetooth/test/bluetooth_test.cc
@@ -15,6 +15,13 @@
 
 namespace device {
 
+BluetoothTestBase::LowEnergyDeviceData::LowEnergyDeviceData() = default;
+
+BluetoothTestBase::LowEnergyDeviceData::LowEnergyDeviceData(
+    LowEnergyDeviceData&& data) = default;
+
+BluetoothTestBase::LowEnergyDeviceData::~LowEnergyDeviceData() = default;
+
 const char BluetoothTestBase::kTestAdapterName[] = "FakeBluetoothAdapter";
 const char BluetoothTestBase::kTestAdapterAddress[] = "A1:B2:C3:D4:E5:F6";
 
@@ -60,12 +67,11 @@
 const char BluetoothTestBase::kTestUUIDCharacteristicPresentationFormat[] =
     "00002904-0000-1000-8000-00805f9b34fb";
 // Manufacturer kTestAdapterAddress
-const unsigned short BluetoothTestBase::kTestManufacturerId = 0x00E0;
+const uint16_t BluetoothTestBase::kTestManufacturerId = 0x00E0;
 
 BluetoothTestBase::BluetoothTestBase() : weak_factory_(this) {}
 
 BluetoothTestBase::~BluetoothTestBase() = default;
-
 void BluetoothTestBase::StartLowEnergyDiscoverySession() {
   adapter_->StartDiscoverySessionWithFilter(
       std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE),
@@ -434,13 +440,6 @@
   adapter_->RemoveTimedOutDevices();
 }
 
-BluetoothTestBase::LowEnergyDeviceData::LowEnergyDeviceData() = default;
-
-BluetoothTestBase::LowEnergyDeviceData::LowEnergyDeviceData(
-    LowEnergyDeviceData&& data) = default;
-
-BluetoothTestBase::LowEnergyDeviceData::~LowEnergyDeviceData() = default;
-
 BluetoothTestBase::LowEnergyDeviceData
 BluetoothTestBase::GetLowEnergyDeviceData(int device_ordinal) const {
   LowEnergyDeviceData device_data;
@@ -448,6 +447,7 @@
     case 1:
       device_data.name = kTestDeviceName;
       device_data.address = kTestDeviceAddress1;
+      device_data.flags = 0x04;
       device_data.rssi = static_cast<int>(TestRSSI::LOWEST);
       device_data.advertised_uuids = {BluetoothUUID(kTestUUIDGenericAccess),
                                       BluetoothUUID(kTestUUIDGenericAttribute)};
@@ -458,6 +458,7 @@
     case 2:
       device_data.name = kTestDeviceName;
       device_data.address = kTestDeviceAddress1;
+      device_data.flags = 0x05;
       device_data.rssi = static_cast<int>(TestRSSI::LOWER);
       device_data.advertised_uuids = {BluetoothUUID(kTestUUIDImmediateAlert),
                                       BluetoothUUID(kTestUUIDLinkLoss)};
@@ -479,17 +480,20 @@
       break;
     case 5:
       device_data.address = kTestDeviceAddress1;
+      device_data.flags = 0x06;
       device_data.rssi = static_cast<int>(TestRSSI::HIGH);
       break;
     case 6:
       device_data.name = kTestDeviceName;
       device_data.address = kTestDeviceAddress2;
+      device_data.flags = 0x18;
       device_data.rssi = static_cast<int>(TestRSSI::LOWEST);
       device_data.transport = BLUETOOTH_TRANSPORT_DUAL;
       break;
     case 7:
       device_data.name = kTestDeviceNameU2f;
       device_data.address = kTestDeviceAddress1;
+      device_data.flags = 0x07;
       device_data.rssi = static_cast<int>(TestRSSI::LOWEST);
       device_data.advertised_uuids = {BluetoothUUID(kTestUUIDU2f)};
       device_data.service_data = {
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h
index 5001228..6baa47f 100644
--- a/device/bluetooth/test/bluetooth_test.h
+++ b/device/bluetooth/test/bluetooth_test.h
@@ -62,6 +62,25 @@
     INDICATE,
   };
 
+  // Utility struct to simplify simulating a low energy device.
+  struct LowEnergyDeviceData {
+    LowEnergyDeviceData();
+    LowEnergyDeviceData(LowEnergyDeviceData&& data);
+    ~LowEnergyDeviceData();
+
+    base::Optional<std::string> name;
+    std::string address;
+    int8_t rssi = 0;
+    base::Optional<uint8_t> flags;
+    BluetoothDevice::UUIDList advertised_uuids;
+    base::Optional<int8_t> tx_power;
+    BluetoothDevice::ServiceDataMap service_data;
+    BluetoothDevice::ManufacturerDataMap manufacturer_data;
+    BluetoothTransport transport = BLUETOOTH_TRANSPORT_LE;
+
+    DISALLOW_COPY_AND_ASSIGN(LowEnergyDeviceData);
+  };
+
   static const char kTestAdapterName[];
   static const char kTestAdapterAddress[];
 
@@ -110,7 +129,7 @@
   static const char kTestUUIDServerCharacteristicConfiguration[];
   static const char kTestUUIDCharacteristicPresentationFormat[];
   // Manufacturer data
-  static const unsigned short kTestManufacturerId;
+  static const uint16_t kTestManufacturerId;
 
   BluetoothTestBase();
   ~BluetoothTestBase() override;
@@ -164,6 +183,7 @@
   //   1: Name: kTestDeviceName
   //      Address:           kTestDeviceAddress1
   //      RSSI:              TestRSSI::LOWEST
+  //      Flags:             0x04
   //      Advertised UUIDs: {kTestUUIDGenericAccess, kTestUUIDGenericAttribute}
   //      Service Data:     {kTestUUIDHeartRate: [1]}
   //      ManufacturerData: {kTestManufacturerId: [1, 2, 3, 4]}
@@ -171,6 +191,7 @@
   //   2: Name: kTestDeviceName
   //      Address:           kTestDeviceAddress1
   //      RSSI:              TestRSSI::LOWER
+  //      Flags:             0x05
   //      Advertised UUIDs: {kTestUUIDImmediateAlert, kTestUUIDLinkLoss}
   //      Service Data:     {kTestUUIDHeartRate: [],
   //                         kTestUUIDImmediateAlert: [0, 2]}
@@ -179,6 +200,7 @@
   //   3: Name:    kTestDeviceNameEmpty
   //      Address: kTestDeviceAddress1
   //      RSSI:    TestRSSI::LOW
+  //      No Flags
   //      No Advertised UUIDs
   //      No Service Data
   //      No Manufacturer Data
@@ -186,6 +208,7 @@
   //   4: Name:    kTestDeviceNameEmpty
   //      Address: kTestDeviceAddress2
   //      RSSI:    TestRSSI::MEDIUM
+  //      No Flags
   //      No Advertised UUIDs
   //      No Service Data
   //      No Manufacturer Data
@@ -193,11 +216,13 @@
   //   5: No name device
   //      Address: kTestDeviceAddress1
   //      RSSI:    TestRSSI::HIGH
+  //      Flags:   0x06
   //      No Advertised UUIDs
   //      No Service Data
   //      No Tx Power
   //   6: Name:    kTestDeviceName
   //      Address: kTestDeviceAddress2
+  //      Flags:   0x18
   //      RSSI:    TestRSSI::LOWEST
   //      No Advertised UUIDs
   //      No Service Data
@@ -206,6 +231,7 @@
   //      Supports BR/EDR and LE.
   //   7: Name:    kTestDeviceNameU2f
   //      Address: kTestDeviceAddress1
+  //      Flags:   0x07
   //      RSSI:    TestRSSI::LOWEST
   //      Advertised UUIDs: {kTestUUIDU2f}
   //      Service Data:     {kTestUUIDU2fControlPointLength: [0, 20]}
@@ -216,7 +242,7 @@
   // Simulates a connected low energy device. Used before starting a low energy
   // discovey session.
   virtual void SimulateConnectedLowEnergyDevice(
-      ConnectedDeviceType device_ordinal){};
+      ConnectedDeviceType device_ordinal) {}
 
   // Create a fake classic device and discover it. The device will have
   // name kTestDeviceName, no advertised UUIDs and address kTestDeviceAddress3.
@@ -538,25 +564,8 @@
   void RemoveTimedOutDevices();
 
  protected:
-  // Utility struct and method to return required data to simulate a LE device
-  // corresponding to |device_ordinal|.
-  struct LowEnergyDeviceData {
-    LowEnergyDeviceData();
-    LowEnergyDeviceData(LowEnergyDeviceData&& data);
-    ~LowEnergyDeviceData();
-
-    base::Optional<std::string> name;
-    std::string address;
-    int8_t rssi = 0;
-    BluetoothDevice::UUIDList advertised_uuids;
-    BluetoothDevice::ServiceDataMap service_data;
-    BluetoothDevice::ManufacturerDataMap manufacturer_data;
-    base::Optional<int8_t> tx_power;
-    BluetoothTransport transport = BLUETOOTH_TRANSPORT_LE;
-
-    DISALLOW_COPY_AND_ASSIGN(LowEnergyDeviceData);
-  };
-
+  // Utility method to simplify creading a low energy device of a given
+  // |device_ordinal|.
   LowEnergyDeviceData GetLowEnergyDeviceData(int device_ordinal) const;
 
   // A ScopedTaskEnvironment is required by some implementations that will
diff --git a/device/bluetooth/test/bluetooth_test_win.cc b/device/bluetooth/test/bluetooth_test_win.cc
index 4c0c9ca..e04bd95b 100644
--- a/device/bluetooth/test/bluetooth_test_win.cc
+++ b/device/bluetooth/test/bluetooth_test_win.cc
@@ -35,9 +35,7 @@
 #include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/test/fake_bluetooth_adapter_winrt.h"
-#include "device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h"
 #include "device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h"
-#include "device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h"
 #include "device/bluetooth/test/fake_bluetooth_le_device_winrt.h"
 #include "device/bluetooth/test/fake_device_information_winrt.h"
 
@@ -665,19 +663,9 @@
     return BluetoothTestWin::SimulateLowEnergyDevice(device_ordinal);
 
   LowEnergyDeviceData data = GetLowEnergyDeviceData(device_ordinal);
-  std::vector<GUID> guids;
-  for (const auto& uuid : data.advertised_uuids)
-    guids.push_back(
-        BluetoothUUID::GetCanonicalValueAsGUID(uuid.canonical_value()));
-
-  auto service_uuids = Make<base::win::Vector<GUID>>(std::move(guids));
-  auto advertisement = Make<FakeBluetoothLEAdvertisementWinrt>(
-      std::move(data.name), std::move(service_uuids));
-  auto event_args = Make<FakeBluetoothLEAdvertisementReceivedEventArgsWinrt>(
-      data.address, std::move(advertisement));
   static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
       ->watcher()
-      ->SimulateAdvertisement(std::move(event_args));
+      ->SimulateLowEnergyDevice(data);
 
   return adapter_->GetDevice(data.address);
 }
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.cc b/device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.cc
new file mode 100644
index 0000000..0e50ef03
--- /dev/null
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.cc
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h"
+
+#include <wrl/client.h>
+
+#include <utility>
+
+#include "base/win/winrt_storage_util.h"
+
+namespace device {
+
+namespace {
+
+using ABI::Windows::Storage::Streams::IBuffer;
+using Microsoft::WRL::ComPtr;
+
+}  // namespace
+
+FakeBluetoothLEAdvertisementDataSectionWinrt::
+    FakeBluetoothLEAdvertisementDataSectionWinrt(std::vector<uint8_t> data)
+    : data_(std::move(data)) {}
+
+FakeBluetoothLEAdvertisementDataSectionWinrt::
+    ~FakeBluetoothLEAdvertisementDataSectionWinrt() = default;
+
+HRESULT FakeBluetoothLEAdvertisementDataSectionWinrt::get_DataType(
+    uint8_t* value) {
+  return E_NOTIMPL;
+}
+
+HRESULT FakeBluetoothLEAdvertisementDataSectionWinrt::put_DataType(
+    uint8_t value) {
+  return E_NOTIMPL;
+}
+
+HRESULT FakeBluetoothLEAdvertisementDataSectionWinrt::get_Data(
+    IBuffer** value) {
+  ComPtr<IBuffer> buffer;
+  HRESULT hr = base::win::CreateIBufferFromData(
+      data_.data(), static_cast<uint32_t>(data_.size()), &buffer);
+  return SUCCEEDED(hr) ? buffer.CopyTo(value) : hr;
+}
+
+HRESULT FakeBluetoothLEAdvertisementDataSectionWinrt::put_Data(IBuffer* value) {
+  return E_NOTIMPL;
+}
+
+}  // namespace device
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h b/device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h
new file mode 100644
index 0000000..bc0f5da
--- /dev/null
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_TEST_FAKE_BLUETOOTH_LE_ADVERTISEMENT_DATA_SECTION_WINRT_H_
+#define DEVICE_BLUETOOTH_TEST_FAKE_BLUETOOTH_LE_ADVERTISEMENT_DATA_SECTION_WINRT_H_
+
+#include <windows.devices.bluetooth.advertisement.h>
+#include <wrl/implements.h>
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+
+namespace device {
+
+class FakeBluetoothLEAdvertisementDataSectionWinrt
+    : public Microsoft::WRL::RuntimeClass<
+          Microsoft::WRL::RuntimeClassFlags<
+              Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
+          ABI::Windows::Devices::Bluetooth::Advertisement::
+              IBluetoothLEAdvertisementDataSection> {
+ public:
+  explicit FakeBluetoothLEAdvertisementDataSectionWinrt(
+      std::vector<uint8_t> data);
+  ~FakeBluetoothLEAdvertisementDataSectionWinrt() override;
+
+  // IBluetoothLEAdvertisementDataSection:
+  IFACEMETHODIMP get_DataType(uint8_t* value) override;
+  IFACEMETHODIMP put_DataType(uint8_t value) override;
+  IFACEMETHODIMP get_Data(
+      ABI::Windows::Storage::Streams::IBuffer** value) override;
+  IFACEMETHODIMP put_Data(
+      ABI::Windows::Storage::Streams::IBuffer* value) override;
+
+ private:
+  std::vector<uint8_t> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEAdvertisementDataSectionWinrt);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_BLUETOOTH_TEST_FAKE_BLUETOOTH_LE_ADVERTISEMENT_DATA_SECTION_WINRT_H_
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.cc b/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.cc
index f791dec2..625c57f4 100644
--- a/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.cc
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.cc
@@ -25,9 +25,11 @@
 
 FakeBluetoothLEAdvertisementReceivedEventArgsWinrt::
     FakeBluetoothLEAdvertisementReceivedEventArgsWinrt(
+        int16_t rssi,
         base::StringPiece address,
         ComPtr<IBluetoothLEAdvertisement> advertisement)
-    : raw_address_(FakeBluetoothAdapterWinrt::ToRawBluetoothAddress(address)),
+    : rssi_(rssi),
+      raw_address_(FakeBluetoothAdapterWinrt::ToRawBluetoothAddress(address)),
       advertisement_(std::move(advertisement)) {}
 
 FakeBluetoothLEAdvertisementReceivedEventArgsWinrt::
@@ -36,7 +38,7 @@
 HRESULT
 FakeBluetoothLEAdvertisementReceivedEventArgsWinrt::get_RawSignalStrengthInDBm(
     int16_t* value) {
-  *value = 0;
+  *value = rssi_;
   return S_OK;
 }
 
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h b/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h
index 70cf8e7..91929a83 100644
--- a/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h
@@ -23,6 +23,7 @@
               IBluetoothLEAdvertisementReceivedEventArgs> {
  public:
   FakeBluetoothLEAdvertisementReceivedEventArgsWinrt(
+      int16_t rssi,
       base::StringPiece address,
       Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::Advertisement::
                                  IBluetoothLEAdvertisement> advertisement);
@@ -41,6 +42,7 @@
           IBluetoothLEAdvertisement** value) override;
 
  private:
+  int16_t rssi_;
   uint64_t raw_address_;
   Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::Advertisement::
                              IBluetoothLEAdvertisement>
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.cc b/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.cc
index 8db8ee8e..7700570e 100644
--- a/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.cc
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.cc
@@ -4,6 +4,10 @@
 
 #include "device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h"
 
+#include "base/strings/string_piece.h"
+#include "device/bluetooth/test/fake_bluetooth_le_advertisement_received_event_args_winrt.h"
+#include "device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h"
+
 namespace device {
 
 namespace {
@@ -29,6 +33,7 @@
 using ABI::Windows::Foundation::TimeSpan;
 using ABI::Windows::Foundation::ITypedEventHandler;
 using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::Make;
 
 }  // namespace
 
@@ -131,10 +136,18 @@
   return E_NOTIMPL;
 }
 
-void FakeBluetoothLEAdvertisementWatcherWinrt::SimulateAdvertisement(
-    ComPtr<IBluetoothLEAdvertisementReceivedEventArgs> advertisement) {
-  if (handler_)
-    handler_->Invoke(this, advertisement.Get());
+void FakeBluetoothLEAdvertisementWatcherWinrt::SimulateLowEnergyDevice(
+    const BluetoothTestBase::LowEnergyDeviceData& device_data) {
+  if (handler_) {
+    handler_->Invoke(
+        this, Make<FakeBluetoothLEAdvertisementReceivedEventArgsWinrt>(
+                  device_data.rssi, device_data.address,
+                  Make<FakeBluetoothLEAdvertisementWinrt>(
+                      device_data.name, device_data.flags,
+                      device_data.advertised_uuids, device_data.tx_power,
+                      device_data.service_data, device_data.manufacturer_data))
+                  .Get());
+  }
 }
 
 }  // namespace device
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h b/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h
index 148f966..a0d7709 100644
--- a/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h
@@ -12,6 +12,7 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "device/bluetooth/test/bluetooth_test.h"
 
 namespace device {
 
@@ -74,10 +75,8 @@
       EventRegistrationToken* token) override;
   IFACEMETHODIMP remove_Stopped(EventRegistrationToken token) override;
 
-  void SimulateAdvertisement(
-      Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::Advertisement::
-                                 IBluetoothLEAdvertisementReceivedEventArgs>
-          advertisement);
+  void SimulateLowEnergyDevice(
+      const BluetoothTestBase::LowEnergyDeviceData& device_data);
 
  private:
   ABI::Windows::Devices::Bluetooth::Advertisement::
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.cc b/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.cc
index f260524..1b8539a6 100644
--- a/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.cc
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.cc
@@ -4,12 +4,21 @@
 
 #include "device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h"
 
+#include <windows.foundation.collections.h>
+
+#include <algorithm>
 #include <utility>
+#include <vector>
 
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/win/reference.h"
 #include "base/win/scoped_hstring.h"
-
-namespace device {
+#include "base/win/vector.h"
+#include "device/bluetooth/bluetooth_device_winrt.h"
+#include "device/bluetooth/test/fake_bluetooth_le_advertisement_data_section_winrt.h"
+#include "device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h"
 
 namespace {
 
@@ -19,25 +28,133 @@
     BluetoothLEAdvertisementFlags;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     BluetoothLEManufacturerData;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
+    IBluetoothLEAdvertisementDataSection;
+using ABI::Windows::Devices::Bluetooth::Advertisement::
+    IBluetoothLEManufacturerData;
 using ABI::Windows::Foundation::IReference;
 using ABI::Windows::Foundation::Collections::IVector;
 using ABI::Windows::Foundation::Collections::IVectorView;
 using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::Make;
+
+}  // namespace
+
+// Note: As UWP does not provide GUID and  specializations for all required
+// templates we need to supply our own. UUIDs were generated using `uuidgen`.
+namespace ABI {
+namespace Windows {
+namespace Foundation {
+namespace Collections {
+
+template <>
+struct __declspec(uuid("241709e6-4b79-44b4-827c-9bcb6025ebe6"))
+    IObservableVector<GUID> : IObservableVector_impl<GUID> {};
+
+template <>
+struct __declspec(uuid("868ba4c1-7019-470b-b667-df34fa20efc6"))
+    VectorChangedEventHandler<GUID> : VectorChangedEventHandler_impl<GUID> {};
+
+template <>
+struct __declspec(uuid("5a7b58a6-fbd4-4ef9-98fd-d700649cd32e"))
+    IObservableVector<BluetoothLEManufacturerData*>
+    : IObservableVector_impl<
+          Internal::AggregateType<BluetoothLEManufacturerData*,
+                                  IBluetoothLEManufacturerData*>> {};
+
+template <>
+struct __declspec(uuid("0a57dc65-0e06-46ff-9ff7-cf2390847d2a"))
+    VectorChangedEventHandler<BluetoothLEManufacturerData*>
+    : VectorChangedEventHandler_impl<
+          Internal::AggregateType<BluetoothLEManufacturerData*,
+                                  IBluetoothLEManufacturerData*>> {};
+
+template <>
+struct __declspec(uuid("eeec55af-8cd4-4935-aa43-31aa2c5567b9"))
+    IObservableVector<BluetoothLEAdvertisementDataSection*>
+    : IObservableVector_impl<
+          Internal::AggregateType<BluetoothLEAdvertisementDataSection*,
+                                  IBluetoothLEAdvertisementDataSection*>> {};
+
+template <>
+struct __declspec(uuid("978f98e6-b03c-41c8-a529-7781fd06f1e4"))
+    VectorChangedEventHandler<BluetoothLEAdvertisementDataSection*>
+    : VectorChangedEventHandler_impl<
+          Internal::AggregateType<BluetoothLEAdvertisementDataSection*,
+                                  IBluetoothLEAdvertisementDataSection*>> {};
+
+}  // namespace Collections
+}  // namespace Foundation
+}  // namespace Windows
+}  // namespace ABI
+
+namespace device {
+
+namespace {
+
+constexpr size_t kNumBytesCanonicalUuid = 16;
+
+std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> ToDataSections(
+    const BluetoothDevice::ServiceDataMap& service_data) {
+  std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> data_sections;
+  data_sections.reserve(service_data.size());
+  for (const auto& pair : service_data) {
+    std::vector<uint8_t> data;
+    data.reserve(kNumBytesCanonicalUuid + pair.second.size());
+
+    // HexDecode the UUID while ignoring dashes.
+    for (const auto& token :
+         base::SplitStringPiece(pair.first.canonical_value(), "-",
+                                base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+      std::vector<uint8_t> tmp;
+      base::HexStringToBytes(token, &tmp);
+      data.insert(data.end(), tmp.begin(), tmp.end());
+    }
+
+    // Reverse the data as UUIDs are specified in little endian order in the
+    // advertisement payload.
+    std::reverse(data.begin(), data.end());
+
+    // Append the actual service data and append a new data section.
+    data.insert(data.end(), pair.second.begin(), pair.second.end());
+    data_sections.push_back(
+        Make<FakeBluetoothLEAdvertisementDataSectionWinrt>(std::move(data)));
+  }
+
+  return data_sections;
+}
 
 }  // namespace
 
 FakeBluetoothLEAdvertisementWinrt::FakeBluetoothLEAdvertisementWinrt(
     base::Optional<std::string> local_name,
-    ComPtr<IVector<GUID>> service_uuids)
+    base::Optional<uint8_t> flags,
+    BluetoothDevice::UUIDList advertised_uuids,
+    base::Optional<int8_t> tx_power,
+    BluetoothDevice::ServiceDataMap service_data,
+    BluetoothDevice::ManufacturerDataMap manufacturer_data)
     : local_name_(std::move(local_name)),
-      service_uuids_(std::move(service_uuids)) {}
+      flags_(std::move(flags)),
+      advertised_uuids_(std::move(advertised_uuids)),
+      tx_power_(std::move(tx_power)),
+      service_data_(std::move(service_data)),
+      manufacturer_data_(std::move(manufacturer_data)) {}
 
 FakeBluetoothLEAdvertisementWinrt::~FakeBluetoothLEAdvertisementWinrt() =
     default;
 
 HRESULT FakeBluetoothLEAdvertisementWinrt::get_Flags(
     IReference<BluetoothLEAdvertisementFlags>** value) {
-  return E_NOTIMPL;
+  // While non-intuitive, this matches production behavior. When a reference is
+  // supposed to be empty, the pointer is set to null and S_OK is returned.
+  if (!flags_) {
+    *value = nullptr;
+    return S_OK;
+  }
+
+  return Make<base::win::Reference<BluetoothLEAdvertisementFlags>>(
+             static_cast<BluetoothLEAdvertisementFlags>(*flags_))
+      .CopyTo(value);
 }
 
 HRESULT FakeBluetoothLEAdvertisementWinrt::put_Flags(
@@ -59,12 +176,28 @@
 
 HRESULT FakeBluetoothLEAdvertisementWinrt::get_ServiceUuids(
     IVector<GUID>** value) {
-  return service_uuids_.CopyTo(value);
+  std::vector<GUID> guids;
+  guids.reserve(advertised_uuids_.size());
+  for (const auto& uuid : advertised_uuids_) {
+    guids.emplace_back(
+        BluetoothUUID::GetCanonicalValueAsGUID(uuid.canonical_value()));
+  }
+
+  return Make<base::win::Vector<GUID>>(std::move(guids)).CopyTo(value);
 }
 
 HRESULT FakeBluetoothLEAdvertisementWinrt::get_ManufacturerData(
     IVector<BluetoothLEManufacturerData*>** value) {
-  return E_NOTIMPL;
+  std::vector<ComPtr<IBluetoothLEManufacturerData>> manufacturer_data;
+  manufacturer_data.reserve(manufacturer_data_.size());
+  for (const auto& pair : manufacturer_data_) {
+    manufacturer_data.push_back(
+        Make<FakeBluetoothLEManufacturerData>(pair.first, pair.second));
+  }
+
+  return Make<base::win::Vector<BluetoothLEManufacturerData*>>(
+             std::move(manufacturer_data))
+      .CopyTo(value);
 }
 
 HRESULT FakeBluetoothLEAdvertisementWinrt::get_DataSections(
@@ -81,7 +214,19 @@
 HRESULT FakeBluetoothLEAdvertisementWinrt::GetSectionsByType(
     uint8_t type,
     IVectorView<BluetoothLEAdvertisementDataSection*>** section_list) {
-  return E_NOTIMPL;
+  std::vector<ComPtr<IBluetoothLEAdvertisementDataSection>> data_sections;
+  if (type == BluetoothDeviceWinrt::kTxPowerLevelDataSection && tx_power_) {
+    data_sections.push_back(Make<FakeBluetoothLEAdvertisementDataSectionWinrt>(
+        std::vector<uint8_t>({*tx_power_})));
+  }
+
+  // For simplicity we only implement querying 128 Bit UUID Service Data.
+  if (type == BluetoothDeviceWinrt::k128BitServiceDataSection)
+    data_sections = ToDataSections(service_data_);
+
+  return Make<base::win::Vector<BluetoothLEAdvertisementDataSection*>>(
+             std::move(data_sections))
+      ->GetView(section_list);
 }
 
 }  // namespace device
diff --git a/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h b/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h
index 23d9004..a9c47a1 100644
--- a/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h
+++ b/device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h
@@ -15,6 +15,7 @@
 
 #include "base/macros.h"
 #include "base/optional.h"
+#include "device/bluetooth/bluetooth_device.h"
 
 namespace device {
 
@@ -27,8 +28,11 @@
  public:
   FakeBluetoothLEAdvertisementWinrt(
       base::Optional<std::string> local_name,
-      Microsoft::WRL::ComPtr<
-          ABI::Windows::Foundation::Collections::IVector<GUID>> service_uuids);
+      base::Optional<uint8_t> flags,
+      BluetoothDevice::UUIDList advertised_uuids,
+      base::Optional<int8_t> tx_power,
+      BluetoothDevice::ServiceDataMap service_data,
+      BluetoothDevice::ManufacturerDataMap manufacturer_data);
   ~FakeBluetoothLEAdvertisementWinrt() override;
 
   // IBluetoothLEAdvertisement:
@@ -63,8 +67,11 @@
 
  private:
   base::Optional<std::string> local_name_;
-  Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<GUID>>
-      service_uuids_;
+  base::Optional<uint8_t> flags_;
+  BluetoothDevice::UUIDList advertised_uuids_;
+  base::Optional<int8_t> tx_power_;
+  BluetoothDevice::ServiceDataMap service_data_;
+  BluetoothDevice::ManufacturerDataMap manufacturer_data_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEAdvertisementWinrt);
 };
diff --git a/device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.cc b/device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.cc
new file mode 100644
index 0000000..149309a
--- /dev/null
+++ b/device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h"
+
+#include <wrl/client.h>
+
+#include <utility>
+
+#include "base/win/winrt_storage_util.h"
+
+namespace device {
+
+namespace {
+
+using ABI::Windows::Storage::Streams::IBuffer;
+using Microsoft::WRL::ComPtr;
+
+}  // namespace
+
+FakeBluetoothLEManufacturerData::FakeBluetoothLEManufacturerData(
+    uint16_t company_id,
+    std::vector<uint8_t> data)
+    : company_id_(company_id), data_(std::move(data)) {}
+
+FakeBluetoothLEManufacturerData::~FakeBluetoothLEManufacturerData() = default;
+
+HRESULT FakeBluetoothLEManufacturerData::get_CompanyId(uint16_t* value) {
+  *value = company_id_;
+  return S_OK;
+}
+
+HRESULT FakeBluetoothLEManufacturerData::put_CompanyId(uint16_t value) {
+  return E_NOTIMPL;
+}
+
+HRESULT FakeBluetoothLEManufacturerData::get_Data(IBuffer** value) {
+  ComPtr<IBuffer> buffer;
+  HRESULT hr = base::win::CreateIBufferFromData(
+      data_.data(), static_cast<uint32_t>(data_.size()), &buffer);
+  return SUCCEEDED(hr) ? buffer.CopyTo(value) : hr;
+}
+
+HRESULT FakeBluetoothLEManufacturerData::put_Data(IBuffer* value) {
+  return E_NOTIMPL;
+}
+
+}  // namespace device
diff --git a/device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h b/device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h
new file mode 100644
index 0000000..1140a8f
--- /dev/null
+++ b/device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_TEST_FAKE_BLUETOOTH_LE_MANUFACTURER_DATA_WINRT_H_
+#define DEVICE_BLUETOOTH_TEST_FAKE_BLUETOOTH_LE_MANUFACTURER_DATA_WINRT_H_
+
+#include <windows.devices.bluetooth.advertisement.h>
+#include <wrl/implements.h>
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+
+namespace device {
+
+class FakeBluetoothLEManufacturerData
+    : public Microsoft::WRL::RuntimeClass<
+          Microsoft::WRL::RuntimeClassFlags<
+              Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
+          ABI::Windows::Devices::Bluetooth::Advertisement::
+              IBluetoothLEManufacturerData> {
+ public:
+  FakeBluetoothLEManufacturerData(uint16_t company_id,
+                                  std::vector<uint8_t> data);
+  ~FakeBluetoothLEManufacturerData() override;
+
+  // IBluetoothLEManufacturerData:
+  IFACEMETHODIMP get_CompanyId(uint16_t* value) override;
+  IFACEMETHODIMP put_CompanyId(uint16_t value) override;
+  IFACEMETHODIMP get_Data(
+      ABI::Windows::Storage::Streams::IBuffer** value) override;
+  IFACEMETHODIMP put_Data(
+      ABI::Windows::Storage::Streams::IBuffer* value) override;
+
+ private:
+  uint16_t company_id_;
+  std::vector<uint8_t> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEManufacturerData);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_BLUETOOTH_TEST_FAKE_BLUETOOTH_LE_MANUFACTURER_DATA_WINRT_H_
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index bde7433..69a3342 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -497,6 +497,8 @@
     "browsertest_util.h",
     "preload_check_test_util.cc",
     "preload_check_test_util.h",
+    "test_event_router_observer.cc",
+    "test_event_router_observer.h",
     "value_store/test_value_store_factory.cc",
     "value_store/test_value_store_factory.h",
     "value_store/testing_value_store.cc",
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index 3bde19d9..f142a31e 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -243,6 +243,14 @@
   }
 }
 
+void EventRouter::AddObserverForTesting(TestObserver* observer) {
+  test_observers_.AddObserver(observer);
+}
+
+void EventRouter::RemoveObserverForTesting(TestObserver* observer) {
+  test_observers_.RemoveObserver(observer);
+}
+
 void EventRouter::OnListenerAdded(const EventListener* listener) {
   const EventListenerInfo details(listener->event_name(),
                                   listener->extension_id(),
@@ -510,6 +518,10 @@
   DCHECK(!event->restrict_to_browser_context ||
          ExtensionsBrowserClient::Get()->IsSameContext(
              browser_context_, event->restrict_to_browser_context));
+
+  for (TestObserver& observer : test_observers_)
+    observer.OnWillDispatchEvent(*event);
+
   std::set<const EventListener*> listeners(
       listeners_.GetEventListeners(*event));
 
@@ -913,7 +925,7 @@
 
 Event::~Event() {}
 
-Event* Event::DeepCopy() {
+Event* Event::DeepCopy() const {
   Event* copy = new Event(
       histogram_value, event_name,
       std::unique_ptr<base::ListValue>(event_args->DeepCopy()),
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h
index 512ff10..387d99f4 100644
--- a/extensions/browser/event_router.h
+++ b/extensions/browser/event_router.h
@@ -15,6 +15,7 @@
 #include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "base/values.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -82,6 +83,13 @@
     virtual ~Observer() {}
   };
 
+  // A test observer to monitor event dispatching.
+  class TestObserver {
+   public:
+    virtual ~TestObserver() = default;
+    virtual void OnWillDispatchEvent(const Event& event) = 0;
+  };
+
   // Gets the EventRouter for |browser_context|.
   static EventRouter* Get(content::BrowserContext* browser_context);
 
@@ -155,6 +163,10 @@
   // Unregisters an observer from all events.
   void UnregisterObserver(Observer* observer);
 
+  // Adds/removes test observers.
+  void AddObserverForTesting(TestObserver* observer);
+  void RemoveObserverForTesting(TestObserver* observer);
+
   // Add or remove the extension as having a lazy background page that listens
   // to the event. The difference from the above methods is that these will be
   // remembered even after the process goes away. We use this list to decide
@@ -360,6 +372,8 @@
   using ObserverMap = std::unordered_map<std::string, Observer*>;
   ObserverMap observers_;
 
+  base::ObserverList<TestObserver> test_observers_;
+
   std::set<content::RenderProcessHost*> observed_process_set_;
 
   LazyEventDispatchUtil lazy_event_dispatch_util_;
@@ -440,7 +454,8 @@
 
   // Makes a deep copy of this instance. Ownership is transferred to the
   // caller.
-  Event* DeepCopy();
+  // TODO(devlin): Have this return a unique_ptr.
+  Event* DeepCopy() const;
 };
 
 struct EventListenerInfo {
diff --git a/extensions/browser/test_event_router_observer.cc b/extensions/browser/test_event_router_observer.cc
new file mode 100644
index 0000000..b7f623eb
--- /dev/null
+++ b/extensions/browser/test_event_router_observer.cc
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/test_event_router_observer.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace extensions {
+
+TestEventRouterObserver::TestEventRouterObserver(EventRouter* event_router)
+    : event_router_(event_router) {
+  event_router_->AddObserverForTesting(this);
+}
+
+TestEventRouterObserver::~TestEventRouterObserver() {
+  // Note: can't use ScopedObserver<> here because the method is
+  // RemoveObserverForTesting() instead of RemoveObserver().
+  event_router_->RemoveObserverForTesting(this);
+}
+
+void TestEventRouterObserver::ClearEvents() {
+  events_.clear();
+}
+
+void TestEventRouterObserver::OnWillDispatchEvent(const Event& event) {
+  DCHECK(!event.event_name.empty());
+  events_[event.event_name] = base::WrapUnique(event.DeepCopy());
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/test_event_router_observer.h b/extensions/browser/test_event_router_observer.h
new file mode 100644
index 0000000..19926835
--- /dev/null
+++ b/extensions/browser/test_event_router_observer.h
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_TEST_EVENT_ROUTER_OBSERVER_H_
+#define EXTENSIONS_BROWSER_TEST_EVENT_ROUTER_OBSERVER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "extensions/browser/event_router.h"
+
+namespace extensions {
+
+class TestEventRouterObserver : public EventRouter::TestObserver {
+ public:
+  using EventMap = std::map<std::string, std::unique_ptr<Event>>;
+
+  explicit TestEventRouterObserver(EventRouter* event_router);
+  ~TestEventRouterObserver() override;
+
+  // Clears all recorded events.
+  void ClearEvents();
+
+  const EventMap& events() { return events_; }
+
+ private:
+  // EventRouter::TestObserver:
+  void OnWillDispatchEvent(const Event& event) override;
+
+  EventMap events_;
+  EventRouter* event_router_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestEventRouterObserver);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_TEST_EVENT_ROUTER_OBSERVER_H_
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc
index 5760745..5f221fd 100644
--- a/extensions/common/permissions/permissions_data.cc
+++ b/extensions/common/permissions/permissions_data.cc
@@ -363,7 +363,8 @@
   // Check the real origin, in order to account for filesystem:, blob:, etc.
   // (url::Origin grabs the inner origin of these, whereas GURL::GetOrigin()
   // does not.)
-  const GURL origin = url::Origin::Create(document_url).GetURL();
+  url::Origin origin = url::Origin::Create(document_url);
+  const GURL origin_url = origin.GetURL();
   {
     base::AutoLock auto_lock(runtime_lock_);
     // Disallow capturing policy-blocked hosts. No exceptions.
@@ -371,7 +372,8 @@
     // blocked host in a different page and then capture that, but it's better
     // than nothing (and policy hosts can set their x-frame options
     // accordingly).
-    if (location_ != Manifest::COMPONENT && IsPolicyBlockedHostUnsafe(origin)) {
+    if (location_ != Manifest::COMPONENT &&
+        IsPolicyBlockedHostUnsafe(origin_url)) {
       if (error)
         *error = extension_misc::kPolicyBlockedScripting;
       return false;
@@ -404,7 +406,7 @@
   // If the extension has page access (and has activeTab or <all_urls>, as
   // checked above), allow the capture.
   std::string access_error;
-  if (GetPageAccess(origin, tab_id, &access_error) == PageAccess::kAllowed)
+  if (GetPageAccess(origin_url, tab_id, &access_error) == PageAccess::kAllowed)
     return true;
 
   // The extension doesn't have explicit page access. However, there are a
@@ -420,7 +422,7 @@
   // web content.
   // TODO(devlin): Should activeTab/<all_urls> account for the extension's own
   // domain?
-  if (origin.host() == extension_id_)
+  if (origin_url.host() == extension_id_)
     return true;
 
   // The following are special cases that require activeTab explicitly. Normal
@@ -435,10 +437,12 @@
   // - data: URLs (which don't have a defined underlying origin).
   // TODO(devlin): Include the Webstore in this list?
   bool allowed_with_active_tab =
-      origin.SchemeIs(content::kChromeUIScheme) ||
-      origin.SchemeIs(kExtensionScheme) ||
+      origin_url.SchemeIs(content::kChromeUIScheme) ||
+      origin_url.SchemeIs(kExtensionScheme) ||
       // Note: The origin of a data: url is empty, so check the url itself.
-      document_url.SchemeIs(url::kDataScheme);
+      document_url.SchemeIs(url::kDataScheme) ||
+      origin.IsSameOriginWith(
+          url::Origin::Create(ExtensionsClient::Get()->GetWebstoreBaseURL()));
 
   if (!allowed_with_active_tab) {
     if (error)
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index ae3837a..4c4b7c60 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -843,6 +843,14 @@
     return false;
   }
 
+  // According to the OpenGL extension spec EXT_sRGB.txt, EXT_SRGB is based on
+  // ES 2.0 and generateMipmap is not allowed if texture format is SRGB_EXT or
+  // SRGB_ALPHA_EXT.
+  if (feature_info->IsWebGL1OrES2Context() &&
+      (base.format == GL_SRGB_EXT || base.format == GL_SRGB_ALPHA_EXT)) {
+    return false;
+  }
+
   if (!feature_info->validators()->texture_unsized_internal_format.IsValid(
       base.internal_format)) {
     if (!Texture::ColorRenderable(feature_info, base.internal_format,
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 4ba6ee24..5ae14ab 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -30,7 +30,6 @@
 
 #if defined(USE_OZONE)
 #include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/ozone_switches.h"
 #endif
 
 #if defined(OS_WIN)
@@ -212,7 +211,7 @@
   // may also have started at this point.
   ui::OzonePlatform::InitParams params;
   params.single_process = false;
-  params.using_mojo = command_line->HasSwitch(switches::kEnableDrmMojo);
+  params.using_mojo = features::IsOzoneDrmMojo();
   ui::OzonePlatform::InitializeForGPU(params);
 #endif
 
@@ -339,10 +338,10 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
 #if defined(OS_CHROMEOS)
-  params.using_mojo = !features::IsAshInBrowserProcess() ||
-                      command_line->HasSwitch(switches::kEnableDrmMojo);
+  params.using_mojo =
+      !features::IsAshInBrowserProcess() || features::IsOzoneDrmMojo();
 #else
-  params.using_mojo = command_line->HasSwitch(switches::kEnableDrmMojo);
+  params.using_mojo = features::IsOzoneDrmMojo();
 #endif
   ui::OzonePlatform::InitializeForGPU(params);
   ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
diff --git a/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json b/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json
index e20676a..8a5a538 100644
--- a/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json
+++ b/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json
@@ -1,6 +1,6 @@
 {
   "comments": [
-    "UIRefresh tests for iPhone device."
+    "UIRefresh tests for iPhone simulator."
   ],
   "xcode build version": "9C40b",
   "gn_args": [
@@ -20,7 +20,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone 5s",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "uirefresh_unittests.json",
@@ -28,7 +38,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone X",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "uirefresh_unittests.json",
@@ -36,7 +56,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
@@ -44,7 +74,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone 6",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
@@ -52,7 +92,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
@@ -60,7 +110,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone X",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
@@ -68,7 +128,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_tests.json",
@@ -76,7 +146,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone X",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_tests.json",
@@ -84,7 +164,17 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2"
+      "os": "11.2",
+      "dimensions": [
+        {
+          "os": "Mac-10.13.4",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13.5",
+          "pool": "Chrome"
+        }
+      ]
     }
   ]
 }
diff --git a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm
index 044526d..210fc20 100644
--- a/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm
+++ b/ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.mm
@@ -20,6 +20,8 @@
   UIAlertController* _dialogController;
   // Number of attempts to show the repost form action sheet.
   NSUInteger _repostAttemptCount;
+  // A completion handler to be called when the dialog is dismissed.
+  void (^_dismissCompletionHandler)(void);
 }
 
 // Creates a new UIAlertController to use for the dialog.
@@ -49,6 +51,12 @@
         [[self class] newDialogControllerForSourceView:webState->GetView()
                                             sourceRect:sourceRect
                                      completionHandler:completionHandler];
+    // The dialog may be dimissed when a new navigation starts while the dialog
+    // is still presenting. This should be treated as a NO from user.
+    // See https://crbug.com/854750 for a case why this matters.
+    _dismissCompletionHandler = ^{
+      completionHandler(NO);
+    };
   }
   return self;
 }
@@ -94,8 +102,9 @@
 - (void)stop {
   [_dialogController.presentingViewController
       dismissViewControllerAnimated:YES
-                         completion:nil];
+                         completion:_dismissCompletionHandler];
   _repostAttemptCount = 0;
+  _dismissCompletionHandler = nil;
 }
 
 #pragma mark - Private
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 1cbc0ac..63ebfe9 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -277,10 +277,16 @@
           ->PickAccountIdForAccount(
               base::SysNSStringToUTF8([_selectedIdentity gaiaID]),
               base::SysNSStringToUTF8([_selectedIdentity userEmail]));
+
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  sync_consent.set_confirmation_grd_id(consent_confirmation_id);
+  for (int id : consent_text_ids) {
+    sync_consent.add_description_grd_ids(id);
+  }
   ConsentAuditorFactory::GetForBrowserState(_browserState)
-      ->RecordGaiaConsent(account_id, consent_auditor::Feature::CHROME_SYNC,
-                          consent_text_ids, consent_confirmation_id,
-                          consent_auditor::ConsentStatus::GIVEN);
+      ->RecordSyncConsent(account_id, sync_consent);
   _didAcceptSignIn = YES;
   if (!_didFinishSignIn) {
     _didFinishSignIn = YES;
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 75eef8a..77d1f02 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -195,6 +195,7 @@
 #import "ios/chrome/browser/ui/static_content/static_html_native_content.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.h"
 #import "ios/chrome/browser/ui/tabs/background_tab_animation_view.h"
+#import "ios/chrome/browser/ui/tabs/foreground_tab_animation_view.h"
 #import "ios/chrome/browser/ui/tabs/requirements/tab_strip_constants.h"
 #import "ios/chrome/browser/ui/tabs/requirements/tab_strip_presentation.h"
 #import "ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h"
@@ -5264,6 +5265,8 @@
   UIView* newPage = nil;
   CGFloat offset = 0;
   GURL tabURL = tab.webState->GetLastCommittedURL();
+  // Toolbar snapshot is only used for the UIRefresh animation.
+  UIView* toolbarSnapshot;
   // Vislble URL should be more correct here than last committed, but for
   // safety, limiting the scope only to WKBasedNavigationManager, which needs
   // it to correctly animate NTP. See https://crbug.com/819606.
@@ -5272,10 +5275,24 @@
   if (tabURL == kChromeUINewTabURL && !_isOffTheRecord &&
       ![self canShowTabStrip]) {
     offset = 0;
-    // Temporary expand content area to take whole view space. Otherwise the
-    // animated NTP will be clipped by content area bound. Previous frame will
-    // be reset back on the animation completion.
-    self.contentArea.frame = self.view.frame;
+    if (IsUIRefreshPhase1Enabled()) {
+      // Add a snapshot of the primary toolbar to the background as the
+      // animation runs.
+      UIViewController* toolbarViewController =
+          self.primaryToolbarCoordinator.viewController;
+      toolbarSnapshot =
+          [toolbarViewController.view snapshotViewAfterScreenUpdates:NO];
+      toolbarSnapshot.frame =
+          [self.contentArea convertRect:toolbarSnapshot.frame
+                               fromView:self.view];
+      [self.contentArea addSubview:toolbarSnapshot];
+    } else {
+      // Temporarily expand content area to take whole view space. Otherwise the
+      // animated NTP will be clipped by content area bound. Previous frame will
+      // be reset back on the animation completion.
+      self.contentArea.frame = self.view.frame;
+    }
+
     newPage = tab.view;
     newPage.userInteractionEnabled = NO;
     if (base::FeatureList::IsEnabled(
@@ -5305,39 +5322,69 @@
   }
   newPageOffset = newPage.frame.origin.y;
 
-  [self.contentArea addSubview:newPage];
+  // Cleanup steps needed for both UI Refresh and stack-view style animations.
+  auto commonCompletion = ^{
+    tab.view.frame = self.contentArea.bounds;
+    newPage.userInteractionEnabled = YES;
+    self.inNewTabAnimation = NO;
+    // Use the model's currentTab here because it is possible that it can
+    // be reset to a new value before the new Tab animation finished (e.g.
+    // if another Tab shows a dialog via |dialogPresenter|). However, that
+    // tab's view hasn't been displayed yet because it was in a new tab
+    // animation.
+    Tab* currentTab = [_model currentTab];
+    if (currentTab) {
+      [self tabSelected:currentTab notifyToolbar:NO];
+    }
+    if (completion)
+      completion();
+
+    if (self.foregroundTabWasAddedCompletionBlock) {
+      self.foregroundTabWasAddedCompletionBlock();
+      self.foregroundTabWasAddedCompletionBlock = nil;
+    }
+  };
+
   CGPoint origin = [self lastTapPoint];
+
+  // UI Refresh animation.
+  if (IsUIRefreshPhase1Enabled()) {
+    CGRect frame = self.view.bounds;
+    frame.origin.y += StatusBarHeight();
+    frame = [self.contentArea convertRect:frame fromView:self.view];
+    ForegroundTabAnimationView* animatedView =
+        [[ForegroundTabAnimationView alloc] initWithFrame:frame];
+    animatedView.contentView = newPage;
+    __weak UIView* weakAnimatedView = animatedView;
+    auto completionBlock = ^() {
+      [weakAnimatedView removeFromSuperview];
+      [toolbarSnapshot removeFromSuperview];
+      commonCompletion();
+    };
+    [self.contentArea addSubview:animatedView];
+    [animatedView animateFrom:origin withCompletion:completionBlock];
+    return;
+  }
+
+  // Else, stack view-style animation.
+  [self.contentArea addSubview:newPage];
+
+  auto animationCompletion = ^{
+    [newPage removeFromSuperview];
+    commonCompletion();
+    // Restore content area frame, which was resized to fullscreen for
+    // NTP opening animation.
+    CGRect contentAreaFrame = self.view.bounds;
+    if (!self.usesFullscreenContainer) {
+      contentAreaFrame.origin.y += StatusBarHeight();
+      contentAreaFrame.size.height -= StatusBarHeight();
+    }
+    self.contentArea.frame = contentAreaFrame;
+  };
+
   page_animation_util::AnimateInPaperWithAnimationAndCompletion(
-      newPage, -newPageOffset, offset, origin, _isOffTheRecord, NULL, ^{
-        tab.view.frame = self.contentArea.bounds;
-        newPage.userInteractionEnabled = YES;
-        [newPage removeFromSuperview];
-        self.inNewTabAnimation = NO;
-        // Use the model's currentTab here because it is possible that it can
-        // be reset to a new value before the new Tab animation finished (e.g.
-        // if another Tab shows a dialog via |dialogPresenter|). However, that
-        // tab's view hasn't been displayed yet because it was in a new tab
-        // animation.
-        Tab* currentTab = [_model currentTab];
-        if (currentTab) {
-          [self tabSelected:currentTab notifyToolbar:NO];
-        }
-        completion();
-
-        if (self.foregroundTabWasAddedCompletionBlock) {
-          self.foregroundTabWasAddedCompletionBlock();
-          self.foregroundTabWasAddedCompletionBlock = nil;
-        }
-
-        // Restore content area frame, which was resized to fullscreen for
-        // NTP opening animation.
-        CGRect contentAreaFrame = self.view.bounds;
-        if (!self.usesFullscreenContainer) {
-          contentAreaFrame.origin.y += StatusBarHeight();
-          contentAreaFrame.size.height -= StatusBarHeight();
-        }
-        self.contentArea.frame = contentAreaFrame;
-      });
+      newPage, -newPageOffset, offset, origin, _isOffTheRecord, NULL,
+      animationCompletion);
 }
 
 - (void)animateNewTabInBackgroundFromPoint:(CGPoint)originPoint
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
index 5296341..6658a656 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -8,6 +8,7 @@
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/ui/commands/load_query_commands.h"
 #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_mediator.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
@@ -17,6 +18,7 @@
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h"
 #import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h"
+#import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -53,6 +55,8 @@
   self.viewController =
       [[OmniboxViewController alloc] initWithIncognito:isIncognito];
 
+  self.viewController.dispatcher =
+      static_cast<id<LoadQueryCommands, OmniboxFocuser>>(self.dispatcher);
   self.mediator = [[OmniboxMediator alloc] init];
   self.mediator.consumer = self.viewController;
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index fdeb4f3..49651d4 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -330,8 +330,8 @@
                 completionAnimator:(UIViewPropertyAnimator*)completionAnimator {
   DCHECK(!IsRefreshLocationBarEnabled());
 
-  // Hide the rightView button so its not visibile on its initial layout
-  // while the expan animation is happening.
+  // Hide the rightView button so it's not visible on its initial layout
+  // while the expand animation is happening.
   self.clearButtonView.hidden = YES;
   self.clearButtonView.alpha = 0;
   self.clearButtonView.frame =
@@ -577,7 +577,7 @@
   }
 
   // iOS9 added updated RTL support, but only half implemented it for
-  // UITextField. leftView and rightView were not renamed, but are are correctly
+  // UITextField. leftView and rightView were not renamed, but are correctly
   // swapped and treated as leadingView / trailingView.  However,
   // -leftViewRectForBounds and -rightViewRectForBounds are *not* treated as
   // leading and trailing.  Hence the swapping below.
@@ -689,26 +689,34 @@
 }
 
 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
-  // Disable the "Define" menu item.  iOS7 implements this with a private
-  // selector.  Avoid using private APIs by instead doing a string comparison.
-  if ([NSStringFromSelector(action) hasSuffix:@"define:"]) {
-    return NO;
+  // If there is selected text, show copy and cut.
+  if ([self textInRange:self.selectedTextRange].length > 0 &&
+      (action == @selector(cut:) || action == @selector(copy:))) {
+    return YES;
   }
 
-  // Disable the RTL arrow menu item. The omnibox sets alignment based on the
-  // text in the field, and should not be overridden.
-  if ([NSStringFromSelector(action) hasPrefix:@"makeTextWritingDirection"]) {
-    return NO;
+  // If there is no selected text, show select and selectAll.
+  if ([self textInRange:self.selectedTextRange].length == 0 &&
+      (action == @selector(select:) || action == @selector(selectAll:))) {
+    return YES;
   }
 
-  if ([self isPreEditing]) {
-    // Allow cut/copy/paste in preedit.
-    if ((action == @selector(copy:)) || (action == @selector(cut:))) {
-      return YES;
-    }
+  // If there is pasteboard content, show paste.
+  if (UIPasteboard.generalPasteboard.string.length > 0 && action == @selector
+                                                              (paste:)) {
+    return YES;
   }
 
-  return [super canPerformAction:action withSender:sender];
+  // Note that this NO does not keep other elements in the responder chain from
+  // adding actions they handle to the menu.
+  // No special handling is necessary for pre-edit and autocomplete states.
+  // In pre-edit, the text in the textfield is selected even though it is not
+  // shown. so the behavior is correct. As an aside, the only way to access the
+  // editing menu without exiting the pre-edit state is via accessibility
+  // features. For inline autocomplete, any action on the textfield first
+  // accepts the autocompletion and unselects the text. It is therefore not
+  // possible to open the editing menu in this state.
+  return NO;
 }
 
 #pragma mark Copy/Paste
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
index 540a6f6..c6936d2 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
@@ -11,6 +11,9 @@
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
 #import "ios/chrome/browser/ui/orchestrator/location_bar_offset_provider.h"
 
+@protocol LoadQueryCommands;
+@protocol OmniboxFocuser;
+
 // The view controller managing the omnibox textfield and its container view.
 @interface OmniboxViewController
     : UIViewController<LocationBarOffsetProvider, OmniboxConsumer>
@@ -21,6 +24,9 @@
 // Designated initializer.
 - (instancetype)initWithIncognito:(BOOL)isIncognito;
 
+// The dispatcher for the paste and go action.
+@property(nonatomic, weak) id<LoadQueryCommands, OmniboxFocuser> dispatcher;
+
 @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 1be003e..1d2944dd 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -5,8 +5,10 @@
 #import "ios/chrome/browser/ui/omnibox/omnibox_view_controller.h"
 
 #include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/ui/commands/load_query_commands.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_container_view.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_constants.h"
+#import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -34,6 +36,7 @@
 
 @implementation OmniboxViewController
 @synthesize incognito = _incognito;
+@synthesize dispatcher = _dispatcher;
 @dynamic view;
 
 - (instancetype)initWithIncognito:(BOOL)isIncognito {
@@ -72,6 +75,13 @@
 - (void)viewDidLoad {
   [super viewDidLoad];
 
+  // Add Paste and Go option to the editing menu
+  UIMenuController* menu = [UIMenuController sharedMenuController];
+  UIMenuItem* pasteAndGo = [[UIMenuItem alloc]
+      initWithTitle:l10n_util::GetNSString(IDS_IOS_PASTE_AND_GO)
+             action:NSSelectorFromString(@"pasteAndGo:")];
+  [menu setMenuItems:@[ pasteAndGo ]];
+
   self.textField.placeholderTextColor = [self placeholderAndClearButtonColor];
   self.textField.placeholder = l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT);
   [self setupClearButton];
@@ -175,4 +185,21 @@
                                            : UITextFieldViewModeNever];
 }
 
+#pragma mark - UIMenuItem
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
+  if (UIPasteboard.generalPasteboard.string.length > 0 && action == @selector
+                                                              (pasteAndGo:)) {
+    return YES;
+  }
+
+  return NO;
+}
+
+- (void)pasteAndGo:(id)sender {
+  [self.dispatcher loadQuery:UIPasteboard.generalPasteboard.string
+                 immediately:YES];
+  [self.dispatcher cancelOmniboxEdit];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index fe75645b..0ffa923 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -92,10 +92,6 @@
 // The UI displays relative time for up to this number of hours and then
 // switches to absolute values.
 const int kRelativeTimeMaxHours = 4;
-// Height for single line headers.
-const CGFloat kSingleLineSectionHeaderHeight = 44;
-// Height for double line headers.
-const CGFloat kDoubleLineSectionHeaderHeight = 56;
 // Section index for recently closed tabs.
 const int kRecentlyClosedTabsSectionIndex = 0;
 
@@ -637,24 +633,17 @@
   }
 }
 
-// TODO(crbug.com/850814): Use estimatedSectionHeaderHeight once we stop
-// supporting iOS10.
+// TODO(crbug.com/850814): Use only dynamic sizing once we stop supporting
+// iOS10.
 - (CGFloat)tableView:(UITableView*)tableView
     heightForHeaderInSection:(NSInteger)section {
   DCHECK_EQ(tableView, self.tableView);
   if (@available(iOS 11, *)) {
     return UITableViewAutomaticDimension;
   } else {
-    NSInteger sectionIdentifier =
-        [self.tableViewModel sectionIdentifierForSection:section];
-    switch (sectionIdentifier) {
-      case SectionIdentifierRecentlyClosedTabs:
-      case SectionIdentifierOtherDevices:
-        return kSingleLineSectionHeaderHeight;
-      default:
-        // All remote session sections.
-        return kDoubleLineSectionHeaderHeight;
-    }
+    TableViewHeaderFooterItem* header =
+        [self.tableViewModel headerForSection:section];
+    return [header headerHeightForWidth:self.view.bounds.size.width];
   }
 }
 
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 027ade5..f9645b0a 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -21,6 +21,7 @@
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_page_control.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h"
+#import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
@@ -87,6 +88,8 @@
 @property(nonatomic, assign) TabGridConfiguration configuration;
 // Setting the current page will adjust the scroll view to the correct position.
 @property(nonatomic, assign) TabGridPage currentPage;
+// The frame of |self.view| when it initially appeared.
+@property(nonatomic, assign) CGRect initialFrame;
 @end
 
 @implementation TabGridViewController
@@ -115,6 +118,7 @@
 @synthesize floatingButton = _floatingButton;
 @synthesize configuration = _configuration;
 @synthesize currentPage = _currentPage;
+@synthesize initialFrame = _initialFrame;
 
 - (instancetype)init {
   if (self = [super init]) {
@@ -159,6 +163,10 @@
   [super viewWillAppear:animated];
 }
 
+- (void)viewDidAppear:(BOOL)animated {
+  self.initialFrame = self.view.frame;
+}
+
 - (void)viewWillDisappear:(BOOL)animated {
   self.undoCloseAllAvailable = NO;
   [self.regularTabsDelegate discardSavedClosedItems];
@@ -173,17 +181,15 @@
   [super viewWillDisappear:animated];
 }
 
-- (void)viewWillLayoutSubviews {
-  [super viewWillLayoutSubviews];
+- (void)viewDidLayoutSubviews {
+  [super viewDidLayoutSubviews];
+
   // Call the current page setter to sync the scroll view offset to the current
   // page value, if the scroll view isn't scrolling. Don't animate this.
   if (!self.scrollView.dragging && !self.scrollView.decelerating) {
     self.currentPage = _currentPage;
   }
-}
 
-- (void)viewDidLayoutSubviews {
-  [super viewDidLayoutSubviews];
   // The content inset of the tab grids must be modified so that the toolbars
   // do not obscure the tabs. This may change depending on orientation.
   CGFloat bottomInset = self.configuration == TabGridConfigurationBottomToolbar
@@ -290,8 +296,12 @@
     (id<UIViewControllerContextTransitioning>)context {
   GridViewController* gridViewController =
       [self gridViewControllerForPage:self.activePage];
-  return gridViewController == nil ? nil
-                                   : [gridViewController transitionLayout];
+  if (!gridViewController)
+    return nil;
+
+  GridTransitionLayout* layout = [gridViewController transitionLayout];
+  layout.frameChanged = !CGRectEqualToRect(self.view.frame, self.initialFrame);
+  return layout;
 }
 
 - (UIView*)proxyContainerForTransitionContext:
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
index b6b655c..d0ab6bf1 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
@@ -215,13 +215,12 @@
 }
 
 - (void)buildExpandingAnimations {
-  // The transition is structured as four or six separate animations. They are
+  // The transition is structured as four to six separate animations. They are
   // timed based on two sub-durations which are expressed as fractions of the
   // overall animation duration.
   CGFloat partialDuration = 0.66;
   CGFloat briefDuration = 0.3;
-  CGFloat veryBriefDuration = 0.2;
-  CGFloat delay = (1.0 - veryBriefDuration) / 2.0;
+  CGFloat delay = 0.1;
 
   // Damping ratio for the resize animation.
   CGFloat resizeDamping = 0.7;
@@ -230,13 +229,14 @@
   //   (A) Zooming the active cell out into the expanded position.
   //   (B) Crossfading the active cell's top views.
   //   (C) Squaring the corners of the active cell.
-  //   (D) Fading out the main cell view and fading in the main tab view.
+  //   (D) Fading out the main cell view and fading in the main tab view, if
+  //       necessary.
   // These parts are timed over |duration| like this:
   //
   //  {0%}--[A]-----------------------------------{100%}
   //  {0%}--[B]---{30%}
   //  {0%}--[C]---{30%}
-  //                   {40%}-[D]-{60%}
+  //    {10%}--[D]---{40%}
 
   // If there's more than once cell, the animation adds:
   //   (E) Scaling the inactive cells to 95%
@@ -246,7 +246,7 @@
   //  {0%}--[A]-----------------------------------{100%}
   //  {0%}--[B]---{30%}
   //  {0%}--[C]---{30%}
-  //                   {40%}-[D]-{60%}
+  //    {10%}--[D]---{40%}
   //  {0%}--[E]-----------------------------------{100%}
   //  {0%}--[F]-------------------{66%}
   //
@@ -302,25 +302,28 @@
             animations:squareCornersKeyframeAnimation];
   [self.animations addAnimator:squareCorners];
 
-  // D: crossfade the main cell content.
-  // Two notes on this transition. (1) In cases where the cell and tab views are
-  // the same, having both alphas change at the same time means the overall
-  // transition is seamless. (2) using a linear animation curve means that the
-  // sum of the opacities is contstant though the animation, which will help it
-  // seem less abrupt by keeping a relatively constant brightness.
-  auto crossfadeContentAnimation =
-      [self keyframeAnimationWithRelativeStart:delay
-                              relativeDuration:veryBriefDuration
-                                    animations:^{
-                                      activeCell.mainCellView.alpha = 0;
-                                      activeCell.mainTabView.alpha = 1.0;
-                                    }];
-  UIViewPropertyAnimator* crossfadeContent = [[UIViewPropertyAnimator alloc]
-      initWithDuration:self.duration
-                 curve:UIViewAnimationCurveLinear
-            animations:crossfadeContentAnimation];
-  [self.animations addAnimator:crossfadeContent];
-
+  // D: crossfade the main cell content, if necessary.
+  // This crossfade is needed if the aspect ratio of the tab being animated
+  // to doesn't match the aspect ratio of the tab that originally generated the
+  // cell content being animated; this happens when the tab grid is exited in a
+  // diffferent orientation than it was entered.
+  // Using a linear animation curve means that the sum of the opacities is
+  // contstant though the animation, which will help it seem less abrupt by
+  // keeping a relatively constant brightness.
+  if (self.layout.frameChanged) {
+    auto crossfadeContentAnimation =
+        [self keyframeAnimationWithRelativeStart:delay
+                                relativeDuration:briefDuration
+                                      animations:^{
+                                        activeCell.mainCellView.alpha = 0;
+                                        activeCell.mainTabView.alpha = 1.0;
+                                      }];
+    UIViewPropertyAnimator* crossfadeContent = [[UIViewPropertyAnimator alloc]
+        initWithDuration:self.duration
+                   curve:UIViewAnimationCurveLinear
+              animations:crossfadeContentAnimation];
+    [self.animations addAnimator:crossfadeContent];
+  }
   // If there's only a single cell, that's all.
   if (self.layout.inactiveItems.count == 0)
     return;
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h
index c596ca8..b966d5d0 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h
@@ -30,7 +30,11 @@
 @property(nonatomic, strong, readonly) GridTransitionItem* selectionItem;
 
 // The rect, in UIWindow coordinates, that an "expanded" item should occupy.
-@property(nonatomic) CGRect expandedRect;
+@property(nonatomic, assign) CGRect expandedRect;
+
+// YES if the initial frame of the grid is different from the frame used for
+// the animation.
+@property(nonatomic, assign) BOOL frameChanged;
 
 // Creates a new layout object.
 // |inactiveItems| should be non-nil, but it may be empty.
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
index eb036dc..c07118b1 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
@@ -23,6 +23,7 @@
 @synthesize selectionItem = _selectionItem;
 @synthesize inactiveItems = _inactiveItems;
 @synthesize expandedRect = _expandedRect;
+@synthesize frameChanged = _frameChanged;
 
 + (instancetype)layoutWithInactiveItems:(NSArray<GridTransitionItem*>*)items
                              activeItem:(GridTransitionActiveItem*)activeItem
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm b/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm
index f1e42f6..5a78763 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm
@@ -65,6 +65,10 @@
   [containerView insertSubview:gridView belowSubview:dismissingView];
   gridView.frame =
       [transitionContext finalFrameForViewController:gridViewController];
+  // Normally this view will layout before it's displayed, but in order to build
+  // the layout for the animation, |gridView|'s layout needs to be current, so
+  // force an update here.
+  [gridView layoutIfNeeded];
 
   // Ask the state provider for the views to use when inserting the animation.
   UIView* proxyContainer =
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_activity_indicator_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_activity_indicator_header_footer_item.mm
index 82184906..fde3071e 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_activity_indicator_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_activity_indicator_header_footer_item.mm
@@ -41,6 +41,22 @@
     header.titleLabel.textColor = styler.headerFooterTitleColor;
 }
 
+- (CGFloat)headerHeightForWidth:(CGFloat)width {
+  static TableViewActivityIndicatorHeaderFooterView* header;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    header = [[TableViewActivityIndicatorHeaderFooterView alloc] init];
+  });
+
+  [self configureHeaderFooterView:header
+                       withStyler:[[ChromeTableViewStyler alloc] init]];
+  header.frame = CGRectMake(0, 0, width, 0);
+  [header setNeedsLayout];
+  [header layoutIfNeeded];
+  return
+      [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
+}
+
 @end
 
 #pragma mark - TableViewActivityIndicatorHeaderFooterView
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
index 005b264..cf73c92 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
@@ -52,6 +52,22 @@
     header.titleLabel.textColor = styler.headerFooterTitleColor;
 }
 
+- (CGFloat)headerHeightForWidth:(CGFloat)width {
+  static TableViewDisclosureHeaderFooterView* header;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    header = [[TableViewDisclosureHeaderFooterView alloc] init];
+  });
+
+  [self configureHeaderFooterView:header
+                       withStyler:[[ChromeTableViewStyler alloc] init]];
+  header.frame = CGRectMake(0, 0, width, 0);
+  [header setNeedsLayout];
+  [header layoutIfNeeded];
+  return
+      [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
+}
+
 @end
 
 #pragma mark - TableViewDisclosureHeaderFooterView
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h
index 8bdf2f2..ba9326b 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h
@@ -23,6 +23,10 @@
                        withStyler:(ChromeTableViewStyler*)styler
     NS_REQUIRES_SUPER;
 
+// TODO(crbug.com/850814):Use only dynamic sizing once we stop supporting iOS10,
+// we can delete this method then. Returns the height this item's header would
+// need to be to fit within |width|.
+- (CGFloat)headerHeightForWidth:(CGFloat)width;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_HEADER_FOOTER_ITEM_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
index 337b3b4..8b1a37cc 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
@@ -30,4 +30,20 @@
   headerFooter.backgroundView = visualEffect;
 }
 
+- (CGFloat)headerHeightForWidth:(CGFloat)width {
+  static UITableViewHeaderFooterView* header;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    header = [[UITableViewHeaderFooterView alloc] init];
+  });
+
+  [self configureHeaderFooterView:header
+                       withStyler:[[ChromeTableViewStyler alloc] init]];
+  header.frame = CGRectMake(0, 0, width, 0);
+  [header setNeedsLayout];
+  [header layoutIfNeeded];
+  return
+      [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm
index 1de4fdb..6cc4af3 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.mm
@@ -28,6 +28,8 @@
 const CGFloat buttonTitleVerticalContentInset = 8.0;
 // Button corner radius.
 const CGFloat buttonCornerRadius = 8;
+// Font Size for Button Title Label.
+const CGFloat buttonTitleFontSize = 17.0;
 }  // namespace
 
 @implementation TableViewTextButtonItem
@@ -83,7 +85,7 @@
                       forState:UIControlStateNormal];
     self.button.translatesAutoresizingMaskIntoConstraints = NO;
     [self.button.titleLabel
-        setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]];
+        setFont:[UIFont boldSystemFontOfSize:buttonTitleFontSize]];
     self.button.layer.cornerRadius = buttonCornerRadius;
     self.button.clipsToBounds = YES;
     self.button.contentEdgeInsets = UIEdgeInsetsMake(
diff --git a/ios/chrome/browser/ui/tabs/BUILD.gn b/ios/chrome/browser/ui/tabs/BUILD.gn
index 7d09fa6..9685745 100644
--- a/ios/chrome/browser/ui/tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/tabs/BUILD.gn
@@ -7,6 +7,8 @@
   sources = [
     "background_tab_animation_view.h",
     "background_tab_animation_view.mm",
+    "foreground_tab_animation_view.h",
+    "foreground_tab_animation_view.mm",
     "tab_strip_controller+placeholder_view.h",
     "tab_strip_controller.h",
     "tab_strip_controller.mm",
diff --git a/ios/chrome/browser/ui/tabs/foreground_tab_animation_view.h b/ios/chrome/browser/ui/tabs/foreground_tab_animation_view.h
new file mode 100644
index 0000000..aec7289
--- /dev/null
+++ b/ios/chrome/browser/ui/tabs/foreground_tab_animation_view.h
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TABS_FOREGROUND_TAB_ANIMATION_VIEW_H_
+#define IOS_CHROME_BROWSER_UI_TABS_FOREGROUND_TAB_ANIMATION_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+// View used to contain an animation of a new tab opening in the foreground.
+// A content subview animates to fill the view while the background fades to
+// black.
+@interface ForegroundTabAnimationView : UIView
+
+// The content view (typically the new tab's view) to animate.
+@property(nonatomic, strong) UIView* contentView;
+
+// Starts a New Tab animation in |parentView|, from |originPoint| with
+// a |completion| block. The new tab will scale up and move from the direction
+// if |originPoint| to the center of the reciever. |originPoint| must be in
+// UIWindow coordinates.
+- (void)animateFrom:(CGPoint)originPoint withCompletion:(void (^)())completion;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TABS_FOREGROUND_TAB_ANIMATION_VIEW_H_
diff --git a/ios/chrome/browser/ui/tabs/foreground_tab_animation_view.mm b/ios/chrome/browser/ui/tabs/foreground_tab_animation_view.mm
new file mode 100644
index 0000000..dcde80d0b
--- /dev/null
+++ b/ios/chrome/browser/ui/tabs/foreground_tab_animation_view.mm
@@ -0,0 +1,130 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/tabs/foreground_tab_animation_view.h"
+
+#import "ios/chrome/browser/ui/util/property_animator_group.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const NSTimeInterval kAnimationDuration = 0.75;
+const CGFloat kTabMotionDamping = 0.7;
+const CGFloat kTabFadeInRelativeDuration = 0.4;
+const CGFloat kBackgroundFadeRelativeDuration = 0.33;
+const CGFloat kCornerRoundingRelativeDuration = 0.33;
+const CGFloat kInitialTabScale = 0.75;
+const CGFloat kInitialTabCornerRadius = 26.0;
+const CGFloat kPositionCoefficient = 0.25;
+}  // namespace
+
+@implementation ForegroundTabAnimationView
+
+@synthesize contentView = _contentView;
+
+- (void)setContentView:(UIView*)contentView {
+  [_contentView removeFromSuperview];
+  [self addSubview:contentView];
+  _contentView = contentView;
+}
+
+- (void)animateFrom:(CGPoint)originPoint withCompletion:(void (^)())completion {
+  CGPoint origin = [self convertPoint:originPoint fromView:nil];
+  self.contentView.frame = self.bounds;
+  self.backgroundColor = UIColor.clearColor;
+
+  // Translate the content view part of the way from the center of this view to
+  // |originPoint|.
+  CGFloat dx = kPositionCoefficient * (origin.x - self.contentView.center.x);
+  CGFloat dy = kPositionCoefficient * (origin.y - self.contentView.center.y);
+
+  CGAffineTransform transform = self.contentView.transform;
+  transform = CGAffineTransformTranslate(transform, dx, dy);
+  transform =
+      CGAffineTransformScale(transform, kInitialTabScale, kInitialTabScale);
+
+  self.contentView.transform = transform;
+  self.contentView.alpha = 0;
+  self.contentView.layer.cornerRadius = kInitialTabCornerRadius;
+  self.contentView.clipsToBounds = YES;
+
+  // Animation components.
+  auto tabResizeAnimation = ^{
+    self.contentView.transform = CGAffineTransformIdentity;
+  };
+  auto tabFadeAnimation = ^{
+    self.contentView.alpha = 1.0;
+  };
+  auto backgroundFadeAnimation = ^{
+    self.backgroundColor = UIColor.blackColor;
+  };
+  auto cornerAnimation = ^{
+    self.contentView.layer.cornerRadius = 0.0;
+  };
+
+  PropertyAnimatorGroup* animations = [[PropertyAnimatorGroup alloc] init];
+
+  // Motion animation runs for the whole duration with a spring effect.
+  // Because of the spring effect, the total duration needs to be quite long
+  // or else the animation will feel very abrupt.
+  UIViewPropertyAnimator* motionAnimation =
+      [[UIViewPropertyAnimator alloc] initWithDuration:kAnimationDuration
+                                          dampingRatio:kTabMotionDamping
+                                            animations:tabResizeAnimation];
+
+  // Tab fades in over the first half of the overall animation, easing out (so
+  // most of the fade happens sooner).
+  auto tabfadeAnimationKeyframes = ^{
+    [UIView addKeyframeWithRelativeStartTime:0
+                            relativeDuration:kTabFadeInRelativeDuration
+                                  animations:tabFadeAnimation];
+
+  };
+  UIViewPropertyAnimator* tabfadeAnimation = [[UIViewPropertyAnimator alloc]
+      initWithDuration:kAnimationDuration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:^{
+              [UIView animateKeyframesWithDuration:kAnimationDuration
+                                             delay:0
+                                           options:0
+                                        animations:tabfadeAnimationKeyframes
+                                        completion:nil];
+            }];
+
+  // Additional animations happen in the first third of the overall animation,
+  // and are linear.
+  auto additionalAnimationsKeyframes = ^{
+    [UIView addKeyframeWithRelativeStartTime:0
+                            relativeDuration:kBackgroundFadeRelativeDuration
+                                  animations:backgroundFadeAnimation];
+    [UIView addKeyframeWithRelativeStartTime:0
+                            relativeDuration:kCornerRoundingRelativeDuration
+                                  animations:cornerAnimation];
+  };
+  UIViewPropertyAnimator* additionalAnimations = [[UIViewPropertyAnimator alloc]
+      initWithDuration:kAnimationDuration
+                 curve:UIViewAnimationCurveLinear
+            animations:^{
+              [UIView animateKeyframesWithDuration:kAnimationDuration
+                                             delay:0
+                                           options:0
+                                        animations:additionalAnimationsKeyframes
+                                        completion:nil];
+            }];
+
+  [animations addAnimator:motionAnimation];
+  [animations addAnimator:tabfadeAnimation];
+  [animations addAnimator:additionalAnimations];
+
+  [animations addCompletion:^(UIViewAnimatingPosition finalPosition) {
+    self.contentView.clipsToBounds = NO;
+    completion();
+  }];
+
+  [animations startAnimation];
+}
+
+@end
diff --git a/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.cc b/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.cc
index 835e5070..32690f9 100644
--- a/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.cc
+++ b/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.cc
@@ -16,7 +16,7 @@
 void UnifiedConsentServiceClientImpl::SetAlternateErrorPagesEnabled(
     bool enabled) {
   // Feature not available on iOS.
-  NOTREACHED();
+  NOTIMPLEMENTED();
 }
 
 void UnifiedConsentServiceClientImpl::SetMetricsReportingEnabled(bool enabled) {
@@ -34,13 +34,13 @@
 
 void UnifiedConsentServiceClientImpl::SetSafeBrowsingEnabled(bool enabled) {
   // Feature not available on iOS.
-  NOTREACHED();
+  NOTIMPLEMENTED();
 }
 
 void UnifiedConsentServiceClientImpl::SetSafeBrowsingExtendedReportingEnabled(
     bool enabled) {
   // Feature not available on iOS.
-  NOTREACHED();
+  NOTIMPLEMENTED();
 }
 
 void UnifiedConsentServiceClientImpl::SetNetworkPredictionEnabled(
@@ -52,3 +52,8 @@
   wifiPreference.Init(prefs::kNetworkPredictionWifiOnly, pref_service_);
   wifiPreference.SetValue(enabled);
 }
+
+void UnifiedConsentServiceClientImpl::SetSpellCheckEnabled(bool enabled) {
+  // Feature not available on iOS.
+  NOTIMPLEMENTED();
+}
diff --git a/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.h b/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.h
index 88339c0..1a424d3 100644
--- a/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.h
+++ b/ios/chrome/browser/unified_consent/unified_consent_service_client_impl.h
@@ -23,6 +23,7 @@
   void SetSafeBrowsingEnabled(bool enabled) override;
   void SetSafeBrowsingExtendedReportingEnabled(bool enabled) override;
   void SetNetworkPredictionEnabled(bool enabled) override;
+  void SetSpellCheckEnabled(bool enabled) override;
 
  private:
   PrefService* pref_service_;
diff --git a/ios/chrome/browser/web/forms_egtest.mm b/ios/chrome/browser/web/forms_egtest.mm
index b99f6275..ea3e1a3 100644
--- a/ios/chrome/browser/web/forms_egtest.mm
+++ b/ios/chrome/browser/web/forms_egtest.mm
@@ -44,6 +44,9 @@
 // Response shown on the page of |GetDestinationUrl|.
 const char kDestinationText[] = "bar!";
 
+// Response shown on the page of |GetGenericUrl|.
+const char kGenericText[] = "A generic page";
+
 // Label for the button in the form.
 const char kSubmitButtonLabel[] = "submit";
 
@@ -117,7 +120,7 @@
 
   *headers = web::ResponseProvider::GetDefaultResponseHeaders();
   if (url == GetGenericUrl()) {
-    *response_body = "A generic page";
+    *response_body = kGenericText;
     return;
   }
   if (url == GetFormPostOnSamePageUrl()) {
@@ -156,6 +159,12 @@
   return grey_allOf(grey_accessibilityID(@"Go"), grey_interactable(), nil);
 }
 
+// Matcher for the resend POST button in the repost warning dialog.
+id<GREYMatcher> ResendPostButtonMatcher() {
+  return chrome_test_util::ButtonWithAccessibilityLabelId(
+      IDS_HTTP_POST_WARNING_RESEND);
+}
+
 // Waits for view with Tab History accessibility ID.
 - (void)waitForTabHistoryView {
   GREYCondition* condition = [GREYCondition
@@ -182,10 +191,7 @@
 
 // Accepts the warning that the form POST data will be reposted.
 - (void)confirmResendWarning {
-  id<GREYMatcher> resendWarning =
-      chrome_test_util::ButtonWithAccessibilityLabelId(
-          IDS_HTTP_POST_WARNING_RESEND);
-  [[EarlGrey selectElementWithMatcher:resendWarning]
+  [[EarlGrey selectElementWithMatcher:ResendPostButtonMatcher()]
       performAction:grey_longPress()];
 }
 
@@ -193,7 +199,7 @@
 // |GetFormUrl|, and posts data to |GetDestinationUrl| upon submission.
 - (void)setUpFormTestSimpleHttpServer {
   std::map<GURL, std::string> responses;
-  responses[GetGenericUrl()] = "A generic page";
+  responses[GetGenericUrl()] = kGenericText;
   responses[GetFormUrl()] =
       base::StringPrintf(kFormHtmlTemplate, GetDestinationUrl().spec().c_str());
   responses[GetDestinationUrl()] = kDestinationText;
@@ -331,6 +337,42 @@
       assertWithMatcher:grey_interactable()];
 }
 
+// A new navigation dismisses the repost dialog.
+- (void)testRepostFormDismissedByNewNavigation {
+  [self setUpFormTestSimpleHttpServer];
+  const GURL destinationURL = GetDestinationUrl();
+
+  [ChromeEarlGrey loadURL:GetFormUrl()];
+  GREYAssert(TapWebViewElementWithId(kSubmitButtonLabel), @"Failed to tap %s",
+             kSubmitButtonLabel);
+  [ChromeEarlGrey waitForWebViewContainingText:kDestinationText];
+  [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())]
+      assertWithMatcher:grey_notNil()];
+
+  // WKBasedNavigationManager presents repost confirmation dialog before loading
+  // stops.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload];
+  } else {
+    // Legacy navigation manager presents repost confirmation dialog after
+    // loading stops.
+    [ChromeEarlGrey reload];
+  }
+
+  // Repost confirmation box should be visible.
+  [ChromeEarlGrey
+      waitForElementWithMatcherSufficientlyVisible:ResendPostButtonMatcher()];
+
+  // Starting a new navigation while the repost dialog is presented should not
+  // crash.
+  [ChromeEarlGrey loadURL:GetGenericUrl()];
+  [ChromeEarlGrey waitForWebViewContainingText:kGenericText];
+
+  // Repost dialog should not be visible anymore.
+  [[EarlGrey selectElementWithMatcher:ResendPostButtonMatcher()]
+      assertWithMatcher:grey_not(grey_sufficientlyVisible())];
+}
+
 // Tests that pressing the button on a POST-based form changes the page and that
 // the back button works as expected afterwards.
 - (void)testGoBackButtonAfterFormSubmission {
@@ -370,9 +412,7 @@
   [ChromeEarlGrey reload];
 
   // Check that the popup did not show
-  id<GREYMatcher> resendWarning =
-      ButtonWithAccessibilityLabelId(IDS_HTTP_POST_WARNING_RESEND);
-  [[EarlGrey selectElementWithMatcher:resendWarning]
+  [[EarlGrey selectElementWithMatcher:ResendPostButtonMatcher()]
       assertWithMatcher:grey_nil()];
   [ChromeEarlGrey waitForWebViewContainingText:"GET"];
   [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())]
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index 21e18e0..1c40926 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -12,20 +12,6 @@
   ]
 }
 
-source_set("ios_test_support") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-
-  deps = [
-    "//base/test:test_support",
-  ]
-
-  sources = [
-    "wait_util.h",
-    "wait_util.mm",
-  ]
-}
-
 source_set("embedded_test_server_support") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
diff --git a/ios/testing/wait_util.h b/ios/testing/wait_util.h
deleted file mode 100644
index 2c4504c..0000000
--- a/ios/testing/wait_util.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_TESTING_WAIT_UTIL_H_
-#define IOS_TESTING_WAIT_UTIL_H_
-
-#import <Foundation/Foundation.h>
-
-#include "base/compiler_specific.h"
-#import "base/ios/block_types.h"
-
-namespace testing {
-
-// Constant for UI wait loop in seconds.
-extern const NSTimeInterval kSpinDelaySeconds;
-
-// Constant for timeout in seconds while waiting for UI element.
-extern const NSTimeInterval kWaitForUIElementTimeout;
-
-// Constant for timeout in seconds while waiting for JavaScript completion.
-extern const NSTimeInterval kWaitForJSCompletionTimeout;
-
-// Constant for timeout in seconds while waiting for a download to complete.
-extern const NSTimeInterval kWaitForDownloadTimeout;
-
-// Constant for timeout in seconds while waiting for a pageload to complete.
-extern const NSTimeInterval kWaitForPageLoadTimeout;
-
-// Constant for timeout in seconds while waiting for a generic action to
-// complete.
-extern const NSTimeInterval kWaitForActionTimeout;
-
-// Constant for timeout in seconds while waiting for cookies operations to
-// complete.
-extern const NSTimeInterval kWaitForCookiesTimeout;
-
-// Constant for timeout in seconds while waiting for a file operation to
-// complete.
-extern const NSTimeInterval kWaitForFileOperationTimeout;
-
-// Returns true when condition() becomes true, otherwise returns false after
-// |timeout|.
-bool WaitUntilConditionOrTimeout(NSTimeInterval timeout,
-                                 ConditionBlock condition) WARN_UNUSED_RESULT;
-
-}  // namespace testing
-
-#endif  // IOS_TESTING_WAIT_UTIL_H_
diff --git a/ios/testing/wait_util.mm b/ios/testing/wait_util.mm
deleted file mode 100644
index 8ab49ec..0000000
--- a/ios/testing/wait_util.mm
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/testing/wait_util.h"
-
-#import "base/test/ios/wait_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace testing {
-
-const NSTimeInterval kSpinDelaySeconds = 0.01;
-const NSTimeInterval kWaitForJSCompletionTimeout = 4.0;
-const NSTimeInterval kWaitForUIElementTimeout = 4.0;
-const NSTimeInterval kWaitForDownloadTimeout = 10.0;
-const NSTimeInterval kWaitForPageLoadTimeout = 10.0;
-const NSTimeInterval kWaitForActionTimeout = 10.0;
-const NSTimeInterval kWaitForCookiesTimeout = 4.0;
-const NSTimeInterval kWaitForFileOperationTimeout = 2.0;
-
-bool WaitUntilConditionOrTimeout(NSTimeInterval timeout,
-                                 ConditionBlock condition) {
-  NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:timeout];
-  bool success = condition();
-  while (!success && [[NSDate date] compare:deadline] != NSOrderedDescending) {
-    base::test::ios::SpinRunLoopWithMaxDelay(
-        base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds));
-    success = condition();
-  }
-  return success;
-}
-
-}  // namespace testing
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm
index 816391c6..d0b37e4 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -108,9 +108,18 @@
 
   // Transient item is only supposed to be added for pending non-app-specific
   // navigations.
-  NavigationItem* pending_item = GetPendingItem();
-  DCHECK(pending_item->GetUserAgentType() != UserAgentType::NONE);
-  transient_item_->SetUserAgentType(pending_item->GetUserAgentType());
+  // TODO(crbug.com/865727): captive portal detection seems to call this code
+  // without there being a pending item. This may be an improper use of
+  // navigation manager.
+  NavigationItem* item = GetPendingItem();
+  if (!item)
+    item = GetLastCommittedNonAppSpecificItem();
+  // Item may still be null in captive portal case if chrome://newtab is the
+  // only entry in back/forward history.
+  if (item) {
+    DCHECK(item->GetUserAgentType() != UserAgentType::NONE);
+    transient_item_->SetUserAgentType(item->GetUserAgentType());
+  }
 }
 
 void WKBasedNavigationManagerImpl::AddPendingItem(
diff --git a/ios/web_view/test/web_view_inttest.mm b/ios/web_view/test/web_view_inttest.mm
index b01b439..06f78c44 100644
--- a/ios/web_view/test/web_view_inttest.mm
+++ b/ios/web_view/test/web_view_inttest.mm
@@ -116,6 +116,4 @@
   EXPECT_NSNE(nil, error);
 }
 
-// TODO(crbug.com/862537): Write more tests.
-
 }  // namespace ios_web_view
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index f3fbc82a..f9aa336 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -357,6 +357,10 @@
 const base::Feature kAutoplayIgnoreWebAudio{"AutoplayIgnoreWebAudio",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Whether we should show the new unified sound and autoplay settings UI.
+const base::Feature kAutoplaySoundSettings{"AutoplaySoundSettings",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if defined(OS_ANDROID)
 // Enable a gesture to make the media controls expaned into the display cutout.
 const base::Feature kMediaControlsExpandGesture{
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index ac585b6..e047bb32 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -105,6 +105,7 @@
 // alongside the definition of their values in the .cc file.
 
 MEDIA_EXPORT extern const base::Feature kAutoplayIgnoreWebAudio;
+MEDIA_EXPORT extern const base::Feature kAutoplaySoundSettings;
 MEDIA_EXPORT extern const base::Feature kAv1Decoder;
 MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization;
 MEDIA_EXPORT extern const base::Feature kBackgroundVideoTrackOptimization;
diff --git a/net/base/port_util.cc b/net/base/port_util.cc
index f9bb531..fe3d0b30 100644
--- a/net/base/port_util.cc
+++ b/net/base/port_util.cc
@@ -87,9 +87,6 @@
     6668,    // Alternate IRC [Apple addition]
     6669,    // Alternate IRC [Apple addition]
     6697,    // IRC + TLS
-    0xFFFF,  // Used to block all invalid port numbers (see
-             // third_party/WebKit/Source/platform/weborigin/KURL.cpp,
-             // KURL::port())
 };
 
 // FTP overrides the following restricted port.
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index 0358d15..a82d74a 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -162,6 +162,9 @@
 const char kJSFieldFocusType[] = "formFocusChange";
 const char kJSFieldFocus[] = "focused";
 
+// Notify when a save attempt has occured (Plugin -> Page)
+const char kJSSaveCalledType[] = "saveCalled";
+
 const int kFindResultCooldownMs = 100;
 
 // Same value as printing::COMPLETE_PREVIEW_DOCUMENT_INDEX.
@@ -1908,6 +1911,12 @@
   return top_toolbar_height_in_viewport_coords_ * device_scale_;
 }
 
+void OutOfProcessInstance::SaveCalled() {
+  pp::VarDictionary message;
+  message.Set(pp::Var(kType), pp::Var(kJSSaveCalledType));
+  PostMessage(message);
+}
+
 void OutOfProcessInstance::ProcessPreviewPageInfo(const std::string& url,
                                                   int dest_page_index) {
   DCHECK(IsPrintPreview());
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 18ce432..ed808b6 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -152,6 +152,7 @@
   void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override;
   void IsEditModeChanged(bool is_edit_mode) override;
   float GetToolbarHeightInScreenCoords() override;
+  void SaveCalled() override;
 
   // PreviewModeClient::Client implementation.
   void PreviewDocumentLoadComplete() override;
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index b8be454..7ac39f9 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -275,6 +275,9 @@
     // Gets the height of the top toolbar in screen coordinates. This is
     // independent of whether it is hidden or not at the moment.
     virtual float GetToolbarHeightInScreenCoords() = 0;
+
+    // Notifies the client that there was an attempt to save the document
+    virtual void SaveCalled() {}
   };
 
   // Factory method to create an instance of the PDF Engine.
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index d67cb1a..73372929 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -2703,6 +2703,7 @@
   if (document_->form_status() != PDF_FORM_NOTAVAIL ||
       doc_loader_->IsDocumentComplete()) {
     document_->InitializeForm(&form_filler_);
+    form_filler_.RegisterSaveCalledHandler();
 #if defined(PDF_ENABLE_XFA)
     FPDF_LoadXFA(doc());
 #endif
diff --git a/pdf/pdfium/pdfium_form_filler.cc b/pdf/pdfium/pdfium_form_filler.cc
index c64ccaf..dce0645 100644
--- a/pdf/pdfium/pdfium_form_filler.cc
+++ b/pdf/pdfium/pdfium_form_filler.cc
@@ -82,6 +82,10 @@
 
 PDFiumFormFiller::~PDFiumFormFiller() = default;
 
+void PDFiumFormFiller::RegisterSaveCalledHandler() {
+  FORM_SetSaveCallback(engine_->form(), PDFiumFormFiller::Form_SaveCalled);
+}
+
 // static
 void PDFiumFormFiller::Form_Invalidate(FPDF_FORMFILLINFO* param,
                                        FPDF_PAGE page,
@@ -267,6 +271,11 @@
   engine->ScrollToPage(page_index);
 }
 
+// static
+void PDFiumFormFiller::Form_SaveCalled(FPDF_FORMFILLINFO* param) {
+  GetEngine(param)->client_->SaveCalled();
+}
+
 #if defined(PDF_ENABLE_XFA)
 
 // static
diff --git a/pdf/pdfium/pdfium_form_filler.h b/pdf/pdfium/pdfium_form_filler.h
index df4c7fb..6579995 100644
--- a/pdf/pdfium/pdfium_form_filler.h
+++ b/pdf/pdfium/pdfium_form_filler.h
@@ -22,6 +22,8 @@
   PDFiumFormFiller(PDFiumEngine* engine, bool enable_javascript);
   ~PDFiumFormFiller();
 
+  void RegisterSaveCalledHandler();
+
  private:
   // FPDF_FORMFILLINFO callbacks.
   static void Form_Invalidate(FPDF_FORMFILLINFO* param,
@@ -61,6 +63,7 @@
                                 int zoom_mode,
                                 float* position_array,
                                 int size_of_array);
+  static void Form_SaveCalled(FPDF_FORMFILLINFO* param);
 
 #if defined(PDF_ENABLE_XFA)
   static void Form_EmailTo(FPDF_FORMFILLINFO* param,
diff --git a/ppapi/tests/test_websocket.cc b/ppapi/tests/test_websocket.cc
index 98ef8bb..a5ac27d 100644
--- a/ppapi/tests/test_websocket.cc
+++ b/ppapi/tests/test_websocket.cc
@@ -40,12 +40,10 @@
 const char kCloseWithCodeAndReasonServerURL[] = "close-code-and-reason";
 const char kProtocolTestServerURL[] = "protocol-test?protocol=";
 
-const char* const kInvalidURLs[] = {
-  "http://www.google.com/invalid_scheme",
-  "ws://www.google.com/invalid#fragment",
-  "ws://www.google.com:65535/invalid_port",
-  NULL
-};
+const char* const kInvalidURLs[] = {"http://www.google.com/invalid_scheme",
+                                    "ws://www.google.com/invalid#fragment",
+                                    "ws://www.google.com:7/invalid_port",
+                                    NULL};
 
 // Internal packet sizes.
 const uint64_t kMessageFrameOverhead = 6;
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 7ec0f246..dfc727dd 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -23,6 +23,23 @@
 // TODO(860492): Remove this once supervised user support is removed.
 const char kSupervisedUserPseudoGaiaID[] = "managed_user_gaia_id";
 
+// Maps a vector of gaia::ListedAccount structs to a corresponding vector of
+// AccountInfo structs.
+std::vector<AccountInfo> ListedAccountsToAccountInfos(
+    const std::vector<gaia::ListedAccount>& listed_accounts) {
+  std::vector<AccountInfo> account_infos;
+
+  for (const auto& listed_account : listed_accounts) {
+    AccountInfo account_info;
+    account_info.account_id = listed_account.id;
+    account_info.gaia = listed_account.gaia_id;
+    account_info.email = listed_account.email;
+    account_infos.push_back(account_info);
+  }
+
+  return account_infos;
+}
+
 }  // namespace
 
 IdentityManager::IdentityManager(
@@ -72,6 +89,7 @@
 #endif
   token_service_->AddDiagnosticsObserver(this);
   token_service_->set_diagnostics_client(this);
+  gaia_cookie_manager_service_->AddObserver(this);
 }
 
 IdentityManager::~IdentityManager() {
@@ -82,6 +100,7 @@
 #endif
   token_service_->RemoveDiagnosticsObserver(this);
   token_service_->set_diagnostics_client(nullptr);
+  gaia_cookie_manager_service_->RemoveObserver(this);
 }
 
 AccountInfo IdentityManager::GetPrimaryAccountInfo() const {
@@ -147,6 +166,17 @@
   return accounts;
 }
 
+std::vector<AccountInfo> IdentityManager::GetAccountsInCookieJar(
+    const std::string& source) const {
+  // TODO(859882): Change this implementation to interact asynchronously with
+  // GaiaCookieManagerService as detailed in
+  // https://docs.google.com/document/d/1hcrJ44facCSHtMGBmPusvcoP-fAR300Hi-UFez8ffYQ/edit?pli=1#heading=h.w97eil1cygs2.
+  std::vector<gaia::ListedAccount> listed_accounts;
+  gaia_cookie_manager_service_->ListAccounts(&listed_accounts, nullptr, source);
+
+  return ListedAccountsToAccountInfos(listed_accounts);
+}
+
 bool IdentityManager::HasAccountWithRefreshToken(
     const std::string& account_id) const {
   return base::ContainsKey(accounts_with_refresh_tokens_, account_id);
@@ -337,6 +367,18 @@
   }
 }
 
+void IdentityManager::OnGaiaAccountsInCookieUpdated(
+    const std::vector<gaia::ListedAccount>& accounts,
+    const std::vector<gaia::ListedAccount>& signed_out_accounts,
+    const GoogleServiceAuthError& error) {
+  std::vector<AccountInfo> account_infos =
+      ListedAccountsToAccountInfos(accounts);
+
+  for (auto& observer : observer_list_) {
+    observer.OnAccountsInCookieUpdated(account_infos);
+  }
+}
+
 void IdentityManager::OnAccessTokenRequested(
     const std::string& account_id,
     const std::string& consumer_id,
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 3f944ed..6e6c1fa 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -47,7 +47,8 @@
                         public SigninManager::DiagnosticsClient,
 #endif
                         public ProfileOAuth2TokenService::DiagnosticsClient,
-                        public OAuth2TokenService::DiagnosticsObserver {
+                        public OAuth2TokenService::DiagnosticsObserver,
+                        public GaiaCookieManagerService::Observer {
  public:
   class Observer {
    public:
@@ -87,6 +88,11 @@
     // is problematic for your use case, please contact blundell@chromium.org.
     virtual void OnRefreshTokenRemovedForAccount(
         const AccountInfo& account_info) {}
+
+    // Called whenever the list of Gaia accounts in the cookie jar has changed.
+    // |accounts| is ordered by the order of the accounts in the cookie.
+    virtual void OnAccountsInCookieUpdated(
+        const std::vector<AccountInfo>& accounts) {}
   };
 
   // Observer interface for classes that want to monitor status of various
@@ -128,6 +134,22 @@
   // refresh tokens were added.
   std::vector<AccountInfo> GetAccountsWithRefreshTokens() const;
 
+  // Provides access to the latest cached information of all accounts that are
+  // present in the Gaia cookie in the cookie jar, ordered by their order in
+  // the cookie. If the cached state is known to be stale by the underlying
+  // implementation, a call to this method will trigger an internal update and
+  // subsequent invocation of
+  // IdentityManager::Observer::OnAccountsInCookieJarChanged().
+  // |source| is supplied as the source of any network requests that are made as
+  // part of an internal update.
+  // NOTE: The information of whether the cached state is known to be stale by
+  // the underlying implementation is not currently exposed. The design for
+  // exposing it if necessary is tracked by https://crbug.com/859882. If the
+  // lack of this exposure is a blocker for you in using this API, contact
+  // blundell@chromium.org.
+  std::vector<AccountInfo> GetAccountsInCookieJar(
+      const std::string& source) const;
+
   // Returns true if a refresh token exists for |account_id|.
   bool HasAccountWithRefreshToken(const std::string& account_id) const;
 
@@ -208,6 +230,12 @@
   void WillFireGoogleSignedOut(const AccountInfo& account_info) override;
 #endif
 
+  // GaiaCookieManagerService::Observer:
+  void OnGaiaAccountsInCookieUpdated(
+      const std::vector<gaia::ListedAccount>& accounts,
+      const std::vector<gaia::ListedAccount>& signed_out_accounts,
+      const GoogleServiceAuthError& error) override;
+
   // OAuth2TokenService::DiagnosticsObserver:
   void OnAccessTokenRequested(
       const std::string& account_id,
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index da3ffb8..e7b863f 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -245,6 +245,14 @@
     return account_from_refresh_token_removed_callback_;
   }
 
+  void set_on_accounts_in_cookie_updated_callback(base::OnceClosure callback) {
+    on_accounts_in_cookie_updated_callback_ = std::move(callback);
+  }
+
+  const std::vector<AccountInfo>& accounts_from_cookie_change_callback() {
+    return accounts_from_cookie_change_callback_;
+  }
+
  private:
   // IdentityManager::Observer:
   void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override {
@@ -271,17 +279,25 @@
     if (on_refresh_token_removed_callback_)
       std::move(on_refresh_token_removed_callback_).Run();
   }
+  void OnAccountsInCookieUpdated(
+      const std::vector<AccountInfo>& accounts) override {
+    accounts_from_cookie_change_callback_ = accounts;
+    if (on_accounts_in_cookie_updated_callback_)
+      std::move(on_accounts_in_cookie_updated_callback_).Run();
+  }
 
   IdentityManager* identity_manager_;
   base::OnceClosure on_primary_account_set_callback_;
   base::OnceClosure on_primary_account_cleared_callback_;
   base::OnceClosure on_refresh_token_updated_callback_;
   base::OnceClosure on_refresh_token_removed_callback_;
+  base::OnceClosure on_accounts_in_cookie_updated_callback_;
   AccountInfo primary_account_from_set_callback_;
   AccountInfo primary_account_from_cleared_callback_;
   AccountInfo account_from_refresh_token_updated_callback_;
   bool validity_from_refresh_token_updated_callback_;
   AccountInfo account_from_refresh_token_removed_callback_;
+  std::vector<AccountInfo> accounts_from_cookie_change_callback_;
 };
 
 class TestIdentityManagerDiagnosticsObserver
@@ -372,6 +388,9 @@
   CustomFakeProfileOAuth2TokenService* token_service() {
     return &token_service_;
   }
+  FakeGaiaCookieManagerService* gaia_cookie_manager_service() {
+    return &gaia_cookie_manager_service_;
+  }
 
   // Used by some tests that need to re-instantiate IdentityManager after
   // performing some other setup.
@@ -1256,4 +1275,175 @@
   run_loop2.Run();
 }
 
+TEST_F(IdentityManagerTest,
+       CallbackSentOnUpdateToAccountsInCookieWithNoAccounts) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  gaia_cookie_manager_service()->SetListAccountsResponseNoAccounts();
+  gaia_cookie_manager_service()->TriggerListAccounts(
+      "identity_manager_unittest");
+
+  run_loop.Run();
+
+  EXPECT_TRUE(identity_manager_observer()
+                  ->accounts_from_cookie_change_callback()
+                  .empty());
+}
+
+TEST_F(IdentityManagerTest,
+       CallbackSentOnUpdateToAccountsInCookieWithOneAccount) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  gaia_cookie_manager_service()->SetListAccountsResponseOneAccount(kTestEmail,
+                                                                   kTestGaiaId);
+  gaia_cookie_manager_service()->TriggerListAccounts(
+      "identity_manager_unittest");
+  run_loop.Run();
+
+  EXPECT_EQ(1u, identity_manager_observer()
+                    ->accounts_from_cookie_change_callback()
+                    .size());
+
+  AccountInfo account_info =
+      identity_manager_observer()->accounts_from_cookie_change_callback()[0];
+  EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
+            account_info.account_id);
+  EXPECT_EQ(kTestGaiaId, account_info.gaia);
+  EXPECT_EQ(kTestEmail, account_info.email);
+}
+
+TEST_F(IdentityManagerTest,
+       CallbackSentOnUpdateToAccountsInCookieWithTwoAccounts) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  gaia_cookie_manager_service()->SetListAccountsResponseTwoAccounts(
+      kTestEmail, kTestGaiaId, kTestEmail2, kTestGaiaId2);
+  gaia_cookie_manager_service()->TriggerListAccounts(
+      "identity_manager_unittest");
+
+  run_loop.Run();
+
+  EXPECT_EQ(2u, identity_manager_observer()
+                    ->accounts_from_cookie_change_callback()
+                    .size());
+
+  // Verify not only that both accounts are present but that they are listed in
+  // the expected order as well.
+  AccountInfo account_info1 =
+      identity_manager_observer()->accounts_from_cookie_change_callback()[0];
+  EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
+            account_info1.account_id);
+  EXPECT_EQ(kTestGaiaId, account_info1.gaia);
+  EXPECT_EQ(kTestEmail, account_info1.email);
+
+  AccountInfo account_info2 =
+      identity_manager_observer()->accounts_from_cookie_change_callback()[1];
+  EXPECT_EQ(
+      account_tracker()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2),
+      account_info2.account_id);
+  EXPECT_EQ(kTestGaiaId2, account_info2.gaia);
+  EXPECT_EQ(kTestEmail2, account_info2.email);
+}
+
+TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithNoAccounts) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  gaia_cookie_manager_service()->SetListAccountsResponseNoAccounts();
+
+  // Do an initial call to GetAccountsInCookieJar(). This call should return no
+  // accounts but should also trigger an internal update and eventual
+  // notification that the accounts in the cookie jar have been updated.
+  std::vector<AccountInfo> accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar("identity_manager_unittest");
+  EXPECT_TRUE(accounts_in_cookie_jar.empty());
+
+  run_loop.Run();
+
+  // The state of the accounts in IdentityManager should now reflect the
+  // internal update.
+  accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar("identity_manager_unittest");
+
+  EXPECT_TRUE(accounts_in_cookie_jar.empty());
+}
+
+TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithOneAccount) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  gaia_cookie_manager_service()->SetListAccountsResponseOneAccount(kTestEmail,
+                                                                   kTestGaiaId);
+
+  // Do an initial call to GetAccountsInCookieJar(). This call should return no
+  // accounts but should also trigger an internal update and eventual
+  // notification that the accounts in the cookie jar have been updated.
+  std::vector<AccountInfo> accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar("identity_manager_unittest");
+  EXPECT_TRUE(accounts_in_cookie_jar.empty());
+
+  run_loop.Run();
+
+  // The state of the accounts in IdentityManager should now reflect the
+  // internal update.
+  accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar("identity_manager_unittest");
+
+  EXPECT_EQ(1u, accounts_in_cookie_jar.size());
+
+  AccountInfo account_info = accounts_in_cookie_jar[0];
+  EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
+            account_info.account_id);
+  EXPECT_EQ(kTestGaiaId, account_info.gaia);
+  EXPECT_EQ(kTestEmail, account_info.email);
+}
+
+TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithTwoAccounts) {
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+      run_loop.QuitClosure());
+
+  gaia_cookie_manager_service()->SetListAccountsResponseTwoAccounts(
+      kTestEmail, kTestGaiaId, kTestEmail2, kTestGaiaId2);
+
+  // Do an initial call to GetAccountsInCookieJar(). This call should return no
+  // accounts but should also trigger an internal update and eventual
+  // notification that the accounts in the cookie jar have been updated.
+  std::vector<AccountInfo> accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar("identity_manager_unittest");
+  EXPECT_TRUE(accounts_in_cookie_jar.empty());
+
+  run_loop.Run();
+
+  // The state of the accounts in IdentityManager should now reflect the
+  // internal update.
+  accounts_in_cookie_jar =
+      identity_manager()->GetAccountsInCookieJar("identity_manager_unittest");
+
+  EXPECT_EQ(2u, accounts_in_cookie_jar.size());
+
+  // Verify not only that both accounts are present but that they are listed in
+  // the expected order as well.
+  AccountInfo account_info1 = accounts_in_cookie_jar[0];
+  EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
+            account_info1.account_id);
+  EXPECT_EQ(kTestGaiaId, account_info1.gaia);
+  EXPECT_EQ(kTestEmail, account_info1.email);
+
+  AccountInfo account_info2 = accounts_in_cookie_jar[1];
+  EXPECT_EQ(
+      account_tracker()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2),
+      account_info2.account_id);
+  EXPECT_EQ(kTestGaiaId2, account_info2.gaia);
+  EXPECT_EQ(kTestEmail2, account_info2.email);
+}
+
 }  // namespace identity
diff --git a/services/ui/service.cc b/services/ui/service.cc
index bf53a4f8..5011695 100644
--- a/services/ui/service.cc
+++ b/services/ui/service.cc
@@ -44,6 +44,7 @@
 #include "ui/base/mojo/clipboard_host.h"
 #include "ui/base/platform_window_defaults.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/events/event_switches.h"
 #include "ui/events/platform/platform_event_source.h"
@@ -59,7 +60,6 @@
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/ozone_switches.h"
 #endif
 
 #if defined(OS_CHROMEOS)
@@ -226,8 +226,7 @@
     params.single_process = true;
     params.using_mojo = true;
   } else {
-    params.using_mojo = base::CommandLine::ForCurrentProcess()->HasSwitch(
-        ::switches::kEnableDrmMojo);
+    params.using_mojo = features::IsOzoneDrmMojo();
   }
   ui::OzonePlatform::InitializeForUI(params);
 
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index 5c73aa0b..bf0bee4 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -233,8 +233,7 @@
   auto* quad = pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
   quad->SetAll(sqs, bounds_at_origin /* rect */,
                bounds_at_origin /* visible_rect */, true /* needs_blending*/,
-               window_manager_surface_info_.id(),
-               window_manager_surface_info_.id(),
+               viz::SurfaceRange(window_manager_surface_info_.id()),
                SK_ColorWHITE /* default_background_color */,
                false /* stretch_content_to_fill_bounds */);
 }
diff --git a/services/ui/ws2/window_service.cc b/services/ui/ws2/window_service.cc
index 3e072e0..1872604 100644
--- a/services/ui/ws2/window_service.cc
+++ b/services/ui/ws2/window_service.cc
@@ -121,10 +121,13 @@
   window_trees_.erase(tree);
 }
 
-void WindowService::RequestClose(aura::Window* window) {
+bool WindowService::RequestClose(aura::Window* window) {
   ServerWindow* server_window = ServerWindow::GetMayBeNull(window);
-  DCHECK(window && server_window->IsTopLevel());
+  if (!server_window || !server_window->IsTopLevel())
+    return false;
+
   server_window->owning_window_tree()->RequestClose(server_window);
+  return true;
 }
 
 void WindowService::OnDisplayMetricsChanged(const display::Display& display,
diff --git a/services/ui/ws2/window_service.h b/services/ui/ws2/window_service.h
index 9051b99..2788338 100644
--- a/services/ui/ws2/window_service.h
+++ b/services/ui/ws2/window_service.h
@@ -105,9 +105,9 @@
   // Called when a WindowServiceClient is about to be destroyed.
   void OnWillDestroyWindowTree(WindowTree* tree);
 
-  // Asks the client that created |window| to close |window|. |window| must be
-  // a top-level window.
-  void RequestClose(aura::Window* window);
+  // Asks the client that created |window| to close |window|. Returns true if
+  // |window| is a top-level created by a remote client, false otherwise.
+  bool RequestClose(aura::Window* window);
 
   // Called when the metrics of a display changes. It is expected the local
   // environment call this *before* the change is applied to any
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.cc b/services/viz/public/cpp/compositing/quads_struct_traits.cc
index 5f7acfe..47121a2 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.cc
@@ -112,8 +112,7 @@
   viz::SurfaceDrawQuad* quad = static_cast<viz::SurfaceDrawQuad*>(out);
   quad->default_background_color = data.default_background_color();
   quad->stretch_content_to_fill_bounds = data.stretch_content_to_fill_bounds();
-  return data.ReadPrimarySurfaceId(&quad->primary_surface_id) &&
-         data.ReadFallbackSurfaceId(&quad->fallback_surface_id);
+  return data.ReadSurfaceRange(&quad->surface_range);
 }
 
 // static
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.h b/services/viz/public/cpp/compositing/quads_struct_traits.h
index 93f16a02..ac28fea3 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.h
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.h
@@ -19,7 +19,7 @@
 #include "services/viz/public/cpp/compositing/filter_operation_struct_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operations_struct_traits.h"
 #include "services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h"
-#include "services/viz/public/cpp/compositing/surface_id_struct_traits.h"
+#include "services/viz/public/cpp/compositing/surface_range_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/quads.mojom-shared.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
@@ -238,17 +238,10 @@
 
 template <>
 struct StructTraits<viz::mojom::SurfaceQuadStateDataView, viz::DrawQuad> {
-  static const viz::SurfaceId& primary_surface_id(const viz::DrawQuad& input) {
+  static const viz::SurfaceRange& surface_range(const viz::DrawQuad& input) {
     const viz::SurfaceDrawQuad* quad =
         viz::SurfaceDrawQuad::MaterialCast(&input);
-    return quad->primary_surface_id;
-  }
-
-  static const base::Optional<viz::SurfaceId>& fallback_surface_id(
-      const viz::DrawQuad& input) {
-    const viz::SurfaceDrawQuad* quad =
-        viz::SurfaceDrawQuad::MaterialCast(&input);
-    return quad->fallback_surface_id;
+    return quad->surface_range;
   }
 
   static uint32_t default_background_color(const viz::DrawQuad& input) {
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 3ee54c2..2d0f620 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -776,9 +776,11 @@
   const gfx::Rect surface_quad_rect(1337, 2448, 1234, 5678);
   surface_quad->SetNew(
       shared_state_2, surface_quad_rect, surface_quad_rect,
-      SurfaceId(FrameSinkId(1337, 1234),
-                LocalSurfaceId(1234, base::UnguessableToken::Create())),
-      base::nullopt, SK_ColorYELLOW, false);
+      SurfaceRange(
+          base::nullopt,
+          SurfaceId(FrameSinkId(1337, 1234),
+                    LocalSurfaceId(1234, base::UnguessableToken::Create()))),
+      SK_ColorYELLOW, false);
 
   std::unique_ptr<RenderPass> output;
   SerializeAndDeserialize<mojom::RenderPass>(input, &output);
@@ -847,10 +849,7 @@
   EXPECT_EQ(out_surface_quad->shared_quad_state, out_sqs2);
   EXPECT_EQ(surface_quad->rect, out_surface_quad->rect);
   EXPECT_EQ(surface_quad->visible_rect, out_surface_quad->visible_rect);
-  EXPECT_EQ(surface_quad->primary_surface_id,
-            out_surface_quad->primary_surface_id);
-  EXPECT_EQ(surface_quad->fallback_surface_id,
-            out_surface_quad->fallback_surface_id);
+  EXPECT_EQ(surface_quad->surface_range, out_surface_quad->surface_range);
   EXPECT_EQ(surface_quad->default_background_color,
             out_surface_quad->default_background_color);
   EXPECT_EQ(surface_quad->stretch_content_to_fill_bounds,
@@ -921,9 +920,9 @@
       LocalSurfaceId(1234, base::UnguessableToken::Create()));
   SurfaceDrawQuad* primary_surface_quad =
       render_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-  primary_surface_quad->SetNew(sqs, rect3, rect3, primary_surface_id,
-                               base::Optional<SurfaceId>(fallback_surface_id),
-                               SK_ColorBLUE, false);
+  primary_surface_quad->SetNew(
+      sqs, rect3, rect3, SurfaceRange(fallback_surface_id, primary_surface_id),
+      SK_ColorBLUE, false);
 
   const gfx::Rect rect4(1234, 5678, 9101112, 13141516);
   const ResourceId resource_id4(1337);
@@ -1000,11 +999,11 @@
   EXPECT_EQ(rect3, out_primary_surface_draw_quad->visible_rect);
   EXPECT_TRUE(out_primary_surface_draw_quad->needs_blending);
   EXPECT_EQ(primary_surface_id,
-            out_primary_surface_draw_quad->primary_surface_id);
+            out_primary_surface_draw_quad->surface_range.end());
   EXPECT_EQ(SK_ColorBLUE,
             out_primary_surface_draw_quad->default_background_color);
   EXPECT_EQ(fallback_surface_id,
-            out_primary_surface_draw_quad->fallback_surface_id);
+            out_primary_surface_draw_quad->surface_range.start());
 
   const RenderPassDrawQuad* out_render_pass_draw_quad =
       RenderPassDrawQuad::MaterialCast(output->quad_list.ElementAt(3));
diff --git a/services/viz/public/interfaces/compositing/quads.mojom b/services/viz/public/interfaces/compositing/quads.mojom
index c3184f8d..b1eaad0 100644
--- a/services/viz/public/interfaces/compositing/quads.mojom
+++ b/services/viz/public/interfaces/compositing/quads.mojom
@@ -4,7 +4,7 @@
 
 module viz.mojom;
 
-import "services/viz/public/interfaces/compositing/surface_id.mojom";
+import "services/viz/public/interfaces/compositing/surface_range.mojom";
 import "services/viz/public/interfaces/compositing/shared_quad_state.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/color_space.mojom";
@@ -55,8 +55,7 @@
 };
 
 struct SurfaceQuadState {
-  SurfaceId primary_surface_id;
-  SurfaceId? fallback_surface_id;
+  SurfaceRange surface_range;
   uint32 default_background_color;
   bool stretch_content_to_fill_bounds;
 };
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index bb6ce43..35d5ef2 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -214,6 +214,9 @@
 #define SK_ATTR_DEPRECATED          SK_NOTHING_ARG1
 #define GR_GL_CUSTOM_SETUP_HEADER   "GrGLConfig_chrome.h"
 
+// enable interfaces unique to Chrome
+#define SK_BUILD_FOR_CHROME
+
 // ===== End Chrome-specific definitions =====
 
 #endif
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 49c382c..843086b 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -2719,6 +2719,25 @@
         "test": "base_unittests"
       },
       {
+        "args": [
+          "--dbus-stub",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.chromeos_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ],
+          "hard_timeout": 3600,
+          "io_timeout": 3600
+        },
+        "test": "chromeos_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 508963e..eb3848a 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -28,6 +28,7 @@
 
 source_set("chromeos_filters") {
   data = [
+    "//testing/buildbot/filters/chromeos.chromeos_unittests.filter",
     "//testing/buildbot/filters/chromeos.media_unittests.filter",
   ]
 }
diff --git a/testing/buildbot/filters/chromeos.chromeos_unittests.filter b/testing/buildbot/filters/chromeos.chromeos_unittests.filter
new file mode 100644
index 0000000..b7f46dd9
--- /dev/null
+++ b/testing/buildbot/filters/chromeos.chromeos_unittests.filter
@@ -0,0 +1,2 @@
+TODO(crbug.com/865693): Fix this.
+-NetworkConnectionHandlerImplTest.ConnectWithCertificateSuccess
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7577e4a..41a695a 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -353,6 +353,13 @@
 
   'chromeos_gtests_experimental': {
     'base_unittests': {},
+    'chromeos_unittests': {
+      'args': [
+        # TODO(crbug.com/865693): Don't stub out dbus clients.
+        '--dbus-stub',
+        '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.chromeos_unittests.filter',
+      ],
+    },
     'cros_vm_sanity_test': {},
     # net_unittests has a test-time dependency on vpython. So add a CIPD'ed
     # vpython of the right arch to the task, and tell the test runner to copy
diff --git a/testing/scripts/run_telemetry_benchmark_as_googletest.py b/testing/scripts/run_telemetry_benchmark_as_googletest.py
index 3ffeaa53..1aa1c22 100755
--- a/testing/scripts/run_telemetry_benchmark_as_googletest.py
+++ b/testing/scripts/run_telemetry_benchmark_as_googletest.py
@@ -167,7 +167,10 @@
           results, indent=2)
     valid = False
   finally:
-    shutil.rmtree(tempfile_dir)
+    # Add ignore_errors=True because otherwise rmtree may fail due to leaky
+    # processes of tests are still holding opened handles to files under
+    # |tempfile_dir|. For example, see crbug.com/865896
+    shutil.rmtree(tempfile_dir, ignore_errors=True)
 
   if not valid and num_failures == 0:
     if rc == 0:
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 6c36238..5b63006 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -542,8 +542,6 @@
 crbug.com/591099 fast/css3-text/css3-text-indent/negative-text-indent-leading-out-of-flow.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-leading-out-of-flow.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLAreaElement/area-download.html [ Failure ]
-crbug.com/755750 fast/dom/Range/get-bounding-client-rect-empty-and-non-empty.html [ Failure Pass ]
-crbug.com/755750 fast/dom/Range/getBoundingClientRect-linebreak-character.html [ Failure ]
 crbug.com/591099 fast/dom/nodesFromRect/nodesFromRect-basic.html [ Failure ]
 crbug.com/591099 fast/dynamic/first-letter-after-list-marker.html [ Failure ]
 crbug.com/591099 fast/dynamic/text-combine.html [ Failure ]
@@ -665,7 +663,6 @@
 crbug.com/714962 images/color-profile-background-clip-text.html [ Failure ]
 crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/714962 inspector-protocol/css/css-get-platform-fonts.js [ Failure ]
-crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js [ Failure ]
 crbug.com/714962 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-viewport.js [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Failure ]
 crbug.com/591099 inspector-protocol/layers/get-layers.js [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 59b31117..0c44bd4 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1691,6 +1691,7 @@
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Timeout ]
 
 # Failing tests in dictionary order.
+crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-timing.https.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/fetch/chromium/error-messages.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-no-credential-prompt.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-unsupported-url.html [ Failure ]
@@ -1700,6 +1701,7 @@
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-timing.https.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/fetch/chromium/error-messages.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-no-credential-prompt.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-unsupported-url.html [ Failure ]
@@ -4644,23 +4646,6 @@
 # Sheriff 2018-7-13
 crbug.com/863599 [ Linux Debug ] external/wpt/requestidlecallback/callback-iframe.html [ Pass Timeout ]
 
-#crbug.com/860706
-crbug.com/860706 fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html [ Pass Timeout Failure ]
-crbug.com/860706 virtual/gpu/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html [ Pass Timeout Failure ]
-crbug.com/860706 [ Linux Mac ] css3/filters/effect-blur-hw.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] css3/filters/filter-repaint-composited-fallback-crash.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-gradient-over-image.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu/fast/canvas/color-space/canvas-createImageBitmap-p3.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blend-image.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-gradient-over-pattern.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-image.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-color-over-pattern.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-pattern.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-shadow-source-in.html [ Timeout Pass ]
-
 crbug.com/864887 [ Linux ] fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Failure Pass ]
 crbug.com/864888 [ Mac ] editing/selection/offset-from-point-complex-scripts.html [ Failure Pass ]
 crbug.com/864891 [ Mac ] virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html [ Timeout Pass ]
@@ -4669,7 +4654,6 @@
 crbug.com/863067 [ Win10 ] fast/dom/Window/window-focus-self.html [ Failure Pass ]
 crbug.com/864994 [ Mac ] external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-decode-ksc_5601.html [ Timeout Failure Pass ]
 
-crbug.com/865371 [ Mac ]  external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html [ Failure Pass ]
 crbug.com/865432 [ Linux ] external/wpt/workers/modules/dedicated-worker-import-blob-url.any.worker.html [ Timeout Pass ]
 
 crbug.com/865755 [ Debug ] virtual/threaded/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index df0d3e9..28efc88 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -158464,7 +158464,7 @@
      {}
     ]
    ],
-   "interfaces/battery.idl": [
+   "interfaces/battery-status.idl": [
     [
      {}
     ]
@@ -167209,6 +167209,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/malformed-http-response.asis": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/malformed-worker.py": [
     [
      {}
@@ -167744,6 +167749,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/update_shell.py": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/vtt-frame.html": [
     [
      {}
@@ -238379,6 +238389,14 @@
      }
     ]
    ],
+   "picture-in-picture/request-picture-in-picture-twice.html": [
+    [
+     "/picture-in-picture/request-picture-in-picture-twice.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "picture-in-picture/request-picture-in-picture.html": [
     [
      "/picture-in-picture/request-picture-in-picture.html",
@@ -249618,6 +249636,14 @@
    "service-workers/service-worker/update-after-navigation-fetch-event.https.html": [
     [
      "/service-workers/service-worker/update-after-navigation-fetch-event.https.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "service-workers/service-worker/update-after-navigation-redirect.https.html": [
+    [
+     "/service-workers/service-worker/update-after-navigation-redirect.https.html",
      {}
     ]
    ],
@@ -275421,7 +275447,7 @@
    "testharness"
   ],
   "battery-status/battery-interface-idlharness.https.html": [
-   "0390a5ad8de487a38e9b981ae61786c33c980222",
+   "ded64d71b16ef29ee44ef2337642d551f8b557fe",
    "testharness"
   ],
   "battery-status/battery-plugging-in-manual.https.html": [
@@ -354889,11 +354915,11 @@
    "support"
   ],
   "feature-policy/picture-in-picture-default-feature-policy.https.sub.html": [
-   "49c95204e8d3478f6c4509740fa0ed605146ca36",
+   "97beb6665671a5ccead61b3e512840d478bf3a7a",
    "testharness"
   ],
   "feature-policy/picture-in-picture-disabled-by-feature-policy.https.sub.html": [
-   "fb7ea1dbfb4bd71aa007bb456ce5528c3f71fb0c",
+   "6cf3bfd76a411e9981b34b30e538a190c76da206",
    "testharness"
   ],
   "feature-policy/picture-in-picture-disabled-by-feature-policy.https.sub.html.headers": [
@@ -354953,7 +354979,7 @@
    "support"
   ],
   "feature-policy/resources/picture-in-picture.js": [
-   "5f8637f67053cd55cfa0aa03d0bcbc7dee3ba876",
+   "ec1d60b406b88b9b710dd92749e61f9b96a5ab24",
    "support"
   ],
   "feature-policy/resources/redirect-on-load.html": [
@@ -378060,8 +378086,8 @@
    "272d5ef66a2df3a6c3fefaf9688802ed93a9ad5f",
    "support"
   ],
-  "interfaces/battery.idl": [
-   "37550560186be55b56d226be2fdecc1e36574a6d",
+  "interfaces/battery-status.idl": [
+   "0afe8bca88113d4a8116663a308079c439b5530d",
    "support"
   ],
   "interfaces/beacon.idl": [
@@ -389096,12 +389122,16 @@
    "628cc1c6d8d2c83a6f3e466bc66a26ea76b85ff2",
    "testharness"
   ],
+  "picture-in-picture/request-picture-in-picture-twice.html": [
+   "289c2decddd418722b3d5345b31706b4fad59ed3",
+   "testharness"
+  ],
   "picture-in-picture/request-picture-in-picture.html": [
-   "3ffc08be84a5c7b67d35b21c614ccc8fa2a8c642",
+   "fb6711b83e61613cef5928b6829b048d2cb7d73b",
    "testharness"
   ],
   "picture-in-picture/resources/picture-in-picture-helpers.js": [
-   "f31184184ba9a74456ab449c480a6777e860a81a",
+   "1d4f14127753148c7dfc4a79d2beec34410e416b",
    "support"
   ],
   "picture-in-picture/shadow-dom.html": [
@@ -401588,6 +401618,10 @@
    "7a74ae709c072750cf0639f78bf9a0ac4f16f50b",
    "support"
   ],
+  "service-workers/service-worker/resources/malformed-http-response.asis": [
+   "06de4e389698b70ab9b354c9b3df5678f342c7ab",
+   "support"
+  ],
   "service-workers/service-worker/resources/malformed-worker.py": [
    "a9f19c8f8f6908c4a4732bbd0f6b2f3d19401909",
    "support"
@@ -402016,6 +402050,10 @@
    "f2c2345c448cee3c12b8f6dcc6e6da3c32b2d43a",
    "support"
   ],
+  "service-workers/service-worker/resources/update_shell.py": [
+   "429b6a398c226bb18100f95380d08aa5c777b5bd",
+   "support"
+  ],
   "service-workers/service-worker/resources/vtt-frame.html": [
    "6ecbf39466212039c7f3ed307e19c89ef2e12735",
    "support"
@@ -402173,7 +402211,11 @@
    "testharness"
   ],
   "service-workers/service-worker/update-after-navigation-fetch-event.https.html": [
-   "14d79d1008193c96f0eadaf3e47ef321a429b905",
+   "48622ab7b06a9da3946d4ade596bf3f8f6d2fda7",
+   "testharness"
+  ],
+  "service-workers/service-worker/update-after-navigation-redirect.https.html": [
+   "f81390e04cd4d04e0b44ba3884aabcaae64d9772",
    "testharness"
   ],
   "service-workers/service-worker/update-after-oneday.https-expected.txt": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/battery-status/battery-interface-idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/battery-status/battery-interface-idlharness.https.html
index 1a6ad54..888ad95 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/battery-status/battery-interface-idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/battery-status/battery-interface-idlharness.https.html
@@ -8,25 +8,29 @@
 <script src="/resources/WebIDLParser.js"></script>
 <script src="/resources/idlharness.js"></script>
 <script>
-"use strict";
+'use strict';
 
 promise_test(async () => {
+  const battery = await fetch('/interfaces/battery-status.idl').then(r => r.text());
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+  const html = await fetch('/interfaces/html.idl').then(r => r.text());
+
   const idl_array = new IdlArray();
-  const dom_idl = await fetch("/interfaces/dom.idl").then(r => r.text());
-  const battery_idl = await fetch("/interfaces/battery.idl").then(r => r.text());
-  const manager = await navigator.getBattery();
+  idl_array.add_idls(battery);
+  idl_array.add_dependency_idls(dom);
+  idl_array.add_dependency_idls(html);
 
-  idl_array.add_untested_idls(dom_idl, {only: ['EventTarget']});
-  idl_array.add_untested_idls('interface EventHandler {};');
-  idl_array.add_untested_idls('interface Navigator {};');
-  idl_array.add_idls(battery_idl);
-
-  window.manager = manager;
+  let manager;
+  try {
+    manager = await navigator.getBattery();
+  } catch (e) {
+    // Will surface in idlharness.js's test_objects.
+  }
 
   idl_array.add_objects({
     Navigator: ['navigator'],
-    BatteryManager: ['manager'],
+    BatteryManager: [manager],
   });
   idl_array.test();
-}, "Test IDL implementation of Battery Status API");
+}, 'Test IDL implementation of Battery Status API');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl
new file mode 100644
index 0000000..1491d64
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl
@@ -0,0 +1,19 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the
+// "Battery Status API" spec.
+// See: https://w3c.github.io/battery/
+
+partial interface Navigator {
+  Promise<BatteryManager> getBattery();
+};
+[Exposed=Window]
+interface BatteryManager : EventTarget {
+    readonly        attribute boolean charging;
+    readonly        attribute unrestricted double chargingTime;
+    readonly        attribute unrestricted double dischargingTime;
+    readonly        attribute double level;
+                    attribute EventHandler onchargingchange;
+                    attribute EventHandler onchargingtimechange;
+                    attribute EventHandler ondischargingtimechange;
+                    attribute EventHandler onlevelchange;
+};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery.idl
deleted file mode 100644
index 2596a6e..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery.idl
+++ /dev/null
@@ -1,19 +0,0 @@
-// GENERATED CONTENT - DO NOT EDIT
-// Content of this file was automatically extracted from the Battery Status API spec.
-// See https://w3c.github.io/battery/
-
-partial interface Navigator {
-  Promise<BatteryManager> getBattery();
-};
-
-[Exposed=Window]
-interface BatteryManager : EventTarget {
-    readonly        attribute boolean             charging;
-    readonly        attribute unrestricted double chargingTime;
-    readonly        attribute unrestricted double dischargingTime;
-    readonly        attribute double              level;
-                    attribute EventHandler        onchargingchange;
-                    attribute EventHandler        onchargingtimechange;
-                    attribute EventHandler        ondischargingtimechange;
-                    attribute EventHandler        onlevelchange;
-};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/quirks/unitless-length/excluded-properties.html b/third_party/WebKit/LayoutTests/external/wpt/quirks/unitless-length/excluded-properties.html
new file mode 100644
index 0000000..a1de182
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/quirks/unitless-length/excluded-properties.html
@@ -0,0 +1,60 @@
+<html>
+<head>
+<meta charset="utf-8">
+<title>Many properties do not support quirky-length</title>
+<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+<link rel="help" href="https://quirks.spec.whatwg.org/#the-unitless-length-quirk">
+<meta name="assert" content="quirky-length is not supported by properties not listed.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+
+var properties = [
+    'block-size',
+    'inline-size',
+    'margin-block-end',
+    'margin-block-start',
+    'margin-inline-end',
+    'margin-inline-start',
+    'min-block-size',
+    'min-inline-size',
+    'offset-distance',
+    'padding-block-end',
+    'padding-block-start',
+    'padding-inline-end',
+    'padding-inline-start',
+    'scroll-margin-block-end',
+    'scroll-margin-block-start',
+    'scroll-margin-bottom',
+    'scroll-margin-inline-end',
+    'scroll-margin-inline-start',
+    'scroll-margin-left',
+    'scroll-margin-right',
+    'scroll-margin-top',
+    'scroll-padding-block-end',
+    'scroll-padding-block-start',
+    'scroll-padding-bottom',
+    'scroll-padding-inline-end',
+    'scroll-padding-inline-start',
+    'scroll-padding-left',
+    'scroll-padding-right',
+    'scroll-padding-top',
+    'shape-margin'
+];
+
+for (let property of properties) {
+  test(() => {
+    if (!getComputedStyle(target)[property])
+      return;
+    target.style[property] = '567px';
+    target.style[property] = '1234';
+    assert_equals(target.style[property], '567px');
+  }, 'Property ' + property + ' does not support quirky length');
+}
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/webxr-test.js b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/webxr-test.js
new file mode 100644
index 0000000..74be1f0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/webxr-test.js
@@ -0,0 +1,383 @@
+'use strict';
+
+// This polyfill library implements the WebXR Test API as specified here:
+// https://github.com/immersive-web/webxr-test-api
+
+class ChromeXRTest {
+  constructor() {
+    this.mockVRService_ = new MockVRService(mojo.frameInterfaces);
+  }
+
+  simulateDeviceConnection(init_params) {
+    return Promise.resolve(this.mockVRService_.addDevice(init_params));
+  }
+
+  simulateUserActivation(callback) {
+    return new Promise(resolve => {
+      let button = document.createElement('button');
+      button.textContent = 'click to continue test';
+      button.style.display = 'block';
+      button.style.fontSize = '20px';
+      button.style.padding = '10px';
+      button.onclick = () => {
+        resolve(callback());
+        document.body.removeChild(button);
+      };
+      document.body.appendChild(button);
+      test_driver.click(button);
+    });
+  }
+}
+
+// Mocking class definitions
+class MockVRService {
+  constructor() {
+    this.bindingSet_ = new mojo.BindingSet(device.mojom.VRService);
+    this.devices_ = [];
+
+    this.interceptor_ =
+        new MojoInterfaceInterceptor(device.mojom.VRService.name);
+    this.interceptor_.oninterfacerequest = e =>
+        this.bindingSet_.addBinding(this, e.handle);
+    this.interceptor_.start();
+  }
+
+  // Test methods
+  addDevice(fakeDeviceInit) {
+    let device = new MockDevice(fakeDeviceInit, this);
+    this.devices_.push(device);
+
+    return device;
+  }
+
+  // VRService implementation.
+  setClient(client) {
+    this.client_ = client;
+    for (let i = 0; i < this.devices_.length; i++) {
+      this.devices_[i].notifyClientOfDisplay();
+    }
+
+    return Promise.resolve();
+  }
+}
+
+// Implements both VRDisplayHost and VRMagicWindowProvider. Maintains a mock for
+// VRPresentationProvider.
+class MockDevice {
+  constructor(fakeDeviceInit, service) {
+    this.displayClient_ = new device.mojom.VRDisplayClientPtr();
+    this.presentation_provider_ = new MockVRPresentationProvider();
+
+    this.service_ = service;
+
+    this.framesOfReference = {};
+
+    if (fakeDeviceInit.supportsImmersive) {
+      this.displayInfo_ = this.getImmersiveDisplayInfo();
+    } else {
+      this.displayInfo_ = this.getNonImmersiveDisplayInfo();
+    }
+
+    if (service.client_) {
+      this.notifyClientOfDisplay();
+    }
+  }
+
+  // Functions for setup.
+  // This function calls to the backend to add this device to the list.
+  notifyClientOfDisplay() {
+    let displayPtr = new device.mojom.VRDisplayHostPtr();
+    let displayRequest = mojo.makeRequest(displayPtr);
+    let displayBinding =
+        new mojo.Binding(device.mojom.VRDisplayHost, this, displayRequest);
+
+    let clientRequest = mojo.makeRequest(this.displayClient_);
+    this.service_.client_.onDisplayConnected(
+        displayPtr, clientRequest, this.displayInfo_);
+  }
+
+  // Test methods.
+  setXRPresentationFrameData(poseMatrix, views) {
+    if (poseMatrix == null) {
+      this.presentation_provider_.pose_ = null;
+    } else {
+      this.presentation_provider_.setPoseFromMatrix(poseMatrix);
+    }
+
+    if (views) {
+      let changed = false;
+      for (let i = 0; i < views.length; i++) {
+        if (views[i].eye == 'left') {
+          this.displayInfo_.leftEye = this.getEye(views[i]);
+          changed = true;
+        } else if (views[i].eye == 'right') {
+          this.displayInfo_.rightEye = this.getEye(views[i]);
+          changed = true;
+        }
+      }
+
+      if (changed) {
+        this.displayClient_.onChanged(this.displayInfo_);
+      }
+    }
+  }
+
+  getNonImmersiveDisplayInfo() {
+    let displayInfo = this.getImmersiveDisplayInfo();
+
+    displayInfo.capabilities.canPresent = false;
+    displayInfo.leftEye = null;
+    displayInfo.rightEye = null;
+
+    return displayInfo;
+  }
+
+  // Function to generate some valid display information for the device.
+  getImmersiveDisplayInfo() {
+    return {
+      displayName: 'FakeDevice',
+      capabilities: {
+        hasPosition: false,
+        hasExternalDisplay: false,
+        canPresent: true,
+        maxLayers: 1
+      },
+      stageParameters: null,
+      leftEye: {
+        fieldOfView: {
+          upDegrees: 48.316,
+          downDegrees: 50.099,
+          leftDegrees: 50.899,
+          rightDegrees: 35.197
+        },
+        offset: [-0.032, 0, 0],
+        renderWidth: 20,
+        renderHeight: 20
+      },
+      rightEye: {
+        fieldOfView: {
+          upDegrees: 48.316,
+          downDegrees: 50.099,
+          leftDegrees: 50.899,
+          rightDegrees: 35.197
+        },
+        offset: [0.032, 0, 0],
+        renderWidth: 20,
+        renderHeight: 20
+      },
+      webxrDefaultFramebufferScale: 0.7,
+    };
+  }
+
+  // This function converts between the matrix provided by the WebXR test API
+  // and the internal data representation.
+  getEye(fakeXRViewInit) {
+    let m = fakeXRViewInit.projectionMatrix;
+
+    function toDegrees(tan) {
+      return Math.atan(tan) * 180 / Math.PI;
+    }
+
+    let xScale = m[0];
+    let yScale = m[5];
+    let near = m[14] / (m[10] - 1);
+    let far = m[14] / (m[10] - 1);
+    let leftTan = (1 - m[8]) / m[0];
+    let rightTan = (1 + m[8]) / m[0];
+    let upTan = (1 + m[9]) / m[5];
+    let downTan = (1 - m[9]) / m[5];
+
+    return {
+      fieldOfView: {
+        upDegrees: toDegrees(upTan),
+        downDegrees: toDegrees(downTan),
+        leftDegrees: toDegrees(leftTan),
+        rightDegrees: toDegrees(rightTan)
+      },
+      offset: [0, 0, 0],
+      renderWidth: 20,
+      renderHeight: 20
+    };
+  }
+
+  // Mojo function implementations.
+
+  // VRMagicWindowProvider implementation.
+
+  getFrameData() {
+    // Convert current document time to monotonic time.
+    let now = window.performance.now() / 1000.0;
+    let diff = now - internals.monotonicTimeToZeroBasedDocumentTime(now);
+    now += diff;
+    now *= 1000000;
+
+    return Promise.resolve({
+      frameData: {
+        pose: this.presentation_provider_.pose_,
+        bufferHolder: null,
+        bufferSize: {},
+        timeDelta: [],
+        projectionMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
+      }
+    });
+  }
+
+  updateSessionGeometry(frame_size, display_rotation) {
+    // This function must exist to ensure that calls to it do not crash, but we
+    // do not have any use for this data at present.
+  }
+
+  // VRDisplayHost implementation.
+
+  requestSession(sessionOptions, was_activation) {
+    return this.supportsSession(sessionOptions).then((result) => {
+      // The JavaScript bindings convert c_style_names to camelCase names.
+      let options = new device.mojom.VRDisplayFrameTransportOptions();
+      options.transportMethod =
+          device.mojom.VRDisplayFrameTransportMethod.SUBMIT_AS_MAILBOX_HOLDER;
+      options.waitForTransferNotification = true;
+      options.waitForRenderNotification = true;
+
+      let connection;
+      if (result.supportsSession) {
+        connection = {
+          clientRequest: this.presentation_provider_.getClientRequest(),
+          provider: this.presentation_provider_.bindProvider(sessionOptions),
+          transportOptions: options
+        };
+
+        let magicWindowPtr = new device.mojom.VRMagicWindowProviderPtr();
+        let magicWindowRequest = mojo.makeRequest(magicWindowPtr);
+        let magicWindowBinding = new mojo.Binding(
+            device.mojom.VRMagicWindowProvider, this, magicWindowRequest);
+
+        return Promise.resolve({
+          session:
+              {connection: connection, magicWindowProvider: magicWindowPtr}
+        });
+      } else {
+        return Promise.resolve({session: null});
+      }
+    });
+  }
+
+  supportsSession(options) {
+    return Promise.resolve({
+      supportsSession:
+          !options.exclusive || this.displayInfo_.capabilities.canPresent
+    });
+  };
+}
+
+class MockVRPresentationProvider {
+  constructor() {
+    this.binding_ = new mojo.Binding(device.mojom.VRPresentationProvider, this);
+    this.pose_ = null;
+    this.next_frame_id_ = 0;
+    this.submit_frame_count_ = 0;
+    this.missing_frame_count_ = 0;
+  }
+
+  bindProvider(request) {
+    let providerPtr = new device.mojom.VRPresentationProviderPtr();
+    let providerRequest = mojo.makeRequest(providerPtr);
+
+    this.binding_.close();
+
+    this.binding_ = new mojo.Binding(
+        device.mojom.VRPresentationProvider, this, providerRequest);
+
+    return providerPtr;
+  }
+
+  getClientRequest() {
+    this.submitFrameClient_ = new device.mojom.VRSubmitFrameClientPtr();
+    return mojo.makeRequest(this.submitFrameClient_);
+  }
+
+  setPoseFromMatrix(poseMatrix) {
+    this.pose_ = {
+      orientation: null,
+      position: null,
+      angularVelocity: null,
+      linearVelocity: null,
+      angularAcceleration: null,
+      linearAcceleration: null,
+      inputState: null,
+      poseIndex: 0
+    };
+
+    let pose = this.poseFromMatrix(poseMatrix);
+    for (let field in pose) {
+      if (this.pose_.hasOwnProperty(field)) {
+        this.pose_[field] = pose[field];
+      }
+    }
+  }
+
+  poseFromMatrix(m) {
+    let orientation = [];
+
+    let m00 = m[0];
+    let m11 = m[5];
+    let m22 = m[10];
+    // The max( 0, ... ) is just a safeguard against rounding error.
+    orientation[3] = Math.sqrt(Math.max(0, 1 + m00 + m11 + m22)) / 2;
+    orientation[0] = Math.sqrt(Math.max(0, 1 + m00 - m11 - m22)) / 2;
+    orientation[1] = Math.sqrt(Math.max(0, 1 - m00 + m11 - m22)) / 2;
+    orientation[2] = Math.sqrt(Math.max(0, 1 - m00 - m11 + m22)) / 2;
+
+    let position = [];
+    position[0] = m[12];
+    position[1] = m[13];
+    position[2] = m[14];
+
+    return {
+      orientation, position
+    }
+  }
+
+  // VRPresentationProvider mojo implementation
+  submitFrameMissing(frameId, mailboxHolder, timeWaited) {
+    this.missing_frame_count_++;
+  }
+
+  submitFrame(frameId, mailboxHolder, timeWaited) {
+    this.submit_frame_count_++;
+
+    // Trigger the submit completion callbacks here. WARNING: The
+    // Javascript-based mojo mocks are *not* re-entrant. It's OK to
+    // wait for these notifications on the next frame, but waiting
+    // within the current frame would never finish since the incoming
+    // calls would be queued until the current execution context finishes.
+    this.submitFrameClient_.onSubmitFrameTransferred(true);
+    this.submitFrameClient_.onSubmitFrameRendered();
+  }
+
+  getFrameData() {
+    if (this.pose_) {
+      this.pose_.poseIndex++;
+    }
+
+    // Convert current document time to monotonic time.
+    let now = window.performance.now() / 1000.0;
+    let diff = now - internals.monotonicTimeToZeroBasedDocumentTime(now);
+    now += diff;
+    now *= 1000000;
+
+    return Promise.resolve({
+      frameData: {
+        pose: this.pose_,
+        timeDelta: {
+          microseconds: now,
+        },
+        frameId: this.next_frame_id_++,
+        projectionMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+        bufferHolder: null,
+        bufferSize: {}
+      }
+    });
+  }
+}
+
+let XRTest = new ChromeXRTest();
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/webxr-test.js.headers b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/webxr-test.js.headers
new file mode 100644
index 0000000..6805c323
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/webxr-test.js.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=utf-8
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing-expected.txt
index 23b1c53c..d9c3ecf64 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing-expected.txt
@@ -1,6 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught TypeError: Cannot read property 'name' of undefined
-Found 303 tests; 301 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 324 tests; 322 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS 0.js - count (0 ?== 0)
 PASS 1.js - count (1 ?== 1)
 PASS 1.js - name (metric ?== metric)
@@ -304,5 +303,26 @@
 PASS 68.js - [0].name (metric1 ?== metric1)
 PASS 68.js - [0].duration (0 ?== 0)
 PASS 68.js - [0].description ( ?== )
+PASS 69.js - count (1 ?== 1)
+PASS 69.js - name (metric ?== metric)
+PASS 69.js - duration (0 ?== 0)
+PASS 69.js - description ( ?== )
+PASS 70.js - count (1 ?== 1)
+PASS 70.js - name (metric ?== metric)
+PASS 70.js - duration (0 ?== 0)
+PASS 70.js - description ( ?== )
+PASS 71.js - count (0 ?== 0)
+PASS 72.js - count (0 ?== 0)
+PASS 73.js - count (0 ?== 0)
+PASS 74.js - count (0 ?== 0)
+PASS 75.js - count (0 ?== 0)
+PASS 76.js - count (0 ?== 0)
+PASS 77.js - count (0 ?== 0)
+PASS 78.js - count (0 ?== 0)
+PASS 79.js - count (0 ?== 0)
+PASS 80.js - count (0 ?== 0)
+PASS 81.js - count (0 ?== 0)
+PASS 82.js - count (0 ?== 0)
+PASS 83.js - count (0 ?== 0)
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.html
index 50396ed..f74ffeb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.html
@@ -28,12 +28,17 @@
             const dur = expectedResult.dur || 0
             const desc = expectedResult.desc || ''
             const index = expectedResults.length === 1 ? '' : `[${i}].`
-            test_equals(expectedResult.name, serverTiming[i].name,
-                `${fileName} - ${index}name (${expectedResult.name} ?== ${serverTiming[i].name})`)
-            test_equals(dur, serverTiming[i].duration,
-                `${fileName} - ${index}duration (${dur} ?== ${serverTiming[i].duration})`)
-            test_equals(desc, serverTiming[i].description,
-                `${fileName} - ${index}description (${desc} ?== ${serverTiming[i].description})`)
+            const actual = serverTiming[i]
+            if (actual === undefined) {
+              // Protect against more expected results than actual results.
+              return
+            }
+            test_equals(expectedResult.name, actual.name,
+                `${fileName} - ${index}name (${expectedResult.name} ?== ${actual.name})`)
+            test_equals(dur, actual.duration,
+                `${fileName} - ${index}duration (${dur} ?== ${actual.duration})`)
+            test_equals(desc, actual.description,
+                `${fileName} - ${index}description (${desc} ?== ${actual.description})`)
           })
         })
         done()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https-expected.txt
index 6aad30e3..eadb4d2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https-expected.txt
@@ -1,5 +1,4 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught TypeError: Cannot read property 'name' of undefined
 PASS 0.js - count (0 ?== 0)
 PASS 1.js - count (1 ?== 1)
 PASS 1.js - name (metric ?== metric)
@@ -303,5 +302,26 @@
 PASS 68.js - [0].name (metric1 ?== metric1)
 PASS 68.js - [0].duration (0 ?== 0)
 PASS 68.js - [0].description ( ?== )
+PASS 69.js - count (1 ?== 1)
+PASS 69.js - name (metric ?== metric)
+PASS 69.js - duration (0 ?== 0)
+PASS 69.js - description ( ?== )
+PASS 70.js - count (1 ?== 1)
+PASS 70.js - name (metric ?== metric)
+PASS 70.js - duration (0 ?== 0)
+PASS 70.js - description ( ?== )
+PASS 71.js - count (0 ?== 0)
+PASS 72.js - count (0 ?== 0)
+PASS 73.js - count (0 ?== 0)
+PASS 74.js - count (0 ?== 0)
+PASS 75.js - count (0 ?== 0)
+PASS 76.js - count (0 ?== 0)
+PASS 77.js - count (0 ?== 0)
+PASS 78.js - count (0 ?== 0)
+PASS 79.js - count (0 ?== 0)
+PASS 80.js - count (0 ?== 0)
+PASS 81.js - count (0 ?== 0)
+PASS 82.js - count (0 ?== 0)
+PASS 83.js - count (0 ?== 0)
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html
index 50396ed..f74ffeb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html
@@ -28,12 +28,17 @@
             const dur = expectedResult.dur || 0
             const desc = expectedResult.desc || ''
             const index = expectedResults.length === 1 ? '' : `[${i}].`
-            test_equals(expectedResult.name, serverTiming[i].name,
-                `${fileName} - ${index}name (${expectedResult.name} ?== ${serverTiming[i].name})`)
-            test_equals(dur, serverTiming[i].duration,
-                `${fileName} - ${index}duration (${dur} ?== ${serverTiming[i].duration})`)
-            test_equals(desc, serverTiming[i].description,
-                `${fileName} - ${index}description (${desc} ?== ${serverTiming[i].description})`)
+            const actual = serverTiming[i]
+            if (actual === undefined) {
+              // Protect against more expected results than actual results.
+              return
+            }
+            test_equals(expectedResult.name, actual.name,
+                `${fileName} - ${index}name (${expectedResult.name} ?== ${actual.name})`)
+            test_equals(dur, actual.duration,
+                `${fileName} - ${index}duration (${dur} ?== ${actual.duration})`)
+            test_equals(desc, actual.description,
+                `${fileName} - ${index}description (${desc} ?== ${actual.description})`)
           })
         })
         done()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html
index dae58c9..96b99a2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html
@@ -38,7 +38,7 @@
           let nodeOptions = {};
           nodeOptions[attrName] = -1;
           new PannerNode(context, nodeOptions);
-        }, prefix + '-1})').throw('RangeError');
+        }, prefix + '-1})').throw(RangeError);
 
         if (options.isZeroAllowed) {
           should(function() {
@@ -51,7 +51,7 @@
             let nodeOptions = {};
             nodeOptions[attrName] = 0;
             new PannerNode(context, nodeOptions);
-          }, prefix + '0})').throw('RangeError');
+          }, prefix + '0})').throw(RangeError);
         }
 
         // The smallest representable positive single float.
@@ -67,7 +67,7 @@
         panner = new PannerNode(context);
         should(function() {
           panner[attrName] = -1;
-        }, prefix + '-1').throw('RangeError');
+        }, prefix + '-1').throw(RangeError);
 
         if (options.isZeroAllowed) {
           should(function() {
@@ -76,7 +76,7 @@
         } else {
           should(function() {
             panner[attrName] = 0;
-          }, prefix + '0').throw('RangeError');
+          }, prefix + '0').throw(RangeError);
         }
 
         should(function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt
index e9de901..f03a6e2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS insertDTMF() should succeed if tones contains valid DTMF characters
 PASS insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters
-FAIL insertDTMF() should throw InvalidStateError if transceiver is stopped pc.addTransceiver is not a function
-FAIL insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
-FAIL insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL insertDTMF() should throw InvalidStateError if transceiver is stopped Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 PASS insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden
 PASS insertDTMF() after remove and close should reject
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
index 6543f47..b8c379f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
@@ -9,7 +9,7 @@
 PASS Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones
 PASS Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones
 PASS Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing
-FAIL Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing pc.addTransceiver is not a function
+FAIL Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 PASS Tone change event constructor works
 PASS Tone change event with unexpected name should not crash
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt
index e6a5158..680283d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt
@@ -4,9 +4,9 @@
 PASS addTrack with single track argument and single stream should succeed
 FAIL addTrack with single track argument and multiple streams should succeed promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'addTrack' on 'RTCPeerConnection': Adding a track to multiple streams is not supported."
 PASS Adding the same track multiple times should throw InvalidAccessError
-FAIL addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL addTrack with existing sender that has not been used to send should reuse the sender promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL addTrack with existing sender that has been used to send should create new sender promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
-FAIL addTrack with existing sender with null track, different kind, and recvonly direction should create new sender promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTrack with existing sender that has not been used to send should reuse the sender promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTrack with existing sender that has been used to send should create new sender promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTrack with existing sender with null track, different kind, and recvonly direction should create new sender promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt
index 2b80f76a..43351af 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt
@@ -1,21 +1,31 @@
 This is a testharness.js-based test.
-FAIL addTransceiver() with string argument as invalid kind should throw TypeError assert_idl_attribute: property "addTransceiver" not found in prototype chain
-FAIL addTransceiver('audio') should return an audio transceiver assert_idl_attribute: property "addTransceiver" not found in prototype chain
-FAIL addTransceiver('video') should return a video transceiver assert_idl_attribute: property "addTransceiver" not found in prototype chain
-FAIL addTransceiver() with direction sendonly should have result transceiver.direction be the same pc.addTransceiver is not a function
-FAIL addTransceiver() with direction inactive should have result transceiver.direction be the same pc.addTransceiver is not a function
-FAIL addTransceiver() with invalid direction should throw TypeError assert_idl_attribute: property "addTransceiver" not found in prototype chain
-FAIL addTransceiver(track) should have result with sender.track be given track assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL addTransceiver(track) multiple times should create multiple transceivers assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError assert_idl_attribute: property "addTransceiver" not found in prototype chain
-FAIL addTransceiver() with rid longer than 16 characters should throw TypeError assert_idl_attribute: property "addTransceiver" not found in prototype chain
-FAIL addTransceiver() with valid rid value should succeed pc.addTransceiver is not a function
+FAIL addTransceiver() with string argument as invalid kind should throw TypeError assert_throws: function "() => pc.addTransceiver('invalid')" threw object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument." ("InvalidStateError") expected object "TypeError" ("TypeError")
+FAIL addTransceiver('audio') should return an audio transceiver Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL addTransceiver('video') should return a video transceiver Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL addTransceiver() with direction sendonly should have result transceiver.direction be the same Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL addTransceiver() with direction inactive should have result transceiver.direction be the same Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+PASS addTransceiver() with invalid direction should throw TypeError
+FAIL addTransceiver(track) should have result with sender.track be given track Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL addTransceiver(track) multiple times should create multiple transceivers Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          rid: '@Invalid!'
+        }]
+      })" threw object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument." ("InvalidStateError") expected object "TypeError" ("TypeError")
+FAIL addTransceiver() with rid longer than 16 characters should throw TypeError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          rid: 'a'.repeat(17)
+        }]
+      })" threw object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument." ("InvalidStateError") expected object "TypeError" ("TypeError")
+FAIL addTransceiver() with valid rid value should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 FAIL addTransceiver() with readonly ssrc set should throw InvalidAccessError assert_throws: function "() =>
       pc.addTransceiver('audio', {
         sendEncodings: [{
           ssrc: 2
         }]
-      })" threw object "TypeError: pc.addTransceiver is not a function" that is not a DOMException InvalidAccessError: property "code" is equal to undefined, expected 15
+      })" threw object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument." that is not a DOMException InvalidAccessError: property "code" is equal to 11, expected 15
 FAIL addTransceiver() with readonly rtx set should throw InvalidAccessError assert_throws: function "() =>
       pc.addTransceiver('audio', {
         sendEncodings: [{
@@ -23,7 +33,7 @@
             ssrc: 2
           }
         }]
-      })" threw object "TypeError: pc.addTransceiver is not a function" that is not a DOMException InvalidAccessError: property "code" is equal to undefined, expected 15
+      })" threw object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument." that is not a DOMException InvalidAccessError: property "code" is equal to 11, expected 15
 FAIL addTransceiver() with readonly fec set should throw InvalidAccessError assert_throws: function "() =>
       pc.addTransceiver('audio', {
         sendEncodings: [{
@@ -31,7 +41,7 @@
             ssrc: 2
           }
         }]
-      })" threw object "TypeError: pc.addTransceiver is not a function" that is not a DOMException InvalidAccessError: property "code" is equal to undefined, expected 15
-FAIL addTransceiver() with valid sendEncodings should succeed pc.addTransceiver is not a function
+      })" threw object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument." that is not a DOMException InvalidAccessError: property "code" is equal to 11, expected 15
+FAIL addTransceiver() with valid sendEncodings should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver.html
index 9720571..347603ce 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addTransceiver.html
@@ -162,7 +162,6 @@
       'Expect receiver.track to be instance of MediaStreamTrack');
 
     assert_equals(track.kind, 'audio');
-    assert_equals(track.label, 'remote audio');
     assert_equals(track.readyState, 'live');
     assert_equals(track.muted, true);
 
@@ -207,7 +206,6 @@
       'Expect receiver.track to be instance of MediaStreamTrack');
 
     assert_equals(track.kind, 'video');
-    assert_equals(track.label, 'remote video');
     assert_equals(track.readyState, 'live');
     assert_equals(track.muted, true);
 
@@ -270,7 +268,6 @@
     assert_equals(receiverTrack.kind, 'audio',
       `receiver.track should have the same kind as added track's kind`);
 
-    assert_equals(receiverTrack.label, 'remote audio');
     assert_equals(receiverTrack.readyState, 'live');
     assert_equals(receiverTrack.muted, true);
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt
index a686429..7f55db4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt
@@ -2,7 +2,7 @@
 FAIL createOffer() with no argument from newly created RTCPeerConnection should succeed assert_false: Expect offer to not be instance of RTCSessionDescription expected false got true
 FAIL createOffer() and then setLocalDescription() should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
 PASS createOffer() after connection is closed should reject with InvalidStateError
-FAIL When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream pc.addTransceiver is not a function
+FAIL When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 FAIL createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers assert_equals: Expect audio line to remain in created offer expected 1 but got 0
 FAIL createOffer() with offerToReceiveVideo should add video line to all subsequent created offers assert_equals: Expect video line to remain in created offer expected 1 but got 0
 FAIL createOffer() with offerToReceiveAudio:true then offerToReceiveVideo:true should have result offer with both audio and video line assert_equals: Expect audio line to remain in created offer expected 1 but got 0
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt
index 1904ff4..569d63c0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt
@@ -4,14 +4,14 @@
 FAIL offerToReceiveAudio option should be ignored if a non-stopped "recvonly" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveAudio option should be ignored if a non-stopped "sendrecv" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveAudio set to false with a track should create a "sendonly" transceiver assert_equals: Expect pc to have one transceiver expected 1 but got 0
-FAIL offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive" pc.addTransceiver is not a function
+FAIL offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive" Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 FAIL subsequent offerToReceiveAudio set to false with a track should change the direction to "sendonly" assert_equals: Expect pc to have one transceiver expected 1 but got 0
 PASS createOffer() with offerToReceiveVideo set to false should not create a transceiver
 FAIL createOffer() with offerToReceiveVideo should create a "recvonly" transceiver assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveVideo option should be ignored if a non-stopped "recvonly" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveVideo option should be ignored if a non-stopped "sendrecv" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveVideo set to false with a track should create a "sendonly" transceiver assert_equals: Expect pc to have one transceiver expected 1 but got 0
-FAIL offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive" pc.addTransceiver is not a function
+FAIL offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive" Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 FAIL subsequent offerToReceiveVideo set to false with a track should change the direction to "sendonly" assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveAudio and Video should create two "recvonly" transceivers assert_equals: Expect pc to have two transceivers expected 2 but got 0
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
index 93e5e87..43827774 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
@@ -3,14 +3,14 @@
 PASS getStats(null) should succeed
 PASS getStats() with track not added to connection should reject with InvalidAccessError
 PASS getStats() with track added via addTrack should succeed
-FAIL getStats() with track added via addTransceiver should succeed promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL getStats() with track associated with more than one sender should reject with InvalidAccessError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL getStats() with track associated with both sender and receiver should reject with InvalidAccessError pc.addTransceiver is not a function
+FAIL getStats() with track added via addTransceiver should succeed promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL getStats() with track associated with more than one sender should reject with InvalidAccessError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL getStats() with track associated with both sender and receiver should reject with InvalidAccessError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 PASS getStats() with no argument should return stats report containing peer-connection stats on an empty PC
 FAIL getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
 FAIL getStats() with no argument should return stats for no-stream tracks assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
 FAIL getStats() on track associated with RtpSender should return stats report containing outbound-rtp stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
-FAIL getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats pc.addTransceiver is not a function
+FAIL getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 FAIL getStats() with connected peer connections having tracks and data channel should return all mandatory to implement stats assert_unreached: test failed with error: Error: assert_true: Expect dictionary.dataChannelIdentifier to be integer expected true got false Reached unreachable code
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
index 878936f..64d94456 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS Creating first data channel should fire negotiationneeded event
 PASS calling createDataChannel twice should fire negotiationneeded event once
-FAIL addTransceiver() should fire negotiationneeded event pc.addTransceiver is not a function
-FAIL Calling addTransceiver() twice should fire negotiationneeded event once pc.addTransceiver is not a function
-FAIL Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is rejected with: TypeError: pc.addTransceiver is not a function Reached unreachable code
+FAIL addTransceiver() should fire negotiationneeded event Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling addTransceiver() twice should fire negotiationneeded event once Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is rejected with: InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument. Reached unreachable code
 PASS negotiationneeded event should not fire if signaling state is not stable
 FAIL negotiationneeded event should fire only after signaling state go back to stable assert_unreached: Expect negotiationneeded promise to resolve after pc has set remote answer and go back to stable state Reached unreachable code
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
index 7c8c39c..9c4a507 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
@@ -2,7 +2,7 @@
 FAIL setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed. assert_true: Expect trackEvent.transceiver to be defined and is instance of RTCRtpTransceiver expected true got false
 PASS setRemoteDescription() with m= line of recvonly direction should not trigger track event
 FAIL addTrack() should cause remote connection to fire ontrack when setRemoteDescription() assert_true: Expect trackEvent.transceiver to be defined and is instance of RTCRtpTransceiver expected true got false
-FAIL addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription() pc1.addTransceiver is not a function
-FAIL addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription() pc1.addTransceiver is not a function
+FAIL addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription() Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription() Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
index 8157d50..d90c5cc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
@@ -1,15 +1,15 @@
 This is a testharness.js-based test.
-FAIL addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 PASS addTrack - Calling removeTrack when connection is closed should throw InvalidStateError
-FAIL addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 PASS addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError
-FAIL addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 PASS addTrack - Calling removeTrack on different connection should throw InvalidAccessError
-FAIL addTransceiver - Calling removeTrack with valid sender should set sender.track to null promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL addTransceiver - Calling removeTrack with valid sender should set sender.track to null promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 PASS addTrack - Calling removeTrack with valid sender should set sender.track to null
-FAIL Calling removeTrack with currentDirection sendrecv should set direction to recvonly promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
-FAIL Calling removeTrack with currentDirection sendonly should set direction to inactive promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL Calling removeTrack with currentDirection recvonly should not change direction promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
-FAIL Calling removeTrack with currentDirection inactive should not change direction promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL Calling removeTrack with currentDirection sendrecv should set direction to recvonly promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Calling removeTrack with currentDirection sendonly should set direction to inactive promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Calling removeTrack with currentDirection recvonly should not change direction promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Calling removeTrack with currentDirection inactive should not change direction promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt
index 5531a050..0ab8333 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
-FAIL setLocalDescription(offer) with m= section should assign mid to corresponding transceiver pc.addTransceiver is not a function
-FAIL setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver pc1.addTransceiver is not a function
-FAIL setLocalDescription(rollback) should unset transceiver.mid pc.addTransceiver is not a function
-FAIL setLocalDescription(rollback) should only unset transceiver mids associated with current round pc.addTransceiver is not a function
-FAIL setRemoteDescription(rollback) should remove newly created transceiver from transceiver list pc1.addTransceiver is not a function
+FAIL setLocalDescription(offer) with m= section should assign mid to corresponding transceiver Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setLocalDescription(rollback) should unset transceiver.mid Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setLocalDescription(rollback) should only unset transceiver mids associated with current round Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setRemoteDescription(rollback) should remove newly created transceiver from transceiver list Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
index 2656a7e..44e2c10 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
@@ -2,7 +2,7 @@
 FAIL setLocalDescription() with valid answer should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
 FAIL setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer assert_not_equals: Expect session description to be defined got disallowed value undefined
 PASS setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError
-PASS Calling setLocalDescription(answer) from stable state should reject with InvalidStateError
-PASS Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError
+FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
+FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt
index da301025..74022758 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt
@@ -1,9 +1,8 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught Error: assert_equals: expected "stable" but got "closed"
 PASS setRemoteDescription with invalid type and invalid SDP should reject with TypeError
-FAIL setRemoteDescription() with invalid SDP and stable state should reject with InvalidStateError assert_throws: function "() => { throw e }" threw object "OperationError: Failed to parse SessionDescription. invalid Expect line: v=" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
-FAIL Negotiation should fire signalingsstate events assert_equals: expected "stable" but got "have-local-offer"
-FAIL Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed promise_test: Unhandled rejection with value: object "InvalidAccessError: Failed to set remote offer sdp: The order of m-lines in subsequent offer doesn't match order from previous offer/answer."
+FAIL setRemoteDescription() with invalid SDP and stable state should reject with InvalidStateError assert_throws: function "() => { throw e }" threw object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. invalid Expect line: v=" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
+PASS Negotiation should fire signalingsstate events
+FAIL Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed promise_test: Unhandled rejection with value: object "InvalidAccessError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: The order of m-lines in subsequent offer doesn't match order from previous offer/answer."
 FAIL Switching role from offerer to answerer after going back to stable state should succeed promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sdp' of undefined"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
new file mode 100644
index 0000000..2a12474
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
@@ -0,0 +1,44 @@
+This is a testharness.js-based test.
+FAIL addTrack: creates a transceiver for the sender assert_true: expected true got false
+FAIL addTrack: "transceiver == {sender,receiver}" assert_array_equals: pc.getTransceivers() equals [transceiver] lengths differ, expected 1 got 0
+FAIL addTrack: transceiver.sender is associated with the track promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sender' of null"
+FAIL addTrack: transceiver.receiver has its own track promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'receiver' of null"
+FAIL addTrack: transceiver.receiver's track is muted promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'receiver' of null"
+FAIL addTrack: transceiver is not associated with an m-section promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
+FAIL addTrack: transceiver is not stopped promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'stopped' of null"
+FAIL addTrack: transceiver's direction is sendrecv promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'direction' of null"
+FAIL addTrack: transceiver's currentDirection is null promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'currentDirection' of null"
+FAIL setLocalDescription(offer): transceiver gets associated with an m-section promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
+FAIL setLocalDescription(offer): transceiver.mid matches the offer SDP promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
+PASS setRemoteDescription(offer): ontrack fires with a track
+PASS setRemoteDescription(offer): ontrack's track.id is the same as track.id
+FAIL setRemoteDescription(offer): ontrack fires with a transceiver. assert_true: trackEvent.transceiver instanceof RTCRtpTransceiver expected true got false
+FAIL setRemoteDescription(offer): transceiver.mid is the same on both ends promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
+FAIL setRemoteDescription(offer): "transceiver == {sender,receiver}" assert_array_equals: pc2.getTransceivers() equals [transceiver] lengths differ, expected 1 got 0
+FAIL setRemoteDescription(offer): transceiver.direction is recvonly promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'direction' of null"
+FAIL setRemoteDescription(offer): transceiver.currentDirection is null promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'currentDirection' of null"
+FAIL setRemoteDescription(offer): transceiver.stopped is false promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'stopped' of null"
+FAIL setLocalDescription(answer): transceiver.currentDirection is recvonly promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'currentDirection' of null"
+FAIL setLocalDescription(answer): transceiver.currentDirection is sendonly promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'currentDirection' of null"
+FAIL addTransceiver(track): creates a transceiver for the track promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver(track): "transceiver == {sender,receiver}" promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver(track, init): initialize direction to inactive promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver(track, init): initialize sendEncodings[0].active to false promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver(0 streams): ontrack fires with no stream promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver(1 stream): ontrack fires with corresponding stream promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver(2 streams): ontrack fires with corresponding two streams promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTrack(0 streams): ontrack fires with no stream assert_equals: trackEvent.streams.length == 0 expected 0 but got 1
+PASS addTrack(1 stream): ontrack fires with corresponding stream
+FAIL addTrack(2 streams): ontrack fires with corresponding two streams promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'addTrack' on 'RTCPeerConnection': Adding a track to multiple streams is not supported."
+FAIL addTransceiver('audio'): creates a transceiver with direction sendrecv promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver('audio'): transceiver.receiver.track.kind == 'audio' promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver('video'): transceiver.receiver.track.kind == 'video' promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver('audio'): transceiver.sender.track == null promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver('audio'): transceiver.currentDirection is null promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver('audio'): transceiver.stopped is false promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTrack reuses reusable transceivers promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver does not reuse reusable transceivers promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Can setup two-way call using a single transceiver promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'direction' of null"
+FAIL Closing the PC stops the transceivers promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
new file mode 100644
index 0000000..3f4e508
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
@@ -0,0 +1,496 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection-transceivers.https.html</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+//   addEventListenerPromise
+
+function createPeerConnectionWithCleanup(t) {
+  const pc = new RTCPeerConnection();
+  t.add_cleanup(() => pc.close());
+  return pc;
+}
+
+async function createTrackWithCleanup(t, kind = 'audio') {
+  let constraints = {};
+  constraints[kind] = true;
+  const stream = await navigator.mediaDevices.getUserMedia(constraints);
+  const [track] = stream.getTracks();
+  t.add_cleanup(() => track.stop());
+  return track;
+}
+
+function findTransceiverForSender(pc, sender) {
+  const transceivers = pc.getTransceivers();
+  for (let i = 0; i < transceivers.length; ++i) {
+    if (transceivers[i].sender == sender)
+      return transceivers[i];
+  }
+  return null;
+}
+
+// Performs an offer exchange pc1 -> pc2.
+async function exchangeOffer(pc1, pc2) {
+  const offer = await pc1.createOffer();
+  await pc1.setLocalDescription(offer);
+  await pc2.setRemoteDescription(offer);
+}
+
+// The returned promise is resolved with pc2's ontrack event.
+async function exchangeOfferAndListenToOntrack(t, pc1, pc2) {
+  const ontrackPromise = addEventListenerPromise(t, pc2, 'track');
+  await exchangeOffer(pc1, pc2);
+  return ontrackPromise;
+}
+
+// Performs an answer exchange pc2 -> pc1.
+async function exchangeAnswer(pc1, pc2) {
+  const answer = await pc2.createAnswer();
+  await pc2.setLocalDescription(answer);
+  await pc1.setRemoteDescription(answer);
+}
+
+// The returned promise is resolved with pc1's ontrack event.
+async function exchangeAnswerAndListenToOntrack(t, pc1, pc2) {
+  const ontrackPromise = addEventListenerPromise(t, pc1, 'track');
+  await exchangeAnswer(pc1, pc2);
+  return ontrackPromise;
+}
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const sender = pc.addTrack(track);
+  const transceiver = findTransceiverForSender(pc, sender);
+  assert_true(transceiver instanceof RTCRtpTransceiver);
+  assert_true(transceiver.sender instanceof RTCRtpSender);
+  assert_equals(transceiver.sender, sender);
+}, 'addTrack: creates a transceiver for the sender');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_array_equals(pc.getTransceivers(), [transceiver],
+                      'pc.getTransceivers() equals [transceiver]');
+  assert_array_equals(pc.getSenders(), [transceiver.sender],
+                      'pc.getSenders() equals [transceiver.sender]');
+  assert_array_equals(pc.getReceivers(), [transceiver.receiver],
+                      'pc.getReceivers() equals [transceiver.receiver]');
+}, 'addTrack: "transceiver == {sender,receiver}"');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_true(transceiver.sender.track instanceof MediaStreamTrack,
+              'transceiver.sender.track instanceof MediaStreamTrack');
+  assert_equals(transceiver.sender.track, track,
+                'transceiver.sender.track == track');
+}, 'addTrack: transceiver.sender is associated with the track');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_true(transceiver.receiver instanceof RTCRtpReceiver,
+              'transceiver.receiver instanceof RTCRtpReceiver');
+  assert_true(transceiver.receiver.track instanceof MediaStreamTrack,
+              'transceiver.receiver.track instanceof MediaStreamTrack');
+  assert_not_equals(transceiver.receiver.track, track,
+                    'transceiver.receiver.track != track');
+}, 'addTrack: transceiver.receiver has its own track');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_true(transceiver.receiver.track.muted);
+}, 'addTrack: transceiver.receiver\'s track is muted');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_equals(transceiver.mid, null);
+}, 'addTrack: transceiver is not associated with an m-section');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_false(transceiver.stopped);
+}, 'addTrack: transceiver is not stopped');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_equals(transceiver.direction, 'sendrecv');
+}, 'addTrack: transceiver\'s direction is sendrecv');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  assert_equals(transceiver.currentDirection, null);
+}, 'addTrack: transceiver\'s currentDirection is null');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  await pc.setLocalDescription(await pc.createOffer());
+  assert_not_equals(transceiver.mid, null, 'transceiver.mid != null');
+}, 'setLocalDescription(offer): transceiver gets associated with an m-section');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc, pc.addTrack(track));
+  const offer = await pc.createOffer();
+  await pc.setLocalDescription(offer);
+  let sdp = offer.sdp;
+  let sdpMidLineStart = sdp.indexOf('a=mid:');
+  let sdpMidLineEnd = sdp.indexOf('\r\n', sdpMidLineStart);
+  assert_true(sdpMidLineStart != -1 && sdpMidLineEnd != -1,
+              'Failed to parse offer SDP for a=mid');
+  let parsedMid = sdp.substring(sdpMidLineStart + 6, sdpMidLineEnd);
+  assert_equals(transceiver.mid, parsedMid, 'transceiver.mid == parsedMid');
+}, 'setLocalDescription(offer): transceiver.mid matches the offer SDP');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_true(trackEvent instanceof RTCTrackEvent,
+              'trackEvent instanceof RTCTrackEvent');
+  assert_true(trackEvent.track instanceof MediaStreamTrack,
+              'trackEvent.track instanceof MediaStreamTrack');
+}, 'setRemoteDescription(offer): ontrack fires with a track');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  pc1.addTrack(track);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_true(trackEvent.track instanceof MediaStreamTrack,
+              'trackEvent.track instanceof MediaStreamTrack');
+  assert_equals(trackEvent.track.id, track.id,
+                'trackEvent.track.id == track.id');
+}, 'setRemoteDescription(offer): ontrack\'s track.id is the same as track.id');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_true(trackEvent.transceiver instanceof RTCRtpTransceiver,
+              'trackEvent.transceiver instanceof RTCRtpTransceiver');
+}, 'setRemoteDescription(offer): ontrack fires with a transceiver.');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(transceiver.mid, trackEvent.transceiver.mid);
+}, 'setRemoteDescription(offer): transceiver.mid is the same on both ends');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  const transceiver = trackEvent.transceiver;
+  assert_array_equals(pc2.getTransceivers(), [transceiver],
+                      'pc2.getTransceivers() equals [transceiver]');
+  assert_array_equals(pc2.getSenders(), [transceiver.sender],
+                      'pc2.getSenders() equals [transceiver.sender]');
+  assert_array_equals(pc2.getReceivers(), [transceiver.receiver],
+                      'pc2.getReceivers() equals [transceiver.receiver]');
+}, 'setRemoteDescription(offer): "transceiver == {sender,receiver}"');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.transceiver.direction, 'recvonly');
+}, 'setRemoteDescription(offer): transceiver.direction is recvonly');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.transceiver.currentDirection, null);
+}, 'setRemoteDescription(offer): transceiver.currentDirection is null');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_false(trackEvent.transceiver.stopped);
+}, 'setRemoteDescription(offer): transceiver.stopped is false');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(await createTrackWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  const transceiver = trackEvent.transceiver;
+  assert_equals(transceiver.currentDirection, null,
+                'SRD(offer): transciever.currentDirection is null');
+  await pc2.setLocalDescription(await pc2.createAnswer());
+  assert_equals(transceiver.currentDirection, 'recvonly',
+                'SLD(answer): transciever.currentDirection is recvonly');
+}, 'setLocalDescription(answer): transceiver.currentDirection is recvonly');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  await exchangeOffer(pc1, pc2);
+  assert_equals(transceiver.currentDirection, null,
+                'SLD(offer): transciever.currentDirection is null');
+  await exchangeAnswer(pc1, pc2);
+  assert_equals(transceiver.currentDirection, 'sendonly',
+                'SRD(answer): transciever.currentDirection is sendonly');
+}, 'setLocalDescription(answer): transceiver.currentDirection is sendonly');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver(track);
+  assert_true(transceiver instanceof RTCRtpTransceiver);
+  assert_true(transceiver.sender instanceof RTCRtpSender);
+  assert_true(transceiver.receiver instanceof RTCRtpReceiver);
+  assert_equals(transceiver.sender.track, track);
+}, 'addTransceiver(track): creates a transceiver for the track');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver(track);
+  assert_array_equals(pc.getTransceivers(), [transceiver],
+                      'pc.getTransceivers() equals [transceiver]');
+  assert_array_equals(pc.getSenders(), [transceiver.sender],
+                      'pc.getSenders() equals [transceiver.sender]');
+  assert_array_equals(pc.getReceivers(), [transceiver.receiver],
+                      'pc.getReceivers() equals [transceiver.receiver]');
+}, 'addTransceiver(track): "transceiver == {sender,receiver}"');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver(track, {direction:'inactive'});
+  assert_equals(transceiver.direction, 'inactive');
+}, 'addTransceiver(track, init): initialize direction to inactive');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const otherPc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver(track, {
+    sendEncodings: [{active:false}]
+  });
+
+  // Negotiate parameters.
+  const offer = await pc.createOffer();
+  await pc.setLocalDescription(offer);
+  await otherPc.setRemoteDescription(offer);
+  const answer = await otherPc.createAnswer();
+  await otherPc.setLocalDescription(answer);
+  await pc.setRemoteDescription(answer);
+
+  const params = transceiver.sender.getParameters();
+  assert_false(params.encodings[0].active);
+}, 'addTransceiver(track, init): initialize sendEncodings[0].active to false');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  pc1.addTransceiver(track, {streams:[]});
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
+}, 'addTransceiver(0 streams): ontrack fires with no stream');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const stream = new MediaStream();
+  pc1.addTransceiver(track, {streams:[stream]});
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
+  assert_equals(trackEvent.streams[0].id, stream.id,
+                'trackEvent.streams[0].id == stream.id');
+}, 'addTransceiver(1 stream): ontrack fires with corresponding stream');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const stream0 = new MediaStream();
+  const stream1 = new MediaStream();
+  pc1.addTransceiver(track, {streams:[stream0, stream1]});
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
+  assert_equals(trackEvent.streams[0].id, stream0.id,
+                'trackEvent.streams[0].id == stream0.id');
+  assert_equals(trackEvent.streams[1].id, stream1.id,
+                'trackEvent.streams[1].id == stream1.id');
+}, 'addTransceiver(2 streams): ontrack fires with corresponding two streams');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  pc1.addTrack(track);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
+}, 'addTrack(0 streams): ontrack fires with no stream');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const stream = new MediaStream();
+  pc1.addTrack(track, stream);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
+  assert_equals(trackEvent.streams[0].id, stream.id,
+                'trackEvent.streams[0].id == stream.id');
+}, 'addTrack(1 stream): ontrack fires with corresponding stream');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const stream0 = new MediaStream();
+  const stream1 = new MediaStream();
+  pc1.addTrack(track, stream0, stream1);
+  const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
+  assert_equals(trackEvent.streams[0].id, stream0.id,
+                'trackEvent.streams[0].id == stream0.id');
+  assert_equals(trackEvent.streams[1].id, stream1.id,
+                'trackEvent.streams[1].id == stream1.id');
+}, 'addTrack(2 streams): ontrack fires with corresponding two streams');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver('audio');
+  assert_equals(transceiver.direction, 'sendrecv');
+}, 'addTransceiver(\'audio\'): creates a transceiver with direction sendrecv');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver('audio');
+  assert_equals(transceiver.receiver.track.kind, 'audio');
+}, 'addTransceiver(\'audio\'): transceiver.receiver.track.kind == \'audio\'');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver('video');
+  assert_equals(transceiver.receiver.track.kind, 'video');
+}, 'addTransceiver(\'video\'): transceiver.receiver.track.kind == \'video\'');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver('audio');
+  assert_equals(transceiver.sender.track, null);
+}, 'addTransceiver(\'audio\'): transceiver.sender.track == null');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver('audio');
+  assert_equals(transceiver.currentDirection, null);
+}, 'addTransceiver(\'audio\'): transceiver.currentDirection is null');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const transceiver = pc.addTransceiver('audio');
+  assert_false(transceiver.stopped);
+}, 'addTransceiver(\'audio\'): transceiver.stopped is false');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t, 'audio');
+  const transceiver = pc.addTransceiver('audio');
+  const sender = pc.addTrack(track);
+  assert_equals(sender, transceiver.sender, 'sender == transceiver.sender');
+  assert_equals(sender.track, track, 'sender.track == track');
+}, 'addTrack reuses reusable transceivers');
+
+promise_test(async t => {
+  const pc = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t, 'audio');
+  const t1 = pc.addTransceiver('audio');
+  const t2 = pc.addTransceiver(track);
+  assert_not_equals(t2, t1, 't2 != t1');
+  assert_equals(t2.sender.track, track, 't2.sender.track == track');
+}, 'addTransceiver does not reuse reusable transceivers');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t);
+  const pc1Transceiver = findTransceiverForSender(pc1, pc1.addTrack(track));
+  const pc2TrackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  const pc2Transceiver = pc2TrackEvent.transceiver;
+  assert_equals(pc2Transceiver.direction, 'recvonly',
+                'pc2Transceiver.direction is recvonly after SRD(offer)');
+  const pc2Sender = pc2.addTrack(track);
+  assert_equals(pc2Transceiver.sender, pc2Sender,
+                'pc2Transceiver.sender == sender');
+  assert_equals(pc2Transceiver.direction, 'sendrecv',
+                'pc2Transceiver.direction is sendrecv after addTrack()');
+  assert_equals(pc2Transceiver.currentDirection, null,
+                'pc2Transceiver.currentDirection is null before answer');
+  const pc1TrackEvent = await exchangeAnswerAndListenToOntrack(t, pc1, pc2);
+  assert_equals(pc2Transceiver.currentDirection, 'sendrecv',
+      'pc2Transceiver.currentDirection is sendrecv after SLD(answer)');
+  assert_equals(pc1TrackEvent.transceiver, pc1Transceiver,
+                'Answer: pc1.ontrack fires with the existing transceiver.');
+  assert_equals(pc1Transceiver.currentDirection, 'sendrecv',
+                'pc1Transceiver.currentDirection is sendrecv');
+  assert_equals(pc2.getTransceivers().length, 1,
+                'pc2.getTransceivers().length == 1');
+  assert_equals(pc1.getTransceivers().length, 1,
+                'pc1.getTransceivers().length == 1');
+}, 'Can setup two-way call using a single transceiver');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  const track = await createTrackWithCleanup(t, 'audio');
+  const transceiver = pc1.addTransceiver(track);
+  await exchangeOffer(pc1, pc2);
+  await exchangeAnswer(pc1, pc2);
+  assert_equals(transceiver.currentDirection, 'sendonly');
+  assert_false(transceiver.stopped);
+  pc1.close();
+  assert_equals(transceiver.currentDirection, null);
+  assert_true(transceiver.stopped);
+}, 'Closing the PC stops the transceivers');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt
index 46350ee8..c310a37c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-FAIL setParameters() with codec.payloadType modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with codec.mimeType modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with codec.clockRate modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with codec.channels modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with new codecs inserted should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL setParameters() with codec.payloadType modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with codec.mimeType modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with codec.clockRate modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with codec.channels modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with new codecs inserted should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt
index 102eb498..546ce00 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL setParameters with degradationPreference set should succeed pc.addTransceiver is not a function
-FAIL setParameters with degradationPreference unset should succeed pc.addTransceiver is not a function
+FAIL setParameters with degradationPreference set should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setParameters with degradationPreference unset should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
index b4adbb0a..b41ff937 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
@@ -1,26 +1,26 @@
 This is a testharness.js-based test.
-FAIL addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL sender.getParameters() should return sendEncodings set by addTransceiver() promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL sender.setParameters() with encodings unset should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.rtx field should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.rid field should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.dtx should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.dtx should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with unset encoding.dtx should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with unset encoding.dtx should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.active should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.priority should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.priority should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.ptime should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.ptime should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.maxBitrate should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.maxFramerate should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with modified encoding.maxFramerate should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL sender.getParameters() should return sendEncodings set by addTransceiver() promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL sender.setParameters() with encodings unset should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.rtx field should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.rid field should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.dtx should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.dtx should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with unset encoding.dtx should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with unset encoding.dtx should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.active should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.priority should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.priority should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.ptime should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.ptime should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.maxBitrate should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.maxFramerate should succeed with RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with modified encoding.maxFramerate should succeed without RTCRtpTransceiverInit promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt
index 0cc4970..6d3ae82c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL setParameters() with modified headerExtensions should reject with InvalidModificationError pc.addTransceiver is not a function
+FAIL setParameters() with modified headerExtensions should reject with InvalidModificationError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt
index ea557a33..521060a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL setParameters() with modified rtcp.cname should reject with InvalidModificationError pc.addTransceiver is not a function
-FAIL setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError pc.addTransceiver is not a function
+FAIL setParameters() with modified rtcp.cname should reject with InvalidModificationError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt
index 7a59ff8..312e321a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
-FAIL sender.getParameters() should return different transaction IDs for each call promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL sender.setParameters() with transaction ID unset should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() twice with the same parameters should reject with InvalidStateError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL setParameters() with parameters older than last getParameters() should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+FAIL sender.getParameters() should return different transaction IDs for each call promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL sender.setParameters() with transaction ID unset should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() twice with the same parameters should reject with InvalidStateError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL setParameters() with parameters older than last getParameters() should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt
index 370fc34..3f199b05 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL RTCRtpReceiver.prototype.getParameters pc.addTransceiver is not a function
+FAIL RTCRtpReceiver.prototype.getParameters Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
index 3e65fc5..56851d2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
+FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 FAIL receiver.getStats() via addTrack should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
index 3458002..5351a21 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
+FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 FAIL sender.getStats() via addTrack should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt
index 3da7b26e..d08930f5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL Calling replaceTrack on closed connection should reject with InvalidStateError assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack with track of different kind should reject with TypeError assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack on stopped sender should reject with InvalidStateError assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
-FAIL Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain
+FAIL Calling replaceTrack on closed connection should reject with InvalidStateError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack with track of different kind should reject with TypeError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack on stopped sender should reject with InvalidStateError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
index c0ec6af..d75f3e39 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL setParameters() when transceiver is stopped should reject with InvalidStateError pc.addTransceiver is not a function
+FAIL setParameters() when transceiver is stopped should reject with InvalidStateError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt
index 52621c47..1b5df3af 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed pc.addTransceiver is not a function
-FAIL setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed pc.addTransceiver is not a function
-FAIL setCodecPreferences() with both sender receiver codecs combined should succeed pc.addTransceiver is not a function
-FAIL setCodecPreferences([]) should succeed pc.addTransceiver is not a function
-FAIL setCodecPreferences() with reordered codecs should succeed pc.addTransceiver is not a function
-FAIL setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidAccessError pc.addTransceiver is not a function
-FAIL setCodecPreferences() with user defined codec should throw InvalidAccessError pc.addTransceiver is not a function
-FAIL setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidAccessError pc.addTransceiver is not a function
-FAIL setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidAccessError pc.addTransceiver is not a function
+FAIL setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() with both sender receiver codecs combined should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences([]) should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() with reordered codecs should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidAccessError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() with user defined codec should throw InvalidAccessError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidAccessError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidAccessError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt
index f871d9e1..15f42daf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
-FAIL setDirection should change transceiver.direction pc.addTransceiver is not a function
-FAIL setDirection with same direction should have no effect pc.addTransceiver is not a function
-FAIL setDirection should change transceiver.direction independent of transceiver.currentDirection pc.addTransceiver is not a function
+FAIL setDirection should change transceiver.direction Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setDirection with same direction should have no effect Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL setDirection should change transceiver.direction independent of transceiver.currentDirection Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt
index ee38320..ce8e229 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt
@@ -1,10 +1,10 @@
 This is a testharness.js-based test.
-FAIL new RTCTrackEvent() with valid receiver, track, transceiver should succeed pc.addTransceiver is not a function
-FAIL new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed pc.addTransceiver is not a function
-FAIL new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed pc.addTransceiver is not a function
-FAIL new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed pc.addTransceiver is not a function
-FAIL new RTCTrackEvent() with no transceiver should throw TypeError pc.addTransceiver is not a function
-FAIL new RTCTrackEvent() with no track should throw TypeError pc.addTransceiver is not a function
-FAIL new RTCTrackEvent() with no receiver should throw TypeError pc.addTransceiver is not a function
+FAIL new RTCTrackEvent() with valid receiver, track, transceiver should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL new RTCTrackEvent() with no transceiver should throw TypeError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL new RTCTrackEvent() with no track should throw TypeError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
+FAIL new RTCTrackEvent() with no receiver should throw TypeError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/interfaces.https-expected.txt
index 1aad4bf..c3d3875 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/interfaces.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/interfaces.https-expected.txt
@@ -17,7 +17,7 @@
 PASS MediaStreamTrack interface: existence and properties of interface prototype object's @@unscopables property
 PASS MediaStreamTrack must be primary interface of idlTestObjects.mediaStreamTrack
 PASS Stringification of idlTestObjects.mediaStreamTrack
-FAIL MediaStreamTrack must be primary interface of generateMediaStreamTrack('audio') assert_equals: Unexpected exception when evaluating object expected null but got object "Error: assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain"
-FAIL Stringification of generateMediaStreamTrack('audio') assert_equals: Unexpected exception when evaluating object expected null but got object "Error: assert_idl_attribute: Expect pc to have addTransceiver() method property "addTransceiver" not found in prototype chain"
+FAIL MediaStreamTrack must be primary interface of generateMediaStreamTrack('audio') assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Stringification of generateMediaStreamTrack('audio') assert_equals: Unexpected exception when evaluating object expected null but got object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js b/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js
index 5adf0a2..eaa7887 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js
@@ -1,3 +1,25 @@
+// These tests rely on the User Agent providing an implementation of the
+// WebXR Testing API (https://github.com/immersive-web/webxr-test-api).
+//
+// In Chromium-based browsers, this implementation is provided by a JavaScript
+// shim in order to reduce the amount of test-only code shipped to users. To
+// enable these tests the browser must be run with these options:
+//
+//   --enable-blink-features=MojoJS,MojoJSTest
+
+function xr_promise_test(func, name, properties) {
+  promise_test(async (t) => {
+    // Perform any required test setup:
+
+    if (window.XRTest === undefined) {
+      // Chrome setup
+      await loadChromiumResources;
+    }
+
+    return func(t);
+  }, name, properties);
+}
+
 // This functions calls a callback with each API object as specified
 // by https://immersive-web.github.io/webxr/spec/latest/, allowing
 // checks to be made on all ojects.
@@ -25,4 +47,32 @@
   callback(window.XRStageBoundsPoint, 'XRStageBoundsPoint');
   callback(window.XRSessionEvent, 'XRSessionEvent');
   callback(window.XRCoordinateSystemEvent, 'XRCoordinateSystemEvent');
-}
\ No newline at end of file
+}
+
+// Code for loading test api in chromium.
+let loadChromiumResources = Promise.resolve().then(() => {
+  if (!MojoInterfaceInterceptor) {
+    // Do nothing on non-Chromium-based browsers or when the Mojo bindings are
+    // not present in the global namespace.
+    return;
+  }
+
+  let chain = Promise.resolve();
+  ['/gen/layout_test_data/mojo/public/js/mojo_bindings.js',
+   '/gen/ui/gfx/geometry/mojo/geometry.mojom.js',
+   '/gen/mojo/public/mojom/base/time.mojom.js',
+   '/gen/device/vr/public/mojom/vr_service.mojom.js',
+   '/resources/chromium/webxr-test.js', '/resources/testdriver.js',
+   '/resources/testdriver-vendor.js',
+  ].forEach(path => {
+    let script = document.createElement('script');
+    script.src = path;
+    script.async = false;
+    chain = chain.then(() => new Promise(resolve => {
+                         script.onload = () => resolve();
+                       }));
+    document.head.appendChild(script);
+  });
+
+  return chain;
+});
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webxr/xrSession_exclusive_requestAnimationFrame.https.html b/third_party/WebKit/LayoutTests/external/wpt/webxr/xrSession_exclusive_requestAnimationFrame.https.html
new file mode 100644
index 0000000..010ab0b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webxr/xrSession_exclusive_requestAnimationFrame.https.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src="resources/webxr_util.js"></script>
+  <canvas id="webgl-canvas"></canvas>
+
+  <script>
+
+  const identityMatrix = new Float32Array([
+    1, 0, 0, 0,
+    0, 1, 0, 0,
+    0, 0, 1, 0,
+    0, 0, 0, 1
+  ]);
+
+  const rightFakeXRViewInit =
+    {eye:"right", projectionMatrix: identityMatrix, viewMatrix: identityMatrix};
+
+  const leftFakeXRViewInit =
+    {eye:"left", projectionMatrix: identityMatrix, viewMatrix: identityMatrix};
+
+  const immersiveFakeXRDeviceInit = { supportsImmersive:true };
+
+  const webglCanvas = document.getElementById('webgl-canvas');
+  let gl = webglCanvas.getContext('webgl', { alpha: false, antialias: false });
+
+  let testDevice;
+  let testDeviceController;
+  let testSession;
+
+  xr_promise_test(
+    (t) => XRTest.simulateDeviceConnection(immersiveFakeXRDeviceInit)
+      .then((controller) => {
+        testDeviceController = controller;
+        return navigator.xr.requestDevice();
+      })
+      .then((device) => {
+        testDevice = device;
+        return gl.setCompatibleXRDevice(device);
+      })
+      .then(() => new Promise((resolve, reject) => {
+          // Perform the session request in a user gesture.
+          XRTest.simulateUserActivation(() => {
+            testDevice.requestSession({ immersive: true })
+              .then((session) => {
+                testSession = session;
+                return session.requestFrameOfReference('eye-level');
+              })
+              .then((frameOfRef) => {
+                // Session must have a baseLayer or frame requests will be ignored.
+                testSession.baseLayer = new XRWebGLLayer(testSession, gl);
+
+                function onFrame(time, xrFrame) {
+                  assert_true(xrFrame instanceof XRFrame);
+
+                  assert_not_equals(xrFrame.views, null);
+                  assert_equals(xrFrame.views.length, 2);
+
+                  let devicePose = xrFrame.getDevicePose(frameOfRef);
+
+                  assert_not_equals(devicePose, null);
+                  for(let i = 0; i < identityMatrix.length; i++) {
+                    assert_equals(devicePose.poseModelMatrix[i], identityMatrix[i]);
+                  }
+
+                  assert_not_equals(devicePose.getViewMatrix(xrFrame.views[0]), null);
+                  assert_equals(devicePose.getViewMatrix(xrFrame.views[0]).length, 16);
+                  assert_not_equals(devicePose.getViewMatrix(xrFrame.views[1]), null);
+                  assert_equals(devicePose.getViewMatrix(xrFrame.views[1]).length, 16);
+
+                  // Test does not complete until the returned promise resolves.
+                  resolve();
+                }
+
+                testDeviceController.setXRPresentationFrameData(
+                  identityMatrix,
+                  [rightFakeXRViewInit, leftFakeXRViewInit]
+                );
+
+                testSession.requestAnimationFrame(onFrame);
+              }).catch((err) => {
+                reject("Session was rejected with error: "+err);
+              });
+          });
+        })
+      ),
+    "RequestAnimationFrame resolves with good data"
+  );
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element-expected.txt
deleted file mode 100644
index 7ff9412..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element-expected.txt
+++ /dev/null
@@ -1,262 +0,0 @@
-Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.
-{
-  "domNodes": [
-    {
-      "nodeType": 9,
-      "nodeName": "#document",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "childNodeIndexes": [
-        1
-      ],
-      "layoutNodeIndex": 0,
-      "documentURL": "<string>",
-      "baseURL": "<string>",
-      "documentEncoding": "windows-1252",
-      "frameId": "<string>"
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "HTML",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "childNodeIndexes": [
-        2,
-        6
-      ],
-      "layoutNodeIndex": 1,
-      "frameId": "<string>"
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "HEAD",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "childNodeIndexes": [
-        3,
-        5
-      ]
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "STYLE",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "childNodeIndexes": [
-        4
-      ]
-    },
-    {
-      "nodeType": 3,
-      "nodeName": "#text",
-      "nodeValue": "\n    .c::first-letter { font-weight: bold; color: blue; }\n    .c::before { counter-increment: square; content: 'square: ' counter(squre) url(square.png) '! '; }\n  ",
-      "backendNodeId": "<number>"
-    },
-    {
-      "nodeType": 3,
-      "nodeName": "#text",
-      "nodeValue": "\n  ",
-      "backendNodeId": "<number>"
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "BODY",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "childNodeIndexes": [
-        7,
-        8,
-        12
-      ],
-      "layoutNodeIndex": 2
-    },
-    {
-      "nodeType": 3,
-      "nodeName": "#text",
-      "nodeValue": "\n    ",
-      "backendNodeId": "<number>"
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "P",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "childNodeIndexes": [
-        11
-      ],
-      "attributes": [
-        {
-          "name": "class",
-          "value": "c"
-        }
-      ],
-      "pseudoElementIndexes": [
-        9,
-        10
-      ],
-      "layoutNodeIndex": 3
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "<pseudo:first-letter>",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "layoutNodeIndex": 4,
-      "pseudoType": "first-letter"
-    },
-    {
-      "nodeType": 1,
-      "nodeName": "<pseudo:before>",
-      "nodeValue": "",
-      "backendNodeId": "<number>",
-      "layoutNodeIndex": 6,
-      "pseudoType": "before"
-    },
-    {
-      "nodeType": 3,
-      "nodeName": "#text",
-      "nodeValue": "I have some content before me with a first letter.",
-      "backendNodeId": "<number>",
-      "layoutNodeIndex": 12
-    },
-    {
-      "nodeType": 3,
-      "nodeName": "#text",
-      "nodeValue": "\n  \n\n",
-      "backendNodeId": "<number>"
-    }
-  ],
-  "layoutTreeNodes": [
-    {
-      "domNodeIndex": 0,
-      "boundingBox": "<object>"
-    },
-    {
-      "domNodeIndex": 1,
-      "boundingBox": "<object>",
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 6,
-      "boundingBox": "<object>",
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 8,
-      "boundingBox": "<object>",
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 9,
-      "boundingBox": "<object>",
-      "styleIndex": 1
-    },
-    {
-      "domNodeIndex": 9,
-      "boundingBox": "<object>",
-      "layoutText": "s",
-      "inlineTextNodes": [
-        {
-          "boundingBox": "<object>",
-          "startCharacterIndex": 0,
-          "numCharacters": 1
-        }
-      ],
-      "styleIndex": 1
-    },
-    {
-      "domNodeIndex": 10,
-      "boundingBox": "<object>",
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 10,
-      "boundingBox": "<object>",
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 10,
-      "boundingBox": "<object>",
-      "layoutText": "quare: ",
-      "inlineTextNodes": [
-        {
-          "boundingBox": "<object>",
-          "startCharacterIndex": 0,
-          "numCharacters": 7
-        }
-      ],
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 10,
-      "boundingBox": "<object>",
-      "layoutText": "0",
-      "inlineTextNodes": [
-        {
-          "boundingBox": "<object>",
-          "startCharacterIndex": 0,
-          "numCharacters": 1
-        }
-      ],
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 10,
-      "boundingBox": "<object>",
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 10,
-      "boundingBox": "<object>",
-      "layoutText": "! ",
-      "inlineTextNodes": [
-        {
-          "boundingBox": "<object>",
-          "startCharacterIndex": 0,
-          "numCharacters": 2
-        }
-      ],
-      "styleIndex": 0
-    },
-    {
-      "domNodeIndex": 11,
-      "boundingBox": "<object>",
-      "layoutText": "I have some content before me with a first letter.",
-      "inlineTextNodes": [
-        {
-          "boundingBox": "<object>",
-          "startCharacterIndex": 0,
-          "numCharacters": 50
-        }
-      ],
-      "styleIndex": 0
-    }
-  ],
-  "computedStyles": [
-    {
-      "properties": [
-        {
-          "name": "font-weight",
-          "value": "400"
-        },
-        {
-          "name": "color",
-          "value": "rgb(0, 0, 0)"
-        }
-      ]
-    },
-    {
-      "properties": [
-        {
-          "name": "font-weight",
-          "value": "700"
-        },
-        {
-          "name": "color",
-          "value": "rgb(0, 0, 255)"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js
deleted file mode 100644
index a50017a..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js
+++ /dev/null
@@ -1,17 +0,0 @@
-(async function(testRunner) {
-  var {page, session, dp} = await testRunner.startURL('../resources/dom-snapshot-pseudo-element.html', 'Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.');
-
-  function stabilize(key, value) {
-    var unstableKeys = ['documentURL', 'baseURL', 'frameId', 'backendNodeId', 'boundingBox'];
-    if (unstableKeys.indexOf(key) !== -1)
-      return '<' + typeof(value) + '>';
-    return value;
-  }
-
-  var response = await dp.DOMSnapshot.getSnapshot({'computedStyleWhitelist': ['font-weight', 'color'], 'includeEventListeners': true});
-  if (response.error)
-    testRunner.log(response);
-  else
-    testRunner.log(JSON.stringify(response.result, stabilize, 2));
-  testRunner.completeTest();
-})
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/resources/dom-snapshot-pseudo-element.html b/third_party/WebKit/LayoutTests/inspector-protocol/resources/dom-snapshot-pseudo-element.html
deleted file mode 100644
index e1995e9b..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/resources/dom-snapshot-pseudo-element.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
-  <style>
-    .c::first-letter { font-weight: bold; color: blue; }
-    .c::before { counter-increment: square; content: 'square: ' counter(squre) url(square.png) '! '; }
-  </style>
-  <body>
-    <p class='c'>I have some content before me with a first letter.</p>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
deleted file mode 100644
index b4d9e25f..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-This is a testharness.js-based test.
-PASS # AUDIT TASK RUNNER STARTED.
-PASS > [ref-distance-error] 
-FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
-PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
-FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.refDistance = 0 did not throw an exception.
-PASS   panner.refDistance = 5e-324 did not throw an exception.
-FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [max-distance-error] 
-FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
-FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.maxDistance = 5e-324 did not throw an exception.
-FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [min-distance] 
-PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS < [min-distance] All assertions passed. (total 12 assertions)
-PASS > [max-distance] 
-PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351098328828812,0.23690398037433624,-0.11514916270971298,-0.20979724824428558,-0.012793892063200474,0.021439947187900543,0.2256566733121872,0.07854988425970078,-0.24533408880233765,-0.08270072191953659,0.0001093835016945377,0.12551122903823853,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
-PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.0014285872457548976,0.0032695855479687452,-0.0015892094234004617,-0.002895476995036006,-0.0001765724882716313,0.000295899371849373,0.0031143580563366413,0.0010840913746505976,-0.003385932184755802,-0.0011413784231990576,0.0000015096356946742162,0.0017322194762527943,0.0030744909308850765,-0.002051546471193433,-0.002635899931192398...].
-PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001128410105594,0.000041198902181349695,-0.000020025070625706576,-0.000036484892916632816,-0.00000222492803914065,0.0000037285244616214186,0.000039242931961780414,0.00001366025571769569,-0.00004266494215698913,-0.000014382108929567039,1.902239077367085e-8,0.000021827090677106753,0.00003874058529618196,-0.00002585081892902963,-0.000033214051654795185...].
-PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351098328828812,0.23690398037433624,-0.11514916270971298,-0.20979724824428558,-0.012793892063200474,0.021439947187900543,0.2256566733121872,0.07854988425970078,-0.24533408880233765,-0.08270072191953659,0.0001093835016945377,0.12551122903823853,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
-PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.009258303791284561,0.021189337596297264,-0.010299254208803177,-0.018764836713671684,-0.0011443205876275897,0.001917647197842598,0.020183347165584564,0.007025715429335833,-0.021943349391222,-0.007396977860480547,0.00000978355819825083,0.011226066388189793,0.019924979656934738,-0.013295541517436504,-0.017082585021853447...].
-PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264349889941514,0.0018914489774033427,-0.0009193546138703823,-0.0016750278882682323,-0.00010214684152742848,0.000171177220181562,0.0018016500398516655,0.0006271447637118399,-0.001958755310624838,-0.0006602851790376008,8.733213689993136e-7,0.0010020856279879808,0.0017785871168598533,-0.0011868156725540757,-0.0015248629497364163...].
-PASS < [max-distance] All assertions passed. (total 12 assertions)
-FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
deleted file mode 100644
index 8dc474c8..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-This is a testharness.js-based test.
-PASS # AUDIT TASK RUNNER STARTED.
-PASS > [ref-distance-error] 
-FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
-PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
-FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.refDistance = 0 did not throw an exception.
-PASS   panner.refDistance = 5e-324 did not throw an exception.
-FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [max-distance-error] 
-FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
-FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.maxDistance = 5e-324 did not throw an exception.
-FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [min-distance] 
-PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS < [min-distance] All assertions passed. (total 12 assertions)
-PASS > [max-distance] 
-PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351096093654633,0.23690393567085266,-0.11514917016029358,-0.2097972184419632,-0.012793886475265026,0.021439937874674797,0.22565661370754242,0.07854988425970078,-0.24533402919769287,-0.0827007070183754,0.00010937785555142909,0.12551121413707733,0.22276799380779266,-0.14864864945411682,-0.19098907709121704...].
-PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.001428587012924254,0.0032695848494768143,-0.0015892095398157835,-0.0028954767622053623,-0.00017657240096013993,0.00029589925543405116,0.0031143571250140667,0.0010840913746505976,-0.0033859312534332275,-0.001141378190368414,0.000001509557819190377,0.0017322193598374724,0.003074490465223789,-0.002051546238362789,-0.0026358996983617544...].
-PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001124772126786,0.00004119889490539208,-0.00002002507244469598,-0.0000364848856406752,-0.0000022249271296459483,0.0000037285228700056905,0.0000392429246858228,0.00001366025571769569,-0.00004266493488103151,-0.000014382106201082934,1.902140844833866e-8,0.00002182708885811735,0.00003874057802022435,-0.00002585081529105082,-0.00003321404801681638...].
-PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351096093654633,0.23690393567085266,-0.11514917016029358,-0.2097972184419632,-0.012793886475265026,0.021439937874674797,0.22565661370754242,0.07854988425970078,-0.24533402919769287,-0.0827007070183754,0.00010937785555142909,0.12551121413707733,0.22276799380779266,-0.14864864945411682,-0.19098907709121704...].
-PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264348143711686,0.0018914486281573772,-0.0009193546720780432,-0.0016750276554375887,-0.00010214679787168279,0.00017117714742198586,0.0018016495741903782,0.0006271447637118399,-0.001958754612132907,-0.0006602850626222789,8.732762921681569e-7,0.001002085511572659,0.0017785867676138878,-0.0011868155561387539,-0.0015248628333210945...].
-PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.009258301928639412,0.021189333871006966,-0.010299255140125751,-0.018764834851026535,-0.0011443200055509806,0.0019176463829353452,0.020183341577649117,0.007025715429335833,-0.021943343803286552,-0.007396976463496685,0.000009783053428691346,0.011226064525544643,0.01992497593164444,-0.013295539654791355,-0.017082583159208298...].
-PASS < [max-distance] All assertions passed. (total 12 assertions)
-FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
deleted file mode 100644
index 88b87d8..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-This is a testharness.js-based test.
-PASS # AUDIT TASK RUNNER STARTED.
-PASS > [ref-distance-error] 
-FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
-PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
-FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.refDistance = 0 did not throw an exception.
-PASS   panner.refDistance = 5e-324 did not throw an exception.
-FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [max-distance-error] 
-FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
-FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.maxDistance = 5e-324 did not throw an exception.
-FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [min-distance] 
-PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
-PASS < [min-distance] All assertions passed. (total 12 assertions)
-PASS > [max-distance] 
-PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351096093654633,0.23690393567085266,-0.11514917016029358,-0.2097972184419632,-0.012793886475265026,0.021439937874674797,0.22565661370754242,0.07854988425970078,-0.24533402919769287,-0.0827007070183754,0.00010937785555142909,0.12551121413707733,0.22276799380779266,-0.14864864945411682,-0.19098907709121704...].
-PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.001428587012924254,0.0032695848494768143,-0.0015892095398157835,-0.0028954767622053623,-0.00017657240096013993,0.00029589925543405116,0.0031143571250140667,0.0010840913746505976,-0.0033859312534332275,-0.001141378190368414,0.000001509557819190377,0.0017322193598374724,0.003074490465223789,-0.002051546238362789,-0.0026358996983617544...].
-PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001124772126786,0.00004119889490539208,-0.00002002507244469598,-0.0000364848856406752,-0.0000022249271296459483,0.0000037285228700056905,0.0000392429246858228,0.00001366025571769569,-0.00004266493488103151,-0.000014382106201082934,1.902140844833866e-8,0.00002182708885811735,0.00003874057802022435,-0.00002585081529105082,-0.00003321404801681638...].
-PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351096093654633,0.23690393567085266,-0.11514917016029358,-0.2097972184419632,-0.012793886475265026,0.021439937874674797,0.22565661370754242,0.07854988425970078,-0.24533402919769287,-0.0827007070183754,0.00010937785555142909,0.12551121413707733,0.22276799380779266,-0.14864864945411682,-0.19098907709121704...].
-PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.009258301928639412,0.021189333871006966,-0.010299255140125751,-0.018764834851026535,-0.0011443200055509806,0.0019176463829353452,0.020183341577649117,0.007025715429335833,-0.021943343803286552,-0.007396976463496685,0.000009783053428691346,0.011226064525544643,0.01992497593164444,-0.013295539654791355,-0.017082583159208298...].
-PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264348143711686,0.0018914486281573772,-0.0009193546720780432,-0.0016750276554375887,-0.00010214679787168279,0.00017117714742198586,0.0018016495741903782,0.0006271447637118399,-0.001958754612132907,-0.0006602850626222789,8.732762921681569e-7,0.001002085511572659,0.0017785867676138878,-0.0011868155561387539,-0.0015248628333210945...].
-PASS < [max-distance] All assertions passed. (total 12 assertions)
-FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
deleted file mode 100644
index e5c3097..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-This is a testharness.js-based test.
-PASS # AUDIT TASK RUNNER STARTED.
-PASS > [ref-distance-error] 
-FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
-PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
-FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.refDistance = 0 did not throw an exception.
-PASS   panner.refDistance = 5e-324 did not throw an exception.
-FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [max-distance-error] 
-FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
-FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
-FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
-PASS   panner.maxDistance = 5e-324 did not throw an exception.
-FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
-PASS > [min-distance] 
-PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
-PASS < [min-distance] All assertions passed. (total 12 assertions)
-PASS > [max-distance] 
-PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351099818944931,0.23690398037433624,-0.11514918506145477,-0.20979724824428558,-0.012793904170393944,0.02143995463848114,0.2256566733121872,0.07854988425970078,-0.24533405900001526,-0.08270072191953659,0.00010938305058516562,0.12551124393939972,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
-PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.0014285874785855412,0.0032695855479687452,-0.0015892097726464272,-0.002895476995036006,-0.0001765726483426988,0.0002958994882646948,0.0031143580563366413,0.0010840913746505976,-0.003385931719094515,-0.0011413784231990576,0.0000015096295555849792,0.001732219709083438,0.0030744909308850765,-0.002051546471193433,-0.002635899931192398...].
-PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
-PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001130229094997,0.000041198902181349695,-0.000020025074263685383,-0.000036484892916632816,-0.000002224930085503729,0.0000037285258258634713,0.000039242931961780414,0.00001366025571769569,-0.00004266493851901032,-0.000014382108929567039,1.9022312613969916e-8,0.00002182709431508556,0.00003874058529618196,-0.00002585081892902963,-0.000033214051654795185...].
-PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351099818944931,0.23690398037433624,-0.11514918506145477,-0.20979724824428558,-0.012793904170393944,0.02143995463848114,0.2256566733121872,0.07854988425970078,-0.24533405900001526,-0.08270072191953659,0.00010938305058516562,0.12551124393939972,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
-PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.00925830565392971,0.021189337596297264,-0.0102992570027709,-0.018764836713671684,-0.0011443216353654861,0.001917647896334529,0.020183347165584564,0.007025715429335833,-0.0219433456659317,-0.007396977860480547,0.000009783518180483952,0.011226067319512367,0.019924979656934738,-0.013295541517436504,-0.017082585021853447...].
-PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
-PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264351054094732,0.0018914489774033427,-0.000919354788493365,-0.0016750278882682323,-0.00010214693611487746,0.00017117727838922292,0.0018016500398516655,0.0006271447637118399,-0.0019587548449635506,-0.0006602851790376008,8.733177878639253e-7,0.0010020857444033027,0.0017785871168598533,-0.0011868156725540757,-0.0015248629497364163...].
-PASS < [max-distance] All assertions passed. (total 12 assertions)
-FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-timing.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-timing.https-expected.txt
deleted file mode 100644
index 3cf6933e..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-timing.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service worker controlled navigation timing assert_unreached: unexpected rejection: assert_true: Expected workerStart <= fetchStart expected true got false Reached unreachable code
-PASS Service worker controlled navigation timing network fallback
-PASS Service worker controlled navigation timing redirect
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-timing.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-timing.https-expected.txt
deleted file mode 100644
index 3cf6933e..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-timing.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service worker controlled navigation timing assert_unreached: unexpected rejection: assert_true: Expected workerStart <= fetchStart expected true got false Reached unreachable code
-PASS Service worker controlled navigation timing network fallback
-PASS Service worker controlled navigation timing redirect
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index b4e724b49..2ae7d7b 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1027,6 +1027,110 @@
 [Worker]     method sort
 [Worker]     method toString
 [Worker]     method values
+[Worker] interface USB : EventTarget
+[Worker]     attribute @@toStringTag
+[Worker]     getter onconnect
+[Worker]     getter ondisconnect
+[Worker]     method constructor
+[Worker]     method getDevices
+[Worker]     setter onconnect
+[Worker]     setter ondisconnect
+[Worker] interface USBAlternateInterface
+[Worker]     attribute @@toStringTag
+[Worker]     getter alternateSetting
+[Worker]     getter endpoints
+[Worker]     getter interfaceClass
+[Worker]     getter interfaceName
+[Worker]     getter interfaceProtocol
+[Worker]     getter interfaceSubclass
+[Worker]     method constructor
+[Worker] interface USBConfiguration
+[Worker]     attribute @@toStringTag
+[Worker]     getter configurationName
+[Worker]     getter configurationValue
+[Worker]     getter interfaces
+[Worker]     method constructor
+[Worker] interface USBConnectionEvent : Event
+[Worker]     attribute @@toStringTag
+[Worker]     getter device
+[Worker]     method constructor
+[Worker] interface USBDevice
+[Worker]     attribute @@toStringTag
+[Worker]     getter configuration
+[Worker]     getter configurations
+[Worker]     getter deviceClass
+[Worker]     getter deviceProtocol
+[Worker]     getter deviceSubclass
+[Worker]     getter deviceVersionMajor
+[Worker]     getter deviceVersionMinor
+[Worker]     getter deviceVersionSubminor
+[Worker]     getter manufacturerName
+[Worker]     getter opened
+[Worker]     getter productId
+[Worker]     getter productName
+[Worker]     getter serialNumber
+[Worker]     getter usbVersionMajor
+[Worker]     getter usbVersionMinor
+[Worker]     getter usbVersionSubminor
+[Worker]     getter vendorId
+[Worker]     method claimInterface
+[Worker]     method clearHalt
+[Worker]     method close
+[Worker]     method constructor
+[Worker]     method controlTransferIn
+[Worker]     method controlTransferOut
+[Worker]     method isochronousTransferIn
+[Worker]     method isochronousTransferOut
+[Worker]     method open
+[Worker]     method releaseInterface
+[Worker]     method reset
+[Worker]     method selectAlternateInterface
+[Worker]     method selectConfiguration
+[Worker]     method transferIn
+[Worker]     method transferOut
+[Worker] interface USBEndpoint
+[Worker]     attribute @@toStringTag
+[Worker]     getter direction
+[Worker]     getter endpointNumber
+[Worker]     getter packetSize
+[Worker]     getter type
+[Worker]     method constructor
+[Worker] interface USBInTransferResult
+[Worker]     attribute @@toStringTag
+[Worker]     getter data
+[Worker]     getter status
+[Worker]     method constructor
+[Worker] interface USBInterface
+[Worker]     attribute @@toStringTag
+[Worker]     getter alternate
+[Worker]     getter alternates
+[Worker]     getter claimed
+[Worker]     getter interfaceNumber
+[Worker]     method constructor
+[Worker] interface USBIsochronousInTransferPacket
+[Worker]     attribute @@toStringTag
+[Worker]     getter data
+[Worker]     getter status
+[Worker]     method constructor
+[Worker] interface USBIsochronousInTransferResult
+[Worker]     attribute @@toStringTag
+[Worker]     getter data
+[Worker]     getter packets
+[Worker]     method constructor
+[Worker] interface USBIsochronousOutTransferPacket
+[Worker]     attribute @@toStringTag
+[Worker]     getter bytesWritten
+[Worker]     getter status
+[Worker]     method constructor
+[Worker] interface USBIsochronousOutTransferResult
+[Worker]     attribute @@toStringTag
+[Worker]     getter packets
+[Worker]     method constructor
+[Worker] interface USBOutTransferResult
+[Worker]     attribute @@toStringTag
+[Worker]     getter bytesWritten
+[Worker]     getter status
+[Worker]     method constructor
 [Worker] interface WebGL2RenderingContext
 [Worker]     attribute @@toStringTag
 [Worker]     attribute ACTIVE_ATTRIBUTES
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 290950a..17bad86 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -4809,6 +4809,7 @@
     method addIceCandidate
     method addStream
     method addTrack
+    method addTransceiver
     method close
     method constructor
     method createAnswer
@@ -8339,6 +8340,7 @@
     method addIceCandidate
     method addStream
     method addTrack
+    method addTransceiver
     method close
     method constructor
     method createAnswer
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt
new file mode 100644
index 0000000..5bd1585
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+PASS insertDTMF() should succeed if tones contains valid DTMF characters
+PASS insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters
+FAIL insertDTMF() should throw InvalidStateError if transceiver is stopped transceiver.stop is not a function
+PASS insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly
+PASS insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive
+PASS insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden
+PASS insertDTMF() after remove and close should reject
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
index 4deba74..3e68af92 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
@@ -10,7 +10,7 @@
 PASS Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones
 PASS Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones
 PASS Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing
-FAIL Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing pc.addTransceiver is not a function
+FAIL Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing Failed to execute 'insertDTMF' on 'RTCDTMFSender': The 'canInsertDTMF' attribute is false: this sender cannot send DTMF.
 PASS Tone change event constructor works
 PASS Tone change event with unexpected name should not crash
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt
index 9ae3282..db32f43 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTrack.https-expected.txt
@@ -4,9 +4,9 @@
 PASS addTrack with single track argument and single stream should succeed
 PASS addTrack with single track argument and multiple streams should succeed
 PASS Adding the same track multiple times should throw InvalidAccessError
-FAIL addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL addTrack with existing sender that has not been used to send should reuse the sender promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
-FAIL addTrack with existing sender that has been used to send should create new sender promise_test: Unhandled rejection with value: object "TypeError: caller.addTransceiver is not a function"
-FAIL addTrack with existing sender with null track, different kind, and recvonly direction should create new sender promise_test: Unhandled rejection with value: object "TypeError: pc.addTransceiver is not a function"
+PASS addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender
+PASS addTrack with existing sender that has not been used to send should reuse the sender
+PASS addTrack with existing sender that has been used to send should create new sender
+PASS addTrack with existing sender with null track, different kind, and recvonly direction should create new sender
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt
new file mode 100644
index 0000000..de3a0d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver-expected.txt
@@ -0,0 +1,47 @@
+This is a testharness.js-based test.
+PASS addTransceiver() with string argument as invalid kind should throw TypeError
+FAIL addTransceiver('audio') should return an audio transceiver assert_equals: expected true but got false
+FAIL addTransceiver('video') should return a video transceiver assert_equals: expected true but got false
+PASS addTransceiver() with direction sendonly should have result transceiver.direction be the same
+PASS addTransceiver() with direction inactive should have result transceiver.direction be the same
+PASS addTransceiver() with invalid direction should throw TypeError
+FAIL addTransceiver(track) should have result with sender.track be given track assert_equals: expected true but got false
+PASS addTransceiver(track) multiple times should create multiple transceivers
+FAIL addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          rid: '@Invalid!'
+        }]
+      })" did not throw
+FAIL addTransceiver() with rid longer than 16 characters should throw TypeError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          rid: 'a'.repeat(17)
+        }]
+      })" did not throw
+PASS addTransceiver() with valid rid value should succeed
+FAIL addTransceiver() with readonly ssrc set should throw InvalidAccessError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          ssrc: 2
+        }]
+      })" did not throw
+FAIL addTransceiver() with readonly rtx set should throw InvalidAccessError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          rtx: {
+            ssrc: 2
+          }
+        }]
+      })" did not throw
+FAIL addTransceiver() with readonly fec set should throw InvalidAccessError assert_throws: function "() =>
+      pc.addTransceiver('audio', {
+        sendEncodings: [{
+          fec: {
+            ssrc: 2
+          }
+        }]
+      })" did not throw
+PASS addTransceiver() with valid sendEncodings should succeed
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt
index 3422275..72690d4 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-expected.txt
@@ -2,7 +2,7 @@
 FAIL createOffer() with no argument from newly created RTCPeerConnection should succeed assert_false: Expect offer to not be instance of RTCSessionDescription expected false got true
 FAIL createOffer() and then setLocalDescription() should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
 PASS createOffer() after connection is closed should reject with InvalidStateError
-FAIL When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream pc.addTransceiver is not a function
+FAIL When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream assert_equals: Expect m=audio line to be found in offer SDP expected 1 but got 0
 PASS createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers
 PASS createOffer() with offerToReceiveVideo should add video line to all subsequent created offers
 PASS createOffer() with offerToReceiveAudio:true then offerToReceiveVideo:true should have result offer with both audio and video line
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt
index 561ec28..8d98715 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-createOffer-offerToReceive-expected.txt
@@ -4,14 +4,14 @@
 FAIL offerToReceiveAudio option should be ignored if a non-stopped "recvonly" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
 PASS offerToReceiveAudio option should be ignored if a non-stopped "sendrecv" transceiver exists
 FAIL offerToReceiveAudio set to false with a track should create a "sendonly" transceiver assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
-FAIL offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive" pc.addTransceiver is not a function
+FAIL offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive" assert_equals: Expect transceiver to have "inactive" direction expected "inactive" but got "recvonly"
 FAIL subsequent offerToReceiveAudio set to false with a track should change the direction to "sendonly" assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
 PASS createOffer() with offerToReceiveVideo set to false should not create a transceiver
 FAIL createOffer() with offerToReceiveVideo should create a "recvonly" transceiver assert_equals: Expect pc to have one transceiver expected 1 but got 0
 FAIL offerToReceiveVideo option should be ignored if a non-stopped "recvonly" transceiver exists assert_equals: Expect pc to have one transceiver expected 1 but got 0
 PASS offerToReceiveVideo option should be ignored if a non-stopped "sendrecv" transceiver exists
 FAIL offerToReceiveVideo set to false with a track should create a "sendonly" transceiver assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
-FAIL offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive" pc.addTransceiver is not a function
+FAIL offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive" assert_equals: Expect transceiver to have "inactive" direction expected "inactive" but got "recvonly"
 FAIL subsequent offerToReceiveVideo set to false with a track should change the direction to "sendonly" assert_equals: Expect transceiver to have "sendonly" direction expected "sendonly" but got "sendrecv"
 FAIL offerToReceiveAudio and Video should create two "recvonly" transceivers assert_equals: Expect pc to have two transceivers expected 2 but got 0
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
new file mode 100644
index 0000000..14a75b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS getStats() with no argument should succeed
+PASS getStats(null) should succeed
+PASS getStats() with track not added to connection should reject with InvalidAccessError
+PASS getStats() with track added via addTrack should succeed
+PASS getStats() with track added via addTransceiver should succeed
+PASS getStats() with track associated with more than one sender should reject with InvalidAccessError
+PASS getStats() with track associated with both sender and receiver should reject with InvalidAccessError
+PASS getStats() with no argument should return stats report containing peer-connection stats on an empty PC
+FAIL getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
+FAIL getStats() with no argument should return stats for no-stream tracks assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
+FAIL getStats() on track associated with RtpSender should return stats report containing outbound-rtp stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
+FAIL getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats assert_true: Expect statsReport to contain stats object of type inbound-rtp expected true got false
+FAIL getStats() with connected peer connections having tracks and data channel should return all mandatory to implement stats assert_unreached: test failed with error: Error: assert_true: Expect dictionary.dataChannelIdentifier to be integer expected true got false Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-getTransceivers-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-getTransceivers-expected.txt
deleted file mode 100644
index 1928976..0000000
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-getTransceivers-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-PASS Initial peer connection should have list of zero senders, receivers and transceivers
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
new file mode 100644
index 0000000..0861101
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+PASS Creating first data channel should fire negotiationneeded event
+PASS calling createDataChannel twice should fire negotiationneeded event once
+PASS addTransceiver() should fire negotiationneeded event
+FAIL Calling addTransceiver() twice should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is fulfilled with: [object Object] Reached unreachable code
+FAIL Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is fulfilled with: [object Object] Reached unreachable code
+PASS negotiationneeded event should not fire if signaling state is not stable
+FAIL negotiationneeded event should fire only after signaling state go back to stable assert_unreached: Expect negotiationneeded promise to resolve after pc has set remote answer and go back to stable state Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
index 518b5f6..8037f38 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
@@ -2,7 +2,7 @@
 PASS setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed.
 PASS setRemoteDescription() with m= line of recvonly direction should not trigger track event
 PASS addTrack() should cause remote connection to fire ontrack when setRemoteDescription()
-FAIL addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription() pc1.addTransceiver is not a function
-FAIL addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription() pc1.addTransceiver is not a function
+PASS addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()
+PASS addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
new file mode 100644
index 0000000..e5c29e2c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError
+PASS addTrack - Calling removeTrack when connection is closed should throw InvalidStateError
+PASS addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError
+PASS addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError
+PASS addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError
+PASS addTrack - Calling removeTrack on different connection should throw InvalidAccessError
+PASS addTransceiver - Calling removeTrack with valid sender should set sender.track to null
+PASS addTrack - Calling removeTrack with valid sender should set sender.track to null
+PASS Calling removeTrack with currentDirection sendrecv should set direction to recvonly
+PASS Calling removeTrack with currentDirection sendonly should set direction to inactive
+PASS Calling removeTrack with currentDirection recvonly should not change direction
+PASS Calling removeTrack with currentDirection inactive should not change direction
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt
new file mode 100644
index 0000000..e2ccb8c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS setLocalDescription(offer) with m= section should assign mid to corresponding transceiver
+PASS setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver
+FAIL setLocalDescription(rollback) should unset transceiver.mid promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
+FAIL setLocalDescription(rollback) should only unset transceiver mids associated with current round promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
+FAIL setRemoteDescription(rollback) should remove newly created transceiver from transceiver list promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
deleted file mode 100644
index 44e2c10..0000000
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-FAIL setLocalDescription() with valid answer should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
-FAIL setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer assert_not_equals: Expect session description to be defined got disallowed value undefined
-PASS setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError
-FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
-FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt
index 8d3b493..7466031 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-expected.txt
@@ -1,8 +1,7 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught Error: assert_equals: expected "stable" but got "closed"
 PASS setRemoteDescription with invalid type and invalid SDP should reject with TypeError
-FAIL setRemoteDescription() with invalid SDP and stable state should reject with InvalidStateError assert_throws: function "() => { throw e }" threw object "OperationError: Failed to parse SessionDescription. invalid Expect line: v=" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
-FAIL Negotiation should fire signalingsstate events assert_equals: expected "stable" but got "have-local-offer"
+FAIL setRemoteDescription() with invalid SDP and stable state should reject with InvalidStateError assert_throws: function "() => { throw e }" threw object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. invalid Expect line: v=" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
+PASS Negotiation should fire signalingsstate events
 FAIL Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
 FAIL Switching role from offerer to answerer after going back to stable state should succeed promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sdp' of undefined"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
new file mode 100644
index 0000000..8570ecba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
@@ -0,0 +1,44 @@
+This is a testharness.js-based test.
+PASS addTrack: creates a transceiver for the sender
+PASS addTrack: "transceiver == {sender,receiver}"
+PASS addTrack: transceiver.sender is associated with the track
+PASS addTrack: transceiver.receiver has its own track
+FAIL addTrack: transceiver.receiver's track is muted assert_true: expected true got false
+PASS addTrack: transceiver is not associated with an m-section
+PASS addTrack: transceiver is not stopped
+PASS addTrack: transceiver's direction is sendrecv
+PASS addTrack: transceiver's currentDirection is null
+PASS setLocalDescription(offer): transceiver gets associated with an m-section
+PASS setLocalDescription(offer): transceiver.mid matches the offer SDP
+PASS setRemoteDescription(offer): ontrack fires with a track
+PASS setRemoteDescription(offer): ontrack's track.id is the same as track.id
+PASS setRemoteDescription(offer): ontrack fires with a transceiver.
+PASS setRemoteDescription(offer): transceiver.mid is the same on both ends
+PASS setRemoteDescription(offer): "transceiver == {sender,receiver}"
+PASS setRemoteDescription(offer): transceiver.direction is recvonly
+PASS setRemoteDescription(offer): transceiver.currentDirection is null
+PASS setRemoteDescription(offer): transceiver.stopped is false
+PASS setLocalDescription(answer): transceiver.currentDirection is recvonly
+PASS setLocalDescription(answer): transceiver.currentDirection is sendonly
+PASS addTransceiver(track): creates a transceiver for the track
+PASS addTransceiver(track): "transceiver == {sender,receiver}"
+PASS addTransceiver(track, init): initialize direction to inactive
+FAIL addTransceiver(track, init): initialize sendEncodings[0].active to false assert_false: expected false got true
+PASS addTransceiver(0 streams): ontrack fires with no stream
+PASS addTransceiver(1 stream): ontrack fires with corresponding stream
+PASS addTransceiver(2 streams): ontrack fires with corresponding two streams
+PASS addTrack(0 streams): ontrack fires with no stream
+PASS addTrack(1 stream): ontrack fires with corresponding stream
+PASS addTrack(2 streams): ontrack fires with corresponding two streams
+PASS addTransceiver('audio'): creates a transceiver with direction sendrecv
+PASS addTransceiver('audio'): transceiver.receiver.track.kind == 'audio'
+PASS addTransceiver('video'): transceiver.receiver.track.kind == 'video'
+PASS addTransceiver('audio'): transceiver.sender.track == null
+PASS addTransceiver('audio'): transceiver.currentDirection is null
+PASS addTransceiver('audio'): transceiver.stopped is false
+PASS addTrack reuses reusable transceivers
+PASS addTransceiver does not reuse reusable transceivers
+PASS Can setup two-way call using a single transceiver
+PASS Closing the PC stops the transceivers
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt
new file mode 100644
index 0000000..2a977b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-codecs-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS setParameters() with codec.payloadType modified should reject with InvalidModificationError
+PASS setParameters() with codec.mimeType modified should reject with InvalidModificationError
+PASS setParameters() with codec.clockRate modified should reject with InvalidModificationError
+PASS setParameters() with codec.channels modified should reject with InvalidModificationError
+PASS setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError
+PASS setParameters() with new codecs inserted should reject with InvalidModificationError
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt
new file mode 100644
index 0000000..57b1f47
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-degradationPreference-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL setParameters with degradationPreference set should succeed assert_equals: Expect initial param.degradationPreference to be balanced expected (string) "balanced" but got (undefined) undefined
+FAIL setParameters with degradationPreference unset should succeed assert_equals: Expect initial param.degradationPreference to be balanced expected (string) "balanced" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
new file mode 100644
index 0000000..b10eaf6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
@@ -0,0 +1,26 @@
+This is a testharness.js-based test.
+PASS addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true
+PASS addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true
+FAIL sender.getParameters() should return sendEncodings set by addTransceiver() assert_equals: expected (string) "enabled" but got (undefined) undefined
+PASS sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError
+FAIL sender.setParameters() with encodings unset should reject with InvalidModificationError assert_throws: function "function() { throw e }" threw object "TypeError: Failed to execute 'setParameters' on 'RTCRtpSender': required member encodings is undefined." that is not a DOMException InvalidModificationError: property "code" is equal to undefined, expected 13
+FAIL setParameters() with modified encoding.rtx field should reject with InvalidModificationError assert_unreached: Should have rejected: undefined Reached unreachable code
+FAIL setParameters() with modified encoding.rid field should reject with InvalidModificationError assert_equals: expected (string) "foo" but got (undefined) undefined
+FAIL setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError assert_unreached: Should have rejected: undefined Reached unreachable code
+FAIL setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed assert_approx_equals: expected a number but got a "undefined"
+FAIL setParameters() with modified encoding.dtx should succeed with RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
+FAIL setParameters() with modified encoding.dtx should succeed without RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
+FAIL setParameters() with unset encoding.dtx should succeed with RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
+FAIL setParameters() with unset encoding.dtx should succeed without RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
+FAIL setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit assert_equals: expected false but got true
+PASS setParameters() with modified encoding.active should succeed without RTCRtpTransceiverInit
+FAIL setParameters() with modified encoding.priority should succeed with RTCRtpTransceiverInit assert_equals: expected "very-low" but got "low"
+PASS setParameters() with modified encoding.priority should succeed without RTCRtpTransceiverInit
+FAIL setParameters() with modified encoding.ptime should succeed with RTCRtpTransceiverInit assert_equals: expected (number) 2 but got (undefined) undefined
+FAIL setParameters() with modified encoding.ptime should succeed without RTCRtpTransceiverInit assert_equals: expected (number) 2 but got (undefined) undefined
+FAIL setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit assert_equals: expected (number) 10000 but got (undefined) undefined
+PASS setParameters() with modified encoding.maxBitrate should succeed without RTCRtpTransceiverInit
+FAIL setParameters() with modified encoding.maxFramerate should succeed with RTCRtpTransceiverInit assert_equals: expected (number) 24 but got (undefined) undefined
+FAIL setParameters() with modified encoding.maxFramerate should succeed without RTCRtpTransceiverInit assert_equals: expected (number) 24 but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt
new file mode 100644
index 0000000..b3fae21
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-headerExtensions-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS setParameters() with modified headerExtensions should reject with InvalidModificationError
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt
new file mode 100644
index 0000000..d537b97
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-rtcp-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS setParameters() with modified rtcp.cname should reject with InvalidModificationError
+PASS setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt
new file mode 100644
index 0000000..babbdc5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-transactionId-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS sender.getParameters() should return different transaction IDs for each call
+PASS sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError
+FAIL sender.setParameters() with transaction ID unset should reject with InvalidModificationError assert_throws: function "function() { throw e }" threw object "TypeError: Failed to execute 'setParameters' on 'RTCRtpSender': required member transactionId is undefined." that is not a DOMException InvalidModificationError: property "code" is equal to undefined, expected 13
+PASS setParameters() twice with the same parameters should reject with InvalidStateError
+PASS setParameters() with parameters older than last getParameters() should reject with InvalidModificationError
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt
new file mode 100644
index 0000000..1f3c3e8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpReceiver-getParameters-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL RTCRtpReceiver.prototype.getParameters pc.getParameters is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
new file mode 100644
index 0000000..e9feef7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats assert_true: Expect statsReport to contain stats object of type inbound-rtp expected true got false
+FAIL receiver.getStats() via addTrack should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
new file mode 100644
index 0000000..0ad7465
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
+FAIL sender.getStats() via addTrack should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt
new file mode 100644
index 0000000..03841d9e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-replaceTrack.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS Calling replaceTrack on closed connection should reject with InvalidStateError
+FAIL Calling replaceTrack with track of different kind should reject with TypeError assert_throws: function "function() { throw e }" threw object "InvalidModificationError" ("InvalidModificationError") expected object "TypeError" ("TypeError")
+FAIL Calling replaceTrack on stopped sender should reject with InvalidStateError transceiver.stop is not a function
+PASS Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track
+PASS Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track
+PASS Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null
+PASS Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null
+PASS Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track
+PASS Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
new file mode 100644
index 0000000..2fc9877
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL setParameters() when transceiver is stopped should reject with InvalidStateError transceiver.stop is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt
new file mode 100644
index 0000000..a13c414
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver-setCodecPreferences-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed transceiver.setCodecPreferences is not a function
+FAIL setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed transceiver.setCodecPreferences is not a function
+FAIL setCodecPreferences() with both sender receiver codecs combined should succeed transceiver.setCodecPreferences is not a function
+FAIL setCodecPreferences([]) should succeed transceiver.setCodecPreferences is not a function
+FAIL setCodecPreferences() with reordered codecs should succeed transceiver.setCodecPreferences is not a function
+FAIL setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidAccessError Test bug: unrecognized DOMException code "() => transceiver.setCodecPreferences(capabilities.codecs)" passed to assert_throws()
+FAIL setCodecPreferences() with user defined codec should throw InvalidAccessError Test bug: unrecognized DOMException code "() => transceiver.setCodecPreferences(codecs)" passed to assert_throws()
+FAIL setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidAccessError Test bug: unrecognized DOMException code "() => transceiver.setCodecPreferences(codecs)" passed to assert_throws()
+FAIL setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidAccessError Test bug: unrecognized DOMException code "() => transceiver.setCodecPreferences(codecs)" passed to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt
new file mode 100644
index 0000000..3804544
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver-setDirection-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL setDirection should change transceiver.direction transceiver.setDirection is not a function
+FAIL setDirection with same direction should have no effect transceiver.setDirection is not a function
+FAIL setDirection should change transceiver.direction independent of transceiver.currentDirection assert_equals: expected "recvonly" but got "inactive"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt
new file mode 100644
index 0000000..7b3d87c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCTrackEvent-constructor-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL new RTCTrackEvent() with valid receiver, track, transceiver should succeed assert_equals: expected [] but got []
+PASS new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed
+PASS new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed
+PASS new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed
+PASS new RTCTrackEvent() with no transceiver should throw TypeError
+PASS new RTCTrackEvent() with no track should throw TypeError
+PASS new RTCTrackEvent() with no receiver should throw TypeError
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/interfaces.https-expected.txt
new file mode 100644
index 0000000..76de6779
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/interfaces.https-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS Main test driver
+PASS Test driver for asyncInitCertificate
+FAIL Test driver for asyncInitTransports assert_unreached: Failed to run asyncInitTransports: ReferenceError: RTCSctpTransport is not defined Reached unreachable code
+PASS Test driver for asyncInitMediaStreamTrack
+FAIL EventTarget interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function () { [native code] }" did not throw
+PASS EventTarget interface object length
+PASS EventTarget interface object name
+PASS EventTarget interface: existence and properties of interface prototype object
+PASS EventTarget interface: existence and properties of interface prototype object's "constructor" property
+PASS EventTarget interface: existence and properties of interface prototype object's @@unscopables property
+PASS MediaStreamTrack interface: existence and properties of interface object
+PASS MediaStreamTrack interface object length
+PASS MediaStreamTrack interface object name
+PASS MediaStreamTrack interface: existence and properties of interface prototype object
+PASS MediaStreamTrack interface: existence and properties of interface prototype object's "constructor" property
+PASS MediaStreamTrack interface: existence and properties of interface prototype object's @@unscopables property
+PASS MediaStreamTrack must be primary interface of idlTestObjects.mediaStreamTrack
+PASS Stringification of idlTestObjects.mediaStreamTrack
+PASS MediaStreamTrack must be primary interface of generateMediaStreamTrack('audio')
+PASS Stringification of generateMediaStreamTrack('audio')
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 7cab160..a4cf667e 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5440,6 +5440,7 @@
     method addIceCandidate
     method addStream
     method addTrack
+    method addTransceiver
     method close
     method constructor
     method createAnswer
@@ -10152,6 +10153,7 @@
     method addIceCandidate
     method addStream
     method addTrack
+    method addTransceiver
     method close
     method constructor
     method createAnswer
diff --git a/third_party/blink/public/platform/web_content_security_policy.h b/third_party/blink/public/platform/web_content_security_policy.h
index 3089f56..4d94b01 100644
--- a/third_party/blink/public/platform/web_content_security_policy.h
+++ b/third_party/blink/public/platform/web_content_security_policy.h
@@ -44,7 +44,9 @@
 enum WebContentSecurityPolicySource {
   kWebContentSecurityPolicySourceHTTP,
   kWebContentSecurityPolicySourceMeta,
-  kWebContentSecurityPolicySourceLast = kWebContentSecurityPolicySourceMeta
+  kWebContentSecurityPolicySourceOriginPolicy,
+  kWebContentSecurityPolicySourceLast =
+      kWebContentSecurityPolicySourceOriginPolicy
 };
 
 enum WebContentSecurityPolicyDisposition {
diff --git a/third_party/blink/public/platform/web_rtc_peer_connection_handler.h b/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
index f0cf75d..9c0e27aa 100644
--- a/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
+++ b/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
@@ -37,6 +37,7 @@
 #include "third_party/blink/public/platform/web_rtc_stats.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/webrtc/api/rtcerror.h"
+#include "third_party/webrtc/api/rtptransceiverinterface.h"
 
 namespace webrtc {
 enum class RTCErrorType;
@@ -100,6 +101,14 @@
   virtual WebRTCDataChannelHandler* CreateDataChannel(
       const WebString& label,
       const WebRTCDataChannelInit&) = 0;
+  virtual webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
+  AddTransceiverWithTrack(const WebMediaStreamTrack&,
+                          const webrtc::RtpTransceiverInit&) = 0;
+  virtual webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
+  AddTransceiverWithKind(
+      // webrtc::MediaStreamTrackInterface::kAudioKind or kVideoKind
+      std::string kind,
+      const webrtc::RtpTransceiverInit&) = 0;
   // Adds the track to the peer connection, returning the resulting transceiver
   // or error.
   virtual webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>> AddTrack(
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni
index 271c55a..4f0ccb0 100644
--- a/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -50,6 +50,8 @@
   "$bindings_modules_v8_output_dir/idb_object_store_or_idb_index_or_idb_cursor.h",
   "$bindings_modules_v8_output_dir/long_or_constrain_long_range.cc",
   "$bindings_modules_v8_output_dir/long_or_constrain_long_range.h",
+  "$bindings_modules_v8_output_dir/media_stream_track_or_string.cc",
+  "$bindings_modules_v8_output_dir/media_stream_track_or_string.h",
   "$bindings_modules_v8_output_dir/offscreen_rendering_context.cc",
   "$bindings_modules_v8_output_dir/offscreen_rendering_context.h",
   "$bindings_modules_v8_output_dir/password_credential_data_or_html_form_element.cc",
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index fa4dccf5..97bb343 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1992,6 +1992,7 @@
     "loader/modulescript/module_tree_linker_test.cc",
     "loader/navigation_policy_test.cc",
     "loader/ping_loader_test.cc",
+    "loader/previews_resource_loading_hints_test.cc",
     "loader/programmatic_scroll_test.cc",
     "loader/progress_tracker_test.cc",
     "loader/resource/css_style_sheet_resource_test.cc",
diff --git a/third_party/blink/renderer/core/animation/document_timeline.cc b/third_party/blink/renderer/core/animation/document_timeline.cc
index f907702b..a3e0de9 100644
--- a/third_party/blink/renderer/core/animation/document_timeline.cc
+++ b/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -95,7 +95,7 @@
 }
 
 bool DocumentTimeline::IsActive() {
-  return document_ && document_->GetPage();
+  return document_->GetPage();
 }
 
 void DocumentTimeline::AnimationAttached(Animation& animation) {
@@ -105,9 +105,6 @@
 }
 
 Animation* DocumentTimeline::Play(AnimationEffect* child) {
-  if (!document_)
-    return nullptr;
-
   Animation* animation = Animation::Create(child, this);
   DCHECK(animations_.Contains(animation));
 
@@ -197,7 +194,7 @@
 }
 
 void DocumentTimeline::DocumentTimelineTiming::ServiceOnNextFrame() {
-  if (timeline_->document_ && timeline_->document_->View())
+  if (timeline_->document_->View())
     timeline_->document_->View()->ScheduleAnimation();
 }
 
@@ -207,7 +204,7 @@
 }
 
 TimeTicks DocumentTimeline::ZeroTime() {
-  if (!zero_time_initialized_ && document_ && document_->Loader()) {
+  if (!zero_time_initialized_ && document_->Loader()) {
     zero_time_ = document_->Loader()->GetTiming().ReferenceMonotonicTime() +
                  origin_time_;
     zero_time_initialized_ = true;
diff --git a/third_party/blink/renderer/core/animation/document_timeline_test.cc b/third_party/blink/renderer/core/animation/document_timeline_test.cc
index 8efe98e..51b48b5b 100644
--- a/third_party/blink/renderer/core/animation/document_timeline_test.cc
+++ b/third_party/blink/renderer/core/animation/document_timeline_test.cc
@@ -150,6 +150,27 @@
   EXPECT_FALSE(is_null);
 }
 
+// EffectiveTime is identical to CurrentTimeInternal except that it returns 0
+// when the timeline is inactive.
+TEST_F(AnimationDocumentTimelineTest, EffectiveTime) {
+  GetAnimationClock().UpdateTime(base::TimeTicks() +
+                                 base::TimeDelta::FromSecondsD(200));
+  EXPECT_EQ(200, timeline->EffectiveTime());
+  EXPECT_EQ(200, timeline->CurrentTimeInternal());
+  bool is_null;
+  EXPECT_EQ(200, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+
+  Document* document_without_frame = Document::CreateForTest();
+  DocumentTimeline* inactive_timeline = DocumentTimeline::Create(
+      document_without_frame, TimeDelta(), platform_timing);
+
+  EXPECT_EQ(0, inactive_timeline->EffectiveTime());
+  is_null = false;
+  inactive_timeline->CurrentTimeInternal(is_null);
+  EXPECT_TRUE(is_null);
+}
+
 TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormal) {
   TimeTicks zero_time = timeline->ZeroTime();
   bool is_null;
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_end_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_end_custom.cc
index 2e22177..29fbe3c 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_end_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_end_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_start_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_start_custom.cc
index b8fdfd2..e6ba632 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_start_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_block_start_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_bottom_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_bottom_custom.cc
index 305a1d76..5583fdc 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_bottom_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_bottom_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginBottom::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_end_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_end_custom.cc
index e763ddec..bb8b823 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_end_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_end_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_start_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_start_custom.cc
index 91a0c008..0a2668c 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_start_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_inline_start_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_left_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_left_custom.cc
index 9a47a79..3622084 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_left_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_left_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginLeft::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_right_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_right_custom.cc
index 77bc7ab..2ce02b1 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_right_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_right_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginRight::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_top_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_top_custom.cc
index ac66acf..e6ce2a2 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_top_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_margin_top_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context.Mode(), kValueRangeAll,
-                       CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+                       CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginTop::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_end_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_end_custom.cc
index bbb2a9c..1f66c7e 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_end_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_end_custom.cc
@@ -18,7 +18,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_start_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_start_custom.cc
index 7cc55ee..3c93e00 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_start_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_block_start_custom.cc
@@ -18,7 +18,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_bottom_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_bottom_custom.cc
index 23eb030..862abd5 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_bottom_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_bottom_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollPaddingBottom::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_end_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_end_custom.cc
index 5e9f0e48..adaadd25 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_end_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_end_custom.cc
@@ -18,7 +18,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_start_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_start_custom.cc
index 7807578..7a98a9b 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_start_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_inline_start_custom.cc
@@ -18,7 +18,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 }  // namespace CSSLonghand
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_left_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_left_custom.cc
index 730472c3..ee232f2 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_left_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_left_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollPaddingLeft::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_right_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_right_custom.cc
index d4c0bd06..089a230 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_right_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_right_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollPaddingRight::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_top_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_top_custom.cc
index 5994a9e..80886a1 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_top_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_padding_top_custom.cc
@@ -17,7 +17,7 @@
     const CSSParserLocalContext&) const {
   return ConsumeLengthOrPercent(
       range, context.Mode(), kValueRangeNonNegative,
-      CSSPropertyParserHelpers::UnitlessQuirk::kAllow);
+      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollPaddingTop::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc
index 381ef1b..afc57ca 100644
--- a/third_party/blink/renderer/core/editing/editor.cc
+++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -896,7 +896,7 @@
 
   are_marked_text_matches_highlighted_ = flag;
   GetFrame().GetDocument()->Markers().RepaintMarkers(
-      DocumentMarker::kTextMatch);
+      DocumentMarker::MarkerTypes::TextMatch());
 }
 
 void Editor::RespondToChangedSelection() {
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder.cc b/third_party/blink/renderer/core/editing/finder/text_finder.cc
index 2655fbc2..152190f 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -343,7 +343,7 @@
 
   // Remove all markers for matches found and turn off the highlighting.
   OwnerFrame().GetFrame()->GetDocument()->Markers().RemoveMarkersOfTypes(
-      DocumentMarker::kTextMatch);
+      DocumentMarker::MarkerTypes::TextMatch());
   OwnerFrame().GetFrame()->GetEditor().SetMarkedTextMatchesAreHighlighted(
       false);
   ClearFindMatchesCache();
@@ -828,7 +828,7 @@
   if (frame && frame->GetPage() &&
       frame->GetEditor().MarkedTextMatchesAreHighlighted()) {
     frame->GetDocument()->Markers().RemoveMarkersOfTypes(
-        DocumentMarker::kTextMatch);
+        DocumentMarker::MarkerTypes::TextMatch());
   }
 }
 
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
index 484f9b7..f70a399 100644
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
@@ -396,7 +396,8 @@
     composition_range_->setStart(&GetDocument(), 0);
     composition_range_->collapse(true);
   }
-  GetDocument().Markers().RemoveMarkersOfTypes(DocumentMarker::kComposition);
+  GetDocument().Markers().RemoveMarkersOfTypes(
+      DocumentMarker::MarkerTypes::Composition());
 }
 
 void InputMethodController::ContextDestroyed(Document*) {
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
index 700b09a..8f2a7c34 100644
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
@@ -2410,13 +2410,15 @@
   Node* text2 = b->nextSibling();
 
   const DocumentMarkerVector& text1_markers =
-      GetDocument().Markers().MarkersFor(text1, DocumentMarker::kComposition);
+      GetDocument().Markers().MarkersFor(
+          text1, DocumentMarker::MarkerTypes::Composition());
   EXPECT_EQ(1u, text1_markers.size());
   EXPECT_EQ(0u, text1_markers[0]->StartOffset());
   EXPECT_EQ(1u, text1_markers[0]->EndOffset());
 
   const DocumentMarkerVector& text2_markers =
-      GetDocument().Markers().MarkersFor(text2, DocumentMarker::kComposition);
+      GetDocument().Markers().MarkersFor(
+          text2, DocumentMarker::MarkerTypes::Composition());
   EXPECT_EQ(1u, text2_markers.size());
   EXPECT_EQ(0u, text2_markers[0]->StartOffset());
   EXPECT_EQ(3u, text2_markers[0]->EndOffset());
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker.h b/third_party/blink/renderer/core/editing/markers/document_marker.h
index 8c2f971..245f777 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/document_marker.h
@@ -99,9 +99,27 @@
 
   class MarkerTypes {
    public:
-    // The constructor is intentionally implicit to allow conversion from the
-    // bit-wise sum of above types
-    MarkerTypes(unsigned mask) : mask_(mask) {}
+    explicit MarkerTypes(unsigned mask = 0) : mask_(mask) {}
+
+    static MarkerTypes All() {
+      return MarkerTypes((1 << kMarkerTypeIndexesCount) - 1);
+    }
+
+    static MarkerTypes AllBut(const MarkerTypes& types) {
+      return MarkerTypes(All().mask_ & ~types.mask_);
+    }
+
+    static MarkerTypes ActiveSuggestion() {
+      return MarkerTypes(kActiveSuggestion);
+    }
+    static MarkerTypes Composition() { return MarkerTypes(kComposition); }
+    static MarkerTypes Grammar() { return MarkerTypes(kGrammar); }
+    static MarkerTypes Misspelling() {
+      return MarkerTypes(kSpelling | kGrammar);
+    }
+    static MarkerTypes Spelling() { return MarkerTypes(kSpelling); }
+    static MarkerTypes TextMatch() { return MarkerTypes(kTextMatch); }
+    static MarkerTypes Suggestion() { return MarkerTypes(kSuggestion); }
 
     bool Contains(MarkerType type) const { return mask_ & type; }
     bool Intersects(const MarkerTypes& types) const {
@@ -111,8 +129,9 @@
       return mask_ == other.mask_;
     }
 
-    void Add(const MarkerTypes& types) { mask_ |= types.mask_; }
-    void Remove(const MarkerTypes& types) { mask_ &= ~types.mask_; }
+    MarkerTypes Add(const MarkerTypes& types) const {
+      return MarkerTypes(mask_ | types.mask_);
+    }
 
     MarkerTypesIterator begin() const { return MarkerTypesIterator(mask_); }
     MarkerTypesIterator end() const { return MarkerTypesIterator(0); }
@@ -121,16 +140,6 @@
     unsigned mask_;
   };
 
-  class AllMarkers : public MarkerTypes {
-   public:
-    AllMarkers() : MarkerTypes((1 << kMarkerTypeIndexesCount) - 1) {}
-  };
-
-  class MisspellingMarkers : public MarkerTypes {
-   public:
-    MisspellingMarkers() : MarkerTypes(kSpelling | kGrammar) {}
-  };
-
   virtual ~DocumentMarker();
 
   virtual MarkerType GetType() const = 0;
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
index dc0257d..2e0516e 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
@@ -128,6 +128,11 @@
   return (*marker_lists)[marker_list_index];
 }
 
+bool DocumentMarkerController::PossiblyHasMarkers(
+    DocumentMarker::MarkerType type) {
+  return PossiblyHasMarkers(DocumentMarker::MarkerTypes(type));
+}
+
 inline bool DocumentMarkerController::PossiblyHasMarkers(
     DocumentMarker::MarkerTypes types) {
   if (markers_.IsEmpty()) {
@@ -140,7 +145,7 @@
     // Alternatively, we could handle this case at the time the Node is GC'ed,
     // but that operation is more performance-sensitive than anywhere
     // PossiblyHasMarkers() is used.
-    possibly_existing_marker_types_ = 0;
+    possibly_existing_marker_types_ = DocumentMarker::MarkerTypes();
     SetContext(nullptr);
     return false;
   }
@@ -149,12 +154,11 @@
 }
 
 DocumentMarkerController::DocumentMarkerController(Document& document)
-    : possibly_existing_marker_types_(0), document_(&document) {
-}
+    : document_(&document) {}
 
 void DocumentMarkerController::Clear() {
   markers_.clear();
-  possibly_existing_marker_types_ = 0;
+  possibly_existing_marker_types_ = DocumentMarker::MarkerTypes();
   SetContext(nullptr);
 }
 
@@ -280,7 +284,8 @@
 
 void DocumentMarkerController::AddMarkerToNode(const Node& node,
                                                DocumentMarker* new_marker) {
-  possibly_existing_marker_types_.Add(new_marker->GetType());
+  possibly_existing_marker_types_ = possibly_existing_marker_types_.Add(
+      DocumentMarker::MarkerTypes(new_marker->GetType()));
   SetContext(document_);
 
   Member<MarkerLists>& markers =
@@ -308,7 +313,7 @@
   if (length <= 0)
     return;
 
-  if (!PossiblyHasMarkers(DocumentMarker::AllMarkers()))
+  if (!PossiblyHasMarkers(DocumentMarker::MarkerTypes::All()))
     return;
   DCHECK(!markers_.IsEmpty());
 
@@ -323,7 +328,7 @@
   MarkerLists* dst_markers = markers_.at(dst_node);
 
   bool doc_dirty = false;
-  for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) {
+  for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
     DocumentMarkerList* const src_list = ListForType(src_markers, type);
     if (!src_list)
       continue;
@@ -360,7 +365,7 @@
 
   bool doc_dirty = false;
   size_t empty_lists_count = 0;
-  for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) {
+  for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
     DocumentMarkerList* const list = ListForType(markers, type);
     if (!list || list->IsEmpty()) {
       if (list && list->IsEmpty())
@@ -383,7 +388,7 @@
   if (empty_lists_count == DocumentMarker::kMarkerTypeIndexesCount) {
     markers_.erase(&node);
     if (markers_.IsEmpty()) {
-      possibly_existing_marker_types_ = 0;
+      possibly_existing_marker_types_ = DocumentMarker::MarkerTypes();
       SetContext(nullptr);
     }
   }
@@ -509,7 +514,7 @@
   DocumentMarkerVector result;
   for (MarkerMap::iterator i = markers_.begin(); i != markers_.end(); ++i) {
     MarkerLists* markers = i->value.Get();
-    for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) {
+    for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
       DocumentMarkerList* const list = ListForType(markers, type);
       if (!list)
         continue;
@@ -531,18 +536,19 @@
   // Note: DocumentMarkerController::MarkersFor() returns markers sorted by
   // start offset.
   const DocumentMarkerVector& suggestion_markers =
-      MarkersFor(&node, DocumentMarker::kSuggestion);
+      MarkersFor(&node, DocumentMarker::MarkerTypes::Suggestion());
   if (suggestion_markers.IsEmpty()) {
     // If there are no suggestion markers, we can return early as a minor
     // performance optimization.
-    DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers();
-    remaining_types.Remove(DocumentMarker::kSuggestion);
-    return MarkersFor(&node, remaining_types);
+    return MarkersFor(
+        &node, DocumentMarker::MarkerTypes::AllBut(
+                   DocumentMarker::MarkerTypes(DocumentMarker::kSuggestion)));
   }
 
   const DocumentMarkerVector& markers_overridden_by_suggestion_markers =
       MarkersFor(&node,
-                 DocumentMarker::kComposition | DocumentMarker::kSpelling);
+                 DocumentMarker::MarkerTypes(DocumentMarker::kComposition |
+                                             DocumentMarker::kSpelling));
 
   Vector<unsigned> suggestion_starts;
   Vector<unsigned> suggestion_ends;
@@ -590,12 +596,10 @@
 
   markers_to_paint.AppendVector(suggestion_markers);
 
-  DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers();
-  remaining_types.Remove(DocumentMarker::kComposition |
-                         DocumentMarker::kSpelling |
-                         DocumentMarker::kSuggestion);
-
-  markers_to_paint.AppendVector(MarkersFor(&node, remaining_types));
+  markers_to_paint.AppendVector(MarkersFor(
+      &node, DocumentMarker::MarkerTypes::AllBut(DocumentMarker::MarkerTypes(
+                 DocumentMarker::kComposition | DocumentMarker::kSpelling |
+                 DocumentMarker::kSuggestion))));
 
   return markers_to_paint;
 }
@@ -684,7 +688,7 @@
       continue;
     MarkerLists* markers = node_markers.value;
     for (DocumentMarker::MarkerType type :
-         DocumentMarker::MisspellingMarkers()) {
+         DocumentMarker::MarkerTypes::Misspelling()) {
       DocumentMarkerList* const list = ListForType(markers, type);
       if (!list)
         continue;
@@ -721,8 +725,7 @@
       RemoveMarkersFromList(iterator, marker_types);
   }
 
-  possibly_existing_marker_types_.Remove(marker_types);
-  if (PossiblyHasMarkers(DocumentMarker::AllMarkers()))
+  if (PossiblyHasMarkers(DocumentMarker::MarkerTypes::AllBut(marker_types)))
     return;
   SetContext(nullptr);
 }
@@ -734,13 +737,13 @@
   bool node_can_be_removed;
 
   size_t empty_lists_count = 0;
-  if (marker_types == DocumentMarker::AllMarkers()) {
+  if (marker_types == DocumentMarker::MarkerTypes::All()) {
     needs_repainting = true;
     node_can_be_removed = true;
   } else {
     MarkerLists* markers = iterator->value.Get();
 
-    for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) {
+    for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
       DocumentMarkerList* const list = ListForType(markers, type);
       if (!list || list->IsEmpty()) {
         if (list && list->IsEmpty())
@@ -769,7 +772,7 @@
   if (node_can_be_removed) {
     markers_.erase(iterator);
     if (markers_.IsEmpty()) {
-      possibly_existing_marker_types_ = 0;
+      possibly_existing_marker_types_ = DocumentMarker::MarkerTypes();
       SetContext(nullptr);
     }
   }
@@ -788,7 +791,7 @@
 
     // inner loop: process each marker in the current node
     MarkerLists* markers = i->value.Get();
-    for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) {
+    for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
       DocumentMarkerList* const list = ListForType(markers, type);
       if (!list || list->IsEmpty() || !marker_types.Contains(type))
         continue;
@@ -858,7 +861,7 @@
     const Node* node = node_iterator->key;
     builder.Append(String::Format("%p", node));
     MarkerLists* markers = markers_.at(node);
-    for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) {
+    for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
       DocumentMarkerList* const list = ListForType(markers, type);
       if (!list)
         continue;
@@ -891,7 +894,7 @@
                                                       unsigned offset,
                                                       unsigned old_length,
                                                       unsigned new_length) {
-  if (!PossiblyHasMarkers(DocumentMarker::AllMarkers()))
+  if (!PossiblyHasMarkers(DocumentMarker::MarkerTypes::All()))
     return;
   DCHECK(!markers_.IsEmpty());
 
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
index 7f358621..3ce98e9 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
@@ -80,11 +80,11 @@
   void RemoveMarkersOfTypes(DocumentMarker::MarkerTypes);
   void RemoveMarkersForNode(
       const Node*,
-      DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
+      DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All());
   void RemoveSpellingMarkersUnderWords(const Vector<String>& words);
   void RemoveSuggestionMarkerByTag(const Node*, int32_t marker_tag);
   void RepaintMarkers(
-      DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
+      DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All());
   // Returns true if markers within a range are found.
   bool SetTextMatchMarkersActive(const EphemeralRange&, bool);
   // Returns true if markers within a range defined by a node, |startOffset| and
@@ -118,7 +118,7 @@
                            DocumentMarker::MarkerTypes);
   DocumentMarkerVector MarkersFor(
       const Node*,
-      DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
+      DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All());
   DocumentMarkerVector Markers();
   // TODO(yoichio): Make const by making PossiblyHasMarkers const.
   DocumentMarkerVector ComputeMarkersToPaint(const Node&);
@@ -153,6 +153,7 @@
   static Member<DocumentMarkerList>& ListForType(MarkerLists*,
                                                  DocumentMarker::MarkerType);
   bool PossiblyHasMarkers(DocumentMarker::MarkerTypes);
+  bool PossiblyHasMarkers(DocumentMarker::MarkerType);
   void RemoveMarkersFromList(MarkerMap::iterator, DocumentMarker::MarkerTypes);
   void RemoveMarkers(TextIterator&, DocumentMarker::MarkerTypes);
   void RemoveMarkersInternal(const Node&,
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
index 1fb2fcf6..a7e2c103 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
@@ -273,8 +273,8 @@
 
   // Remove markers that overlap "a"
   marker_range = EphemeralRange(Position(text, 0), Position(text, 1));
-  GetDocument().Markers().RemoveMarkersInRange(marker_range,
-                                               DocumentMarker::AllMarkers());
+  GetDocument().Markers().RemoveMarkersInRange(
+      marker_range, DocumentMarker::MarkerTypes::All());
 
   EXPECT_EQ(0u, MarkerController().Markers().size());
 }
@@ -292,8 +292,8 @@
 
   // Remove markers that overlap "b"
   marker_range = EphemeralRange(Position(text, 1), Position(text, 2));
-  GetDocument().Markers().RemoveMarkersInRange(marker_range,
-                                               DocumentMarker::AllMarkers());
+  GetDocument().Markers().RemoveMarkersInRange(
+      marker_range, DocumentMarker::MarkerTypes::All());
 
   EXPECT_EQ(0u, MarkerController().Markers().size());
 }
@@ -311,8 +311,8 @@
 
   // Remove markers that overlap "c"
   marker_range = EphemeralRange(Position(text, 2), Position(text, 3));
-  GetDocument().Markers().RemoveMarkersInRange(marker_range,
-                                               DocumentMarker::AllMarkers());
+  GetDocument().Markers().RemoveMarkersInRange(
+      marker_range, DocumentMarker::MarkerTypes::All());
 
   EXPECT_EQ(0u, MarkerController().Markers().size());
 }
@@ -385,7 +385,7 @@
   // Query for a spellcheck marker intersecting "3456"
   const DocumentMarker* const result =
       MarkerController().FirstMarkerIntersectingOffsetRange(
-          *text, 2, 6, DocumentMarker::MisspellingMarkers());
+          *text, 2, 6, DocumentMarker::MarkerTypes::Misspelling());
 
   EXPECT_EQ(DocumentMarker::kSpelling, result->GetType());
   EXPECT_EQ(0u, result->StartOffset());
@@ -406,7 +406,7 @@
   // Query for a spellcheck marker containing the position between "1" and "2"
   const DocumentMarker* const result =
       MarkerController().FirstMarkerIntersectingOffsetRange(
-          *text, 1, 1, DocumentMarker::MisspellingMarkers());
+          *text, 1, 1, DocumentMarker::MarkerTypes::Misspelling());
 
   EXPECT_EQ(DocumentMarker::kSpelling, result->GetType());
   EXPECT_EQ(0u, result->StartOffset());
@@ -435,7 +435,7 @@
       MarkerController().MarkersIntersectingRange(
           EphemeralRangeInFlatTree(PositionInFlatTree(text, 2),
                                    PositionInFlatTree(text, 6)),
-          DocumentMarker::MisspellingMarkers());
+          DocumentMarker::MarkerTypes::Misspelling());
 
   EXPECT_EQ(1u, results.size());
   EXPECT_EQ(DocumentMarker::kSpelling, results[0].second->GetType());
@@ -457,7 +457,7 @@
       MarkerController().MarkersIntersectingRange(
           EphemeralRangeInFlatTree(PositionInFlatTree(text, 1),
                                    PositionInFlatTree(text, 1)),
-          DocumentMarker::MisspellingMarkers());
+          DocumentMarker::MarkerTypes::Misspelling());
 
   EXPECT_EQ(1u, results.size());
   EXPECT_EQ(DocumentMarker::kSpelling, results[0].second->GetType());
@@ -496,7 +496,7 @@
       MarkerController().MarkersIntersectingRange(
           EphemeralRangeInFlatTree(PositionInFlatTree(not_shadow_text, 9),
                                    PositionInFlatTree(shadow1_text, 1)),
-          DocumentMarker::kTextMatch);
+          DocumentMarker::MarkerTypes::TextMatch());
   EXPECT_EQ(1u, results.size());
 }
 
diff --git a/third_party/blink/renderer/core/editing/selection_controller.cc b/third_party/blink/renderer/core/editing/selection_controller.cc
index 11e667a..0a2ec76 100644
--- a/third_party/blink/renderer/core/editing/selection_controller.cc
+++ b/third_party/blink/renderer/core/editing/selection_controller.cc
@@ -135,7 +135,8 @@
 
   const unsigned offset = position.ComputeOffsetInContainerNode();
   return document_marker_controller.FirstMarkerIntersectingOffsetRange(
-      *ToText(node), offset, offset, DocumentMarker::MisspellingMarkers());
+      *ToText(node), offset, offset,
+      DocumentMarker::MarkerTypes::Misspelling());
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc b/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc
index b9731680..0de20f16 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc
@@ -116,7 +116,7 @@
       CurrentWordIfTypingInPartialWord(*root_editable);
   if (current_word.IsNotNull()) {
     root_editable->GetDocument().Markers().RemoveMarkersInRange(
-        current_word, DocumentMarker::MisspellingMarkers());
+        current_word, DocumentMarker::MarkerTypes::Misspelling());
     return;
   }
 
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
index ddead93..426ff09 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
@@ -120,7 +120,7 @@
                     .Selection()
                     .ComputeVisibleSelectionInDOMTree()
                     .ToNormalizedEphemeralRange(),
-                DocumentMarker::kSpelling);
+                DocumentMarker::MarkerTypes::Spelling());
 }
 
 void SpellChecker::AdvanceToNextMisspelling(bool start_before_selection) {
@@ -322,7 +322,7 @@
   }
 
   // Clear the stale markers.
-  RemoveMarkers(checking_range, DocumentMarker::MisspellingMarkers());
+  RemoveMarkers(checking_range, DocumentMarker::MarkerTypes::Misspelling());
 
   if (!results.size())
     return;
@@ -415,12 +415,10 @@
   // needs to be audited.  See http://crbug.com/590369 for more details.
   GetFrame().GetDocument()->UpdateStyleAndLayoutTreeForNode(&element);
 
-  DocumentMarker::MarkerTypes marker_types(DocumentMarker::kSpelling);
-  marker_types.Add(DocumentMarker::kGrammar);
   for (Node& node : NodeTraversal::InclusiveDescendantsOf(element)) {
     if (elements_type == ElementsType::kAll || !HasEditableStyle(node)) {
-      GetFrame().GetDocument()->Markers().RemoveMarkersForNode(&node,
-                                                               marker_types);
+      GetFrame().GetDocument()->Markers().RemoveMarkersForNode(
+          &node, DocumentMarker::MarkerTypes::Misspelling());
     }
   }
 }
@@ -456,7 +454,7 @@
   DocumentMarker* const marker =
       GetFrame().GetDocument()->Markers().FirstMarkerIntersectingOffsetRange(
           ToText(*selection_start_container), selection_start_offset,
-          selection_end_offset, DocumentMarker::MisspellingMarkers());
+          selection_end_offset, DocumentMarker::MarkerTypes::Misspelling());
   if (!marker)
     return {};
 
@@ -547,7 +545,7 @@
 
 void SpellChecker::RemoveSpellingMarkers() {
   GetFrame().GetDocument()->Markers().RemoveMarkersOfTypes(
-      DocumentMarker::MisspellingMarkers());
+      DocumentMarker::MarkerTypes::Misspelling());
 }
 
 void SpellChecker::RemoveSpellingMarkersUnderWords(
diff --git a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
index e66b7394..66300a7 100644
--- a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
+++ b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
@@ -224,8 +224,10 @@
 
   const std::pair<const Node*, const DocumentMarker*>& node_and_marker =
       FirstMarkerIntersectingRange(
-          range_to_check, DocumentMarker::kSpelling | DocumentMarker::kGrammar |
-                              DocumentMarker::kSuggestion);
+          range_to_check,
+          DocumentMarker::MarkerTypes(DocumentMarker::kSpelling |
+                                      DocumentMarker::kGrammar |
+                                      DocumentMarker::kSuggestion));
   if (!node_and_marker.first)
     return;
 
@@ -255,7 +257,7 @@
   const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
       node_marker_pairs =
           GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
-              range_to_check, DocumentMarker::kActiveSuggestion);
+              range_to_check, DocumentMarker::MarkerTypes::ActiveSuggestion());
 
   if (node_marker_pairs.IsEmpty())
     return;
@@ -291,7 +293,7 @@
   const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
       node_marker_pairs =
           GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
-              range_to_check, DocumentMarker::kSuggestion);
+              range_to_check, DocumentMarker::MarkerTypes::Suggestion());
 
   const Node* marker_text_node = nullptr;
   SuggestionMarker* marker = nullptr;
@@ -356,7 +358,7 @@
     return;
 
   GetDocument().Markers().RemoveMarkersOfTypes(
-      DocumentMarker::kActiveSuggestion);
+      DocumentMarker::MarkerTypes::ActiveSuggestion());
   GetFrame().Selection().SetCaretVisible(true);
   is_suggestion_menu_open_ = false;
 }
@@ -381,7 +383,7 @@
   const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
       node_suggestion_marker_pairs =
           GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
-              range_to_check, DocumentMarker::kSuggestion);
+              range_to_check, DocumentMarker::MarkerTypes::Suggestion());
   if (!node_suggestion_marker_pairs.IsEmpty()) {
     ShowSuggestionMenu(node_suggestion_marker_pairs, max_number_of_suggestions);
     return;
@@ -391,7 +393,7 @@
   const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>
       node_spelling_marker_pairs =
           GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
-              range_to_check, DocumentMarker::MisspellingMarkers());
+              range_to_check, DocumentMarker::MarkerTypes::Misspelling());
   if (!node_spelling_marker_pairs.IsEmpty())
     ShowSpellCheckMenu(node_spelling_marker_pairs.front());
 
@@ -580,7 +582,8 @@
 
 void TextSuggestionController::AttemptToDeleteActiveSuggestionRange() {
   const std::pair<const Node*, const DocumentMarker*>& node_and_marker =
-      FirstMarkerTouchingSelection(DocumentMarker::kActiveSuggestion);
+      FirstMarkerTouchingSelection(
+          DocumentMarker::MarkerTypes::ActiveSuggestion());
   if (!node_and_marker.first)
     return;
 
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 7a664c1..e74dcd5 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -7012,7 +7012,7 @@
 
   EXPECT_EQ(1, textcheck.NumberOfTimesChecked());
   EXPECT_EQ(1, NumMarkersInRange(document, selection_range,
-                                 DocumentMarker::kSpelling));
+                                 DocumentMarker::MarkerTypes::Spelling()));
 
   frame->ReplaceMisspelledRange("welcome");
   EXPECT_EQ("_welcome_.", WebFrameContentDumper::DumpWebViewAsText(
@@ -7059,7 +7059,7 @@
                                        .ToNormalizedEphemeralRange();
 
   EXPECT_EQ(0, NumMarkersInRange(document, selection_range,
-                                 DocumentMarker::kSpelling));
+                                 DocumentMarker::MarkerTypes::Spelling()));
 }
 
 static void GetSpellingMarkerOffsets(WebVector<unsigned>* offsets,
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 2401b6f..c103e02 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1895,4 +1895,13 @@
   return list;
 }
 
+bool ContentSecurityPolicy::HasPolicyFromSource(
+    ContentSecurityPolicyHeaderSource source) const {
+  for (const auto& policy : policies_) {
+    if (policy->HeaderSource() == source)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index d97eb51..783a241 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -461,6 +461,8 @@
   // there is no execution context to enforce the sandbox flags.
   SandboxFlags GetSandboxMask() const { return sandbox_mask_; }
 
+  bool HasPolicyFromSource(ContentSecurityPolicyHeaderSource) const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ContentSecurityPolicyTest, NonceInline);
   FRIEND_TEST_ALL_PREFIXES(ContentSecurityPolicyTest, NonceSinglePolicy);
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
index ad5c35a..f5e347f 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
@@ -29,13 +29,24 @@
   String header = String::FromUTF8(data, size);
   unsigned hash = header.IsNull() ? 0 : header.Impl()->GetHash();
 
+  // Use the 'hash' value to pick header_type and header_source input.
+  // 1st bit: header type.
+  // 2nd bit: header source: HTTP (or other)
+  // 3rd bit: header source: Meta or OriginPolicy (if not HTTP)
+  ContentSecurityPolicyHeaderType header_type =
+      hash & 0x01 ? kContentSecurityPolicyHeaderTypeEnforce
+                  : kContentSecurityPolicyHeaderTypeReport;
+  ContentSecurityPolicyHeaderSource header_source =
+      kContentSecurityPolicyHeaderSourceHTTP;
+  if (hash & 0x02) {
+    header_source = (hash & 0x04)
+                        ? kContentSecurityPolicyHeaderSourceMeta
+                        : kContentSecurityPolicyHeaderSourceOriginPolicy;
+  }
+
   // Construct and initialize a policy from the string.
   ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
-  csp->DidReceiveHeader(header,
-                        hash & 0x01 ? kContentSecurityPolicyHeaderTypeEnforce
-                                    : kContentSecurityPolicyHeaderTypeReport,
-                        hash & 0x02 ? kContentSecurityPolicyHeaderSourceHTTP
-                                    : kContentSecurityPolicyHeaderSourceMeta);
+  csp->DidReceiveHeader(header, header_type, header_source);
   g_page_holder->GetDocument().InitContentSecurityPolicy(csp);
 
   // Force a garbage collection.
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 464a41e..3bb296c 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1446,7 +1446,7 @@
   DCHECK(!previews_resource_loading_hints_receiver_);
   previews_resource_loading_hints_receiver_ =
       std::make_unique<PreviewsResourceLoadingHintsReceiverImpl>(
-          std::move(request));
+          std::move(request), GetDocument());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index f0dc7b1..5f8b5e90 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -30,8 +30,11 @@
 
 namespace {
 
-// a small slack period between deadline and current time for safety
-constexpr TimeDelta kSlackBeforeDeadline = TimeDelta::FromMilliseconds(1);
+// small slack period between deadline and current time for safety
+constexpr TimeDelta kCreateBlobSlackBeforeDeadline =
+    TimeDelta::FromMilliseconds(1);
+constexpr TimeDelta kEncodeRowSlackBeforeDeadline =
+    TimeDelta::FromMicroseconds(100);
 
 /* The value is based on user statistics on Nov 2017. */
 #if (defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN))
@@ -53,8 +56,19 @@
 const double kIdleTaskCompleteTimeoutDelayMs = 9000.0;
 #endif
 
-bool IsDeadlineNearOrPassed(TimeTicks deadline) {
-  return CurrentTimeTicks() >= deadline - kSlackBeforeDeadline;
+bool IsCreateBlobDeadlineNearOrPassed(TimeTicks deadline) {
+  return CurrentTimeTicks() >= deadline - kCreateBlobSlackBeforeDeadline;
+}
+
+bool IsEncodeRowDeadlineNearOrPassed(TimeTicks deadline, size_t image_width) {
+  // Rough estimate of the row encoding time in micro seconds. We will consider
+  // a slack time later to not pass the idle task deadline.
+  int row_encode_time_us = 1000 * (kIdleTaskCompleteTimeoutDelayMs / 4000.0) *
+                           (image_width / 4000.0);
+  TimeDelta row_encode_time_delta =
+      TimeDelta::FromMicroseconds(row_encode_time_us);
+  return CurrentTimeTicks() >=
+         deadline - row_encode_time_delta - kEncodeRowSlackBeforeDeadline;
 }
 
 String ConvertMimeTypeEnumToString(ImageEncoder::MimeType mime_type_enum) {
@@ -184,6 +198,7 @@
     ExecutionContext* context,
     ScriptPromiseResolver* resolver)
     : fail_encoder_initialization_for_test_(false),
+      enforce_idle_encoding_for_test_(false),
       image_(image),
       context_(context),
       encode_options_(options),
@@ -328,7 +343,8 @@
   std::unique_ptr<ImageDataBuffer> buffer = ImageDataBuffer::Create(src_data_);
   if (!buffer)
     return false;
-  return buffer->EncodeImage("image/webp", quality, &encoded_image_);
+  return buffer->EncodeImage(ConvertMimeTypeEnumToString(mime_type_), quality,
+                             &encoded_image_);
 }
 
 void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) {
@@ -339,7 +355,17 @@
                              WrapPersistent(this)));
     return;
   }
-  if (mime_type_ == ImageEncoder::kMimeTypeWebp) {
+  // Webp encoder does not support progressive encoding. We also don't use idle
+  // encoding for layout tests, since the idle task start and completition
+  // deadlines (6.7s or 13s) bypass the layout test running deadline (6s)
+  // and result in timeouts on different tests. We use
+  // enforce_idle_encoding_for_test_ to test idle encoding in unit tests.
+  bool use_idle_encoding =
+      (mime_type_ != ImageEncoder::kMimeTypeWebp) &&
+      (enforce_idle_encoding_for_test_ ||
+       !RuntimeEnabledFeatures::NoIdleEncodingForLayoutTestsEnabled());
+
+  if (!use_idle_encoding) {
     if (!IsMainThread()) {
       DCHECK(function_type_ == kHTMLCanvasConvertToBlobPromise ||
              function_type_ == kOffscreenCanvasConvertToBlobPromise);
@@ -416,7 +442,7 @@
   }
 
   for (int y = num_rows_completed_; y < src_data_.height(); ++y) {
-    if (IsDeadlineNearOrPassed(deadline)) {
+    if (IsEncodeRowDeadlineNearOrPassed(deadline, src_data_.width())) {
       num_rows_completed_ = y;
       Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask(
           FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::IdleEncodeRows,
@@ -436,7 +462,7 @@
   TimeDelta elapsed_time =
       WTF::CurrentTimeTicks() - schedule_idle_task_start_time_;
   RecordElapsedTimeHistogram(kCompleteEncodingDelay, mime_type_, elapsed_time);
-  if (IsDeadlineNearOrPassed(deadline)) {
+  if (IsCreateBlobDeadlineNearOrPassed(deadline)) {
     context_->GetTaskRunner(TaskType::kCanvasBlobSerialization)
         ->PostTask(FROM_HERE,
                    WTF::Bind(&CanvasAsyncBlobCreator::CreateBlobAndReturnResult,
@@ -514,8 +540,6 @@
 
 void CanvasAsyncBlobCreator::EncodeImageOnEncoderThread(double quality) {
   DCHECK(!IsMainThread());
-  DCHECK(mime_type_ == ImageEncoder::kMimeTypeWebp);
-
   if (!EncodeImage(quality)) {
     PostCrossThreadTask(
         *parent_frame_task_runner_, FROM_HERE,
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
index 3b2875d..4e7f119 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
@@ -110,6 +110,7 @@
  protected:
   IdleTaskStatus idle_task_status_;
   bool fail_encoder_initialization_for_test_;
+  bool enforce_idle_encoding_for_test_;
 
  private:
   friend class CanvasAsyncBlobCreatorTest;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
index e3b5269..13d6a52 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -35,6 +35,7 @@
             nullptr) {
     if (fail_encoder_initialization)
       fail_encoder_initialization_for_test_ = true;
+    enforce_idle_encoding_for_test_ = true;
   }
 
   CanvasAsyncBlobCreator::IdleTaskStatus GetIdleTaskStatus() {
@@ -177,7 +178,7 @@
   EXPECT_CALL(*(AsyncBlobCreator()),
               SignalTaskSwitchInStartTimeoutEventForTesting());
 
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
+  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
   test::EnterRunLoop();
 
   testing::Mock::VerifyAndClearExpectations(AsyncBlobCreator());
@@ -195,7 +196,7 @@
   EXPECT_CALL(*(AsyncBlobCreator()),
               SignalTaskSwitchInCompleteTimeoutEventForTesting());
 
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
+  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
   test::EnterRunLoop();
 
   testing::Mock::VerifyAndClearExpectations(AsyncBlobCreator());
@@ -209,7 +210,7 @@
   // the idle task status.
   PrepareMockCanvasAsyncBlobCreatorFail();
 
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
+  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
   test::EnterRunLoop();
 
   EXPECT_EQ(IdleTaskStatus::kIdleTaskFailed,
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 8596b77e5..71b6440 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -420,14 +420,15 @@
         GetOrCreateCanvasResourceProvider(kPreferAcceleration)) {
       // Push a frame
       base::TimeTicks start_time = WTF::CurrentTimeTicks();
-      scoped_refptr<StaticBitmapImage> image =
-          canvas2d_bridge_->NewImageSnapshot(kPreferAcceleration);
+      scoped_refptr<CanvasResource> canvas_resource =
+          ResourceProvider()->ProduceFrame();
       FloatRect src_rect(0, 0, Size().Width(), Size().Height());
       dirty_rect_.Intersect(src_rect);
       IntRect int_dirty = EnclosingIntRect(dirty_rect_);
       SkIRect damage_rect = SkIRect::MakeXYWH(
           int_dirty.X(), int_dirty.Y(), int_dirty.Width(), int_dirty.Height());
-      frame_dispatcher_->DispatchFrameSync(image, start_time, damage_rect);
+      frame_dispatcher_->DispatchFrameSync(std::move(canvas_resource),
+                                           start_time, damage_rect);
       (void)start_time;
       (void)damage_rect;
       dirty_rect_ = FloatRect();
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index 6350c26..6f1a7628 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
+#include "third_party/blink/renderer/core/loader/navigation_policy.h"
 #include "third_party/blink/renderer/core/loader/ping_loader.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
@@ -366,8 +367,10 @@
               : WebFeature::
                     kHTMLAnchorElementDownloadInSandboxWithoutUserGesture);
     }
-    if (GetDocument().GetSecurityOrigin()->CanReadContent(completed_url)) {
-      // TODO(jochen): Handle cross origin server redirects.
+    // Ignore the download attribute if we either can't read the content, or
+    // the event is an alt-click or similar.
+    if (NavigationPolicyFromEvent(event) != kNavigationPolicyDownload &&
+        GetDocument().GetSecurityOrigin()->CanReadContent(completed_url)) {
       request.SetSuggestedFilename(
           static_cast<String>(FastGetAttribute(downloadAttr)));
       request.SetRequestContext(WebURLRequest::kRequestContextDownload);
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
index 0da6c561..15f1d79 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
@@ -361,8 +361,7 @@
   int index = dom_nodes_->length();
   dom_nodes_->addItem(std::move(owned_value));
 
-  int layoutNodeIndex =
-      VisitLayoutTreeNode(node->GetLayoutObject(), node, index);
+  int layoutNodeIndex = VisitLayoutTreeNode(node, index);
   if (layoutNodeIndex != -1)
     value->setLayoutNodeIndex(layoutNodeIndex);
 
@@ -431,12 +430,10 @@
       if (InspectorDOMAgent::GetPseudoElementType(element->GetPseudoId(),
                                                   &pseudo_type)) {
         value->setPseudoType(pseudo_type);
-        VisitPseudoLayoutChildren(node, node->GetLayoutObject(), index);
       }
     } else {
-      value->setPseudoElementIndexes(
-          VisitPseudoElements(element, index, include_event_listeners,
-                              include_user_agent_shadow_tree));
+      value->setPseudoElementIndexes(VisitPseudoElements(
+          element, include_event_listeners, include_user_agent_shadow_tree));
     }
 
     HTMLImageElement* image_element = ToHTMLImageElementOrNull(node);
@@ -589,7 +586,7 @@
   nodes->getNodeValue(nullptr)->addItem(AddString(node_value));
   nodes->getBackendNodeId(nullptr)->addItem(backend_node_id);
   nodes->getAttributes(nullptr)->addItem(BuildArrayForElementAttributes2(node));
-  BuildLayoutTreeNode(node->GetLayoutObject(), node, index);
+  BuildLayoutTreeNode(node, index);
 
   if (origin_url_map_ && origin_url_map_->Contains(backend_node_id)) {
     String origin_url = origin_url_map_->at(backend_node_id);
@@ -639,7 +636,6 @@
       if (InspectorDOMAgent::GetPseudoElementType(element->GetPseudoId(),
                                                   &pseudo_type)) {
         SetRare(nodes->getPseudoType(nullptr), index, pseudo_type);
-        VisitPseudoLayoutChildren2(node, node->GetLayoutObject(), index);
       }
     } else {
       VisitPseudoElements2(element, index);
@@ -726,66 +722,45 @@
   }
 }
 
-void InspectorDOMSnapshotAgent::VisitPseudoLayoutChildren(
-    Node* pseudo_node,
-    LayoutObject* layout_object,
-    int index) {
-  for (LayoutObject* child = layout_object->SlowFirstChild(); child;
-       child = child->NextSibling()) {
-    VisitLayoutTreeNode(child, pseudo_node, index);
-  }
-}
-
-void InspectorDOMSnapshotAgent::VisitPseudoLayoutChildren2(
-    Node* pseudo_node,
-    LayoutObject* layout_object,
-    int index) {
-  for (LayoutObject* child = layout_object->SlowFirstChild(); child;
-       child = child->NextSibling()) {
-    BuildLayoutTreeNode(child, pseudo_node, index);
-  }
-}
-
 std::unique_ptr<protocol::Array<int>>
 InspectorDOMSnapshotAgent::VisitPseudoElements(
     Element* parent,
-    int index,
     bool include_event_listeners,
     bool include_user_agent_shadow_tree) {
-  if (!parent->GetPseudoElement(kPseudoIdFirstLetter) &&
-      !parent->GetPseudoElement(kPseudoIdBefore) &&
+  if (!parent->GetPseudoElement(kPseudoIdBefore) &&
       !parent->GetPseudoElement(kPseudoIdAfter)) {
     return nullptr;
   }
 
   auto pseudo_elements = protocol::Array<int>::create();
-  PseudoId pseudo_types[] = {kPseudoIdFirstLetter, kPseudoIdBefore,
-                             kPseudoIdAfter};
-  for (PseudoId pseudo_id : pseudo_types) {
-    if (parent->GetPseudoElement(pseudo_id)) {
-      Node* pseudo_node = parent->GetPseudoElement(pseudo_id);
-      pseudo_elements->addItem(VisitNode(pseudo_node, include_event_listeners,
-                                         include_user_agent_shadow_tree));
-    }
+
+  if (parent->GetPseudoElement(kPseudoIdBefore)) {
+    pseudo_elements->addItem(
+        VisitNode(parent->GetPseudoElement(kPseudoIdBefore),
+                  include_event_listeners, include_user_agent_shadow_tree));
   }
+  if (parent->GetPseudoElement(kPseudoIdAfter)) {
+    pseudo_elements->addItem(VisitNode(parent->GetPseudoElement(kPseudoIdAfter),
+                                       include_event_listeners,
+                                       include_user_agent_shadow_tree));
+  }
+
   return pseudo_elements;
 }
 
 void InspectorDOMSnapshotAgent::VisitPseudoElements2(Element* parent,
                                                      int parent_index) {
-  if (!parent->GetPseudoElement(kPseudoIdFirstLetter) &&
-      !parent->GetPseudoElement(kPseudoIdBefore) &&
+  if (!parent->GetPseudoElement(kPseudoIdBefore) &&
       !parent->GetPseudoElement(kPseudoIdAfter)) {
     return;
   }
-  PseudoId pseudo_types[] = {kPseudoIdFirstLetter, kPseudoIdBefore,
-                             kPseudoIdAfter};
-  for (PseudoId i : pseudo_types) {
-    if (parent->GetPseudoElement(i)) {
-      Node* pseudo_node = parent->GetPseudoElement(i);
-      VisitNode2(pseudo_node, parent_index);
-    }
-  }
+
+  auto pseudo_elements = protocol::Array<int>::create();
+
+  if (parent->GetPseudoElement(kPseudoIdBefore))
+    VisitNode2(parent->GetPseudoElement(kPseudoIdBefore), parent_index);
+  if (parent->GetPseudoElement(kPseudoIdAfter))
+    VisitNode2(parent->GetPseudoElement(kPseudoIdAfter), parent_index);
 }
 
 std::unique_ptr<protocol::Array<protocol::DOMSnapshot::NameValue>>
@@ -817,9 +792,8 @@
   return result;
 }
 
-int InspectorDOMSnapshotAgent::VisitLayoutTreeNode(LayoutObject* layout_object,
-                                                   Node* node,
-                                                   int node_index) {
+int InspectorDOMSnapshotAgent::VisitLayoutTreeNode(Node* node, int node_index) {
+  LayoutObject* layout_object = node->GetLayoutObject();
   if (!layout_object)
     return -1;
 
@@ -872,9 +846,8 @@
   return index;
 }
 
-int InspectorDOMSnapshotAgent::BuildLayoutTreeNode(LayoutObject* layout_object,
-                                                   Node* node,
-                                                   int node_index) {
+int InspectorDOMSnapshotAgent::BuildLayoutTreeNode(Node* node, int node_index) {
+  LayoutObject* layout_object = node->GetLayoutObject();
   if (!layout_object)
     return -1;
   auto* layout_tree_snapshot = document_->getLayout();
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h
index b65e206b..322420f1 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h
@@ -93,18 +93,8 @@
       bool include_event_listeners,
       bool include_user_agent_shadow_tree);
   void VisitContainerChildren2(Node* container, int parent_index);
-
-  // Collect LayoutTreeNodes owned by a pseudo element.
-  void VisitPseudoLayoutChildren(Node* pseudo_node,
-                                 LayoutObject* layout_object,
-                                 int index);
-  void VisitPseudoLayoutChildren2(Node* pseudo_node,
-                                  LayoutObject* layout_object,
-                                  int index);
-
   std::unique_ptr<protocol::Array<int>> VisitPseudoElements(
       Element* parent,
-      int index,
       bool include_event_listeners,
       bool include_user_agent_shadow_tree);
   void VisitPseudoElements2(Element* parent, int parent_index);
@@ -112,11 +102,11 @@
   BuildArrayForElementAttributes(Element*);
   std::unique_ptr<protocol::Array<int>> BuildArrayForElementAttributes2(Node*);
 
-  // Adds a LayoutTreeNode for the LayoutObject to |layout_tree_nodes_| and
-  // returns its index. Returns -1 if the Node has no associated LayoutObject.
-  // Associates LayoutObjects under a pseudo element with the element.
-  int VisitLayoutTreeNode(LayoutObject*, Node*, int node_index);
-  int BuildLayoutTreeNode(LayoutObject*, Node*, int node_index);
+  // Adds a LayoutTreeNode for the LayoutObject of the given Node to
+  // |layout_tree_nodes_| and returns its index. Returns -1 if the Node has no
+  // associated LayoutObject.
+  int VisitLayoutTreeNode(Node*, int node_index);
+  int BuildLayoutTreeNode(Node*, int node_index);
 
   // Returns the index of the ComputedStyle in |computed_styles_| for the given
   // Node. Adds a new ComputedStyle if necessary, but ensures no duplicates are
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index bb8a4d45..a2ff463 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -480,6 +480,18 @@
     if (!MapDOMOffsetToTextContentOffset(*mapping, &start, &end))
       return;
 
+    // We don't want to add collapsed (i.e., start == end) quads from text
+    // fragments that intersect [start, end] only at the boundary, unless they
+    // are the only quads found. For example, when we have
+    // - text fragments: ABC  DEF  GHI
+    // - text offsets:   012  345  678
+    // and input range [3, 6], since fragment "DEF" gives non-collapsed quad,
+    // we no longer add quads from "ABC" and "GHI" since they are collapsed.
+    // TODO(layout-dev): This heuristic doesn't cover all cases, as we return
+    // 2 collapsed quads (instead of 1) for range [3, 3] in the above example.
+    bool found_non_collapsed_quad = false;
+    Vector<FloatQuad, 1> collapsed_quads_candidates;
+
     // Find fragments that have text for the specified range.
     DCHECK_LE(start, end);
     auto fragments = NGPaintFragment::InlineFragmentsFor(this);
@@ -489,12 +501,22 @@
       if (start > text_fragment.EndOffset() ||
           end < text_fragment.StartOffset())
         continue;
+      const unsigned clamped_start =
+          std::max(start, text_fragment.StartOffset());
+      const unsigned clamped_end = std::min(end, text_fragment.EndOffset());
       NGPhysicalOffsetRect rect =
-          text_fragment.LocalRect(std::max(start, text_fragment.StartOffset()),
-                                  std::min(end, text_fragment.EndOffset()));
+          text_fragment.LocalRect(clamped_start, clamped_end);
       rect.offset += fragment->InlineOffsetToContainerBox();
-      quads.push_back(LocalToAbsoluteQuad(rect.ToFloatRect()));
+      const FloatQuad quad = LocalToAbsoluteQuad(rect.ToFloatRect());
+      if (clamped_start < clamped_end) {
+        quads.push_back(quad);
+        found_non_collapsed_quad = true;
+      } else {
+        collapsed_quads_candidates.push_back(quad);
+      }
     }
+    if (!found_non_collapsed_quad)
+      quads.AppendVector(collapsed_quads_candidates);
     return;
   }
 
diff --git a/third_party/blink/renderer/core/loader/BUILD.gn b/third_party/blink/renderer/core/loader/BUILD.gn
index 49b4ead..f5b9aab 100644
--- a/third_party/blink/renderer/core/loader/BUILD.gn
+++ b/third_party/blink/renderer/core/loader/BUILD.gn
@@ -81,6 +81,8 @@
     "ping_loader.h",
     "prerenderer_client.cc",
     "prerenderer_client.h",
+    "previews_resource_loading_hints.cc",
+    "previews_resource_loading_hints.h",
     "previews_resource_loading_hints_receiver_impl.cc",
     "previews_resource_loading_hints_receiver_impl.h",
     "private/frame_client_hints_preferences_context.cc",
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index f9d0ff8..c0fbdaf5 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
 #include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
 #include "third_party/blink/renderer/core/loader/subresource_filter.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
@@ -412,6 +413,14 @@
       return ResourceRequestBlockedReason::kOther;
   }
 
+  // Loading of a subresource may be blocked by previews resource loading hints.
+  if (GetPreviewsResourceLoadingHints() &&
+      !GetPreviewsResourceLoadingHints()->AllowLoad(url)) {
+    // TODO (tbansal): https://crbug.com/864253. Add a specific reason for why
+    // the resource fetch was blocked.
+    return ResourceRequestBlockedReason::kOther;
+  }
+
   // Let the client have the final say into whether or not the load should
   // proceed.
   if (GetSubresourceFilter() && type != Resource::kMainResource &&
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.h b/third_party/blink/renderer/core/loader/base_fetch_context.h
index 3bb6b18..6edc1fa2a 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.h
@@ -21,6 +21,7 @@
 
 class ConsoleMessage;
 class KURL;
+class PreviewsResourceLoadingHints;
 class SecurityOrigin;
 class SubresourceFilter;
 class WebSocketHandshakeThrottle;
@@ -52,6 +53,8 @@
       const = 0;
   virtual KURL GetSiteForCookies() const = 0;
   virtual SubresourceFilter* GetSubresourceFilter() const = 0;
+  virtual PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
+      const = 0;
   virtual void CountUsage(WebFeature) const = 0;
   virtual void CountDeprecation(WebFeature) const = 0;
   virtual bool ShouldBlockWebSocketByMixedContentCheck(const KURL&) const = 0;
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context_test.cc b/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
index e6937a74..4ae640c 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
@@ -56,6 +56,10 @@
   KURL GetSiteForCookies() const override { return KURL(); }
   bool AllowScriptFromSource(const KURL&) const override { return false; }
   SubresourceFilter* GetSubresourceFilter() const override { return nullptr; }
+  PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
+      const override {
+    return nullptr;
+  }
   bool ShouldBlockRequestByInspector(const KURL&) const override {
     return false;
   }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 0b35e877..175e3ca 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -31,6 +31,7 @@
 
 #include <memory>
 #include "base/auto_reset.h"
+#include "third_party/blink/public/common/origin_policy/origin_policy.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_url_request.h"
@@ -97,6 +98,7 @@
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -174,6 +176,7 @@
   visitor->Trace(history_item_);
   visitor->Trace(parser_);
   visitor->Trace(subresource_filter_);
+  visitor->Trace(resource_loading_hints_);
   visitor->Trace(document_load_timing_);
   visitor->Trace(application_cache_host_);
   visitor->Trace(content_security_policy_);
@@ -608,6 +611,23 @@
   if (!frame_->GetSettings()->BypassCSP()) {
     content_security_policy_->DidReceiveHeaders(
         ContentSecurityPolicyResponseHeaders(response));
+
+    // Handle OriginPolicy. We can skip the entire block if the OP policies have
+    // already been passed down.
+    if (!content_security_policy_->HasPolicyFromSource(
+            kContentSecurityPolicyHeaderSourceOriginPolicy)) {
+      std::unique_ptr<OriginPolicy> origin_policy = OriginPolicy::From(
+          StringUTF8Adaptor(request_.GetOriginPolicy()).AsStringPiece());
+      if (origin_policy) {
+        for (auto csp : origin_policy->GetContentSecurityPolicies()) {
+          content_security_policy_->DidReceiveHeader(
+              WTF::String::FromUTF8(csp.policy.data(), csp.policy.length()),
+              csp.report_only ? kContentSecurityPolicyHeaderTypeReport
+                              : kContentSecurityPolicyHeaderTypeEnforce,
+              kContentSecurityPolicyHeaderSourceOriginPolicy);
+        }
+      }
+    }
   }
   if (!content_security_policy_->AllowAncestors(frame_, response.Url())) {
     CancelLoadAfterCSPDenied(response);
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index ae6d876..124b730 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -48,6 +48,7 @@
 #include "third_party/blink/renderer/core/loader/frame_loader_types.h"
 #include "third_party/blink/renderer/core/loader/link_loader.h"
 #include "third_party/blink/renderer/core/loader/navigation_policy.h"
+#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
 #include "third_party/blink/renderer/core/page/viewport_description.h"
 #include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
 #include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
@@ -122,6 +123,13 @@
   SubresourceFilter* GetSubresourceFilter() const {
     return subresource_filter_.Get();
   }
+  void SetPreviewsResourceLoadingHints(
+      PreviewsResourceLoadingHints* resource_loading_hints) {
+    resource_loading_hints_ = resource_loading_hints;
+  }
+  PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints() const {
+    return resource_loading_hints_;
+  }
 
   const SubstituteData& GetSubstituteData() const { return substitute_data_; }
 
@@ -364,6 +372,9 @@
 
   Member<SubresourceFilter> subresource_filter_;
 
+  // Stores the resource loading hints for this document.
+  Member<PreviewsResourceLoadingHints> resource_loading_hints_;
+
   // A reference to actual request used to create the data source.
   // The only part of this request that should change is the url, and
   // that only in the case of a same-document navigation.
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 68b361c..8dd92139 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -372,6 +372,16 @@
   return document_loader ? document_loader->GetSubresourceFilter() : nullptr;
 }
 
+PreviewsResourceLoadingHints*
+FrameFetchContext::GetPreviewsResourceLoadingHints() const {
+  if (IsDetached())
+    return nullptr;
+  DocumentLoader* document_loader = MasterDocumentLoader();
+  if (!document_loader)
+    return nullptr;
+  return document_loader->GetPreviewsResourceLoadingHints();
+}
+
 LocalFrame* FrameFetchContext::GetFrame() const {
   DCHECK(!IsDetached());
 
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h
index 0da9752..0eab67f6 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -213,6 +213,8 @@
       const override;
   KURL GetSiteForCookies() const override;
   SubresourceFilter* GetSubresourceFilter() const override;
+  PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
+      const override;
   bool AllowScriptFromSource(const KURL&) const override;
   bool ShouldBlockRequestByInspector(const KURL&) const override;
   void DispatchDidBlockRequest(const ResourceRequest&,
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index d08c4076..f1679c9 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -809,7 +809,7 @@
   if (!target_frame && !request.FrameName().IsEmpty()) {
     if (policy == kNavigationPolicyDownload) {
       Client()->DownloadURL(request.GetResourceRequest(),
-                            DownloadCrossOriginRedirects::kNavigate);
+                            DownloadCrossOriginRedirects::kFollow);
       return;  // Navigation/download will be handled by the client.
     } else if (should_navigate_target_frame) {
       request.GetResourceRequest().SetFrameType(
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc
new file mode 100644
index 0000000..ffd2457
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+// static
+PreviewsResourceLoadingHints* PreviewsResourceLoadingHints::Create(
+    ExecutionContext& execution_context,
+    const std::vector<WTF::String>& subresource_patterns_to_block) {
+  return new PreviewsResourceLoadingHints(&execution_context,
+                                          subresource_patterns_to_block);
+}
+
+PreviewsResourceLoadingHints::PreviewsResourceLoadingHints(
+    ExecutionContext* execution_context,
+    const std::vector<WTF::String>& subresource_patterns_to_block)
+    : execution_context_(execution_context),
+      subresource_patterns_to_block_(subresource_patterns_to_block) {}
+
+PreviewsResourceLoadingHints::~PreviewsResourceLoadingHints() = default;
+
+bool PreviewsResourceLoadingHints::AllowLoad(const KURL& resource_url) const {
+  if (!resource_url.ProtocolIsInHTTPFamily())
+    return true;
+
+  WTF::String resource_url_string = resource_url.GetString();
+  resource_url_string = resource_url_string.Left(resource_url.PathEnd());
+
+  for (const WTF::String& subresource_pattern :
+       subresource_patterns_to_block_) {
+    // TODO(tbansal): https://crbug.com/856247. Add support for wildcard
+    // matching.
+    if (resource_url_string.Find(subresource_pattern) != kNotFound)
+      return false;
+  }
+
+  return true;
+}
+
+void PreviewsResourceLoadingHints::Trace(blink::Visitor* visitor) {
+  visitor->Trace(execution_context_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h
new file mode 100644
index 0000000..e4370b6
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_H_
+
+#include <vector>
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class ExecutionContext;
+class KURL;
+
+// PreviewsResourceLoadingHints stores the resource loading hints that apply to
+// a single document.
+class CORE_EXPORT PreviewsResourceLoadingHints final
+    : public GarbageCollectedFinalized<PreviewsResourceLoadingHints> {
+ public:
+  static PreviewsResourceLoadingHints* Create(
+      ExecutionContext& execution_context,
+      const std::vector<WTF::String>& subresource_patterns_to_block);
+
+  ~PreviewsResourceLoadingHints();
+
+  // Returns true if load of |resource_url| is allowed as per resource loading
+  // hints.
+  bool AllowLoad(const KURL& resource_url) const;
+
+  virtual void Trace(blink::Visitor*);
+
+ private:
+  PreviewsResourceLoadingHints(
+      ExecutionContext* execution_context,
+      const std::vector<WTF::String>& subresource_patterns_to_block);
+
+  Member<ExecutionContext> execution_context_;
+
+  // |subresource_patterns_to_block_| is a collection of subresource patterns
+  // for resources whose loading should be blocked. Each pattern is a
+  // WTF::String. If a subresource URL contains any of the strings specified in
+  // |subresource_patterns_to_block_|, then that subresource's loading could
+  // be blocked.
+  const std::vector<WTF::String> subresource_patterns_to_block_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_H_
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc
index 6a1a5e4..615b19b9 100644
--- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc
+++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc
@@ -4,14 +4,20 @@
 
 #include "third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h"
 
+#include <vector>
+
 #include "base/metrics/histogram_macros.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
 PreviewsResourceLoadingHintsReceiverImpl::
     PreviewsResourceLoadingHintsReceiverImpl(
-        mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request)
-    : binding_(this, std::move(request)) {}
+        mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request,
+        Document* document)
+    : binding_(this, std::move(request)), document_(document) {}
 
 PreviewsResourceLoadingHintsReceiverImpl::
     ~PreviewsResourceLoadingHintsReceiverImpl() {}
@@ -23,6 +29,16 @@
   UMA_HISTOGRAM_COUNTS_100(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns",
       resource_loading_hints->subresources_to_block.size());
+
+  std::vector<WTF::String> subresource_patterns_to_block;
+  for (const auto& subresource :
+       resource_loading_hints->subresources_to_block) {
+    subresource_patterns_to_block.push_back(subresource);
+  }
+
+  document_->Loader()->SetPreviewsResourceLoadingHints(
+      PreviewsResourceLoadingHints::Create(*(document_.Get()),
+                                           subresource_patterns_to_block));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h
index d4a8daf0..ffd2e068 100644
--- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h
+++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h
@@ -7,6 +7,8 @@
 
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 
 namespace blink {
 
@@ -16,8 +18,9 @@
 class PreviewsResourceLoadingHintsReceiverImpl
     : public mojom::blink::PreviewsResourceLoadingHintsReceiver {
  public:
-  explicit PreviewsResourceLoadingHintsReceiverImpl(
-      mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request);
+  PreviewsResourceLoadingHintsReceiverImpl(
+      mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request,
+      Document* document);
   ~PreviewsResourceLoadingHintsReceiverImpl() override;
 
  private:
@@ -27,6 +30,8 @@
   // TODO(tbansal): https://crbug.com/800641. Consider using a RevocableBinding.
   mojo::Binding<mojom::blink::PreviewsResourceLoadingHintsReceiver> binding_;
 
+  WeakPersistent<Document> document_;
+
   DISALLOW_COPY_AND_ASSIGN(PreviewsResourceLoadingHintsReceiverImpl);
 };
 
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc
new file mode 100644
index 0000000..0be13dd
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc
@@ -0,0 +1,102 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
+
+#include <memory>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/loader/frame_loader.h"
+#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/geometry/int_size.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+namespace {
+
+class PreviewsResourceLoadingHintsTest : public PageTestBase {
+ public:
+  PreviewsResourceLoadingHintsTest() {
+    dummy_page_holder_ = DummyPageHolder::Create(IntSize(1, 1));
+  }
+
+ protected:
+  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+};
+
+TEST_F(PreviewsResourceLoadingHintsTest, NoPatterns) {
+  std::vector<WTF::String> subresources_to_block;
+
+  PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
+      dummy_page_holder_->GetDocument(), subresources_to_block);
+  EXPECT_TRUE(hints->AllowLoad(KURL("https://www.example.com/")));
+}
+
+TEST_F(PreviewsResourceLoadingHintsTest, OnePattern) {
+  std::vector<WTF::String> subresources_to_block;
+  subresources_to_block.push_back("foo.jpg");
+
+  PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
+      dummy_page_holder_->GetDocument(), subresources_to_block);
+
+  const struct {
+    KURL url;
+    bool allow_load_expected;
+  } tests[] = {
+      {KURL("https://www.example.com/"), true},
+      {KURL("https://www.example.com/foo.js"), true},
+      {KURL("https://www.example.com/foo.jpg"), false},
+      {KURL("https://www.example.com/pages/foo.jpg"), false},
+      {KURL("https://www.example.com/foobar.jpg"), true},
+      {KURL("https://www.example.com/barfoo.jpg"), false},
+      {KURL("http://www.example.com/foo.jpg"), false},
+      {KURL("http://www.example.com/foo.jpg?q=alpha"), false},
+      {KURL("http://www.example.com/bar.jpg?q=foo.jpg"), true},
+      {KURL("http://www.example.com/bar.jpg?q=foo.jpg#foo.jpg"), true},
+  };
+
+  for (const auto& test : tests)
+    EXPECT_EQ(test.allow_load_expected, hints->AllowLoad(test.url));
+}
+
+TEST_F(PreviewsResourceLoadingHintsTest, MultiplePatterns) {
+  std::vector<WTF::String> subresources_to_block;
+  subresources_to_block.push_back(".example1.com/foo.jpg");
+  subresources_to_block.push_back(".example1.com/bar.jpg");
+  subresources_to_block.push_back(".example2.com/baz.jpg");
+
+  PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
+      dummy_page_holder_->GetDocument(), subresources_to_block);
+
+  const struct {
+    KURL url;
+    bool allow_load_expected;
+  } tests[] = {
+      {KURL("https://www.example1.com/"), true},
+      {KURL("https://www.example1.com/foo.js"), true},
+      {KURL("https://www.example1.com/foo.jpg"), false},
+      {KURL("https://www.example1.com/pages/foo.jpg"), true},
+      {KURL("https://www.example1.com/foobar.jpg"), true},
+      {KURL("https://www.example1.com/barfoo.jpg"), true},
+      {KURL("http://www.example1.com/foo.jpg"), false},
+      {KURL("http://www.example1.com/bar.jpg"), false},
+      {KURL("http://www.example2.com/baz.jpg"), false},
+      {KURL("http://www.example2.com/pages/baz.jpg"), true},
+      {KURL("http://www.example2.com/baz.html"), true},
+  };
+
+  for (const auto& test : tests)
+    EXPECT_EQ(test.allow_load_expected, hints->AllowLoad(test.url));
+}
+
+}  // namespace
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index ca6d24b4..869e43e 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -120,6 +120,11 @@
   return subresource_filter_.Get();
 }
 
+PreviewsResourceLoadingHints*
+WorkerFetchContext::GetPreviewsResourceLoadingHints() const {
+  return nullptr;
+}
+
 bool WorkerFetchContext::AllowScriptFromSource(const KURL& url) const {
   WorkerContentSettingsClient* settings_client =
       WorkerContentSettingsClient::From(*global_scope_);
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.h b/third_party/blink/renderer/core/loader/worker_fetch_context.h
index eebe6884..9fc1970 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.h
@@ -41,6 +41,8 @@
       const override;
   KURL GetSiteForCookies() const override;
   SubresourceFilter* GetSubresourceFilter() const override;
+  PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
+      const override;
   bool AllowScriptFromSource(const KURL&) const override;
   bool ShouldBlockRequestByInspector(const KURL&) const override;
   void DispatchDidBlockRequest(const ResourceRequest&,
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index bb38c588..004f9ff4 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -51,7 +51,8 @@
   base::TimeTicks commit_start_time = WTF::CurrentTimeTicks();
   current_frame_damage_rect_.join(damage_rect);
   GetOrCreateResourceDispatcher()->DispatchFrameSync(
-      canvas_resource->Bitmap(), commit_start_time, current_frame_damage_rect_);
+      std::move(canvas_resource), commit_start_time,
+      current_frame_damage_rect_);
   current_frame_damage_rect_ = SkIRect::MakeEmpty();
 }
 
@@ -390,8 +391,9 @@
   if (current_frame_damage_rect_.isEmpty())
     return;
   base::TimeTicks commit_start_time = WTF::CurrentTimeTicks();
-  GetOrCreateResourceDispatcher()->DispatchFrame(
-      canvas_resource->Bitmap(), commit_start_time, current_frame_damage_rect_);
+  GetOrCreateResourceDispatcher()->DispatchFrame(std::move(canvas_resource),
+                                                 commit_start_time,
+                                                 current_frame_damage_rect_);
   current_frame_damage_rect_ = SkIRect::MakeEmpty();
 }
 
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 37cab28..c5b8d5e 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -225,7 +225,7 @@
 static base::Optional<DocumentMarker::MarkerTypes> MarkerTypesFrom(
     const String& marker_type) {
   if (marker_type.IsEmpty() || DeprecatedEqualIgnoringCase(marker_type, "all"))
-    return DocumentMarker::AllMarkers();
+    return DocumentMarker::MarkerTypes::All();
   base::Optional<DocumentMarker::MarkerType> type = MarkerTypeFrom(marker_type);
   if (!type)
     return base::nullopt;
@@ -950,9 +950,8 @@
   DCHECK(node);
 
   // Only TextMatch markers can be active.
-  DocumentMarker::MarkerType marker_type = DocumentMarker::kTextMatch;
-  DocumentMarkerVector markers =
-      node->GetDocument().Markers().MarkersFor(node, marker_type);
+  DocumentMarkerVector markers = node->GetDocument().Markers().MarkersFor(
+      node, DocumentMarker::MarkerTypes::TextMatch());
 
   unsigned active_marker_count = 0;
   for (const auto& marker : markers) {
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index ab90e4e..c5efe86 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -603,6 +603,7 @@
           "peerconnection/rtc_rtp_header_extension_capability.idl",
           "peerconnection/rtc_rtp_header_extension_parameters.idl",
           "peerconnection/rtc_rtp_parameters.idl",
+          "peerconnection/rtc_rtp_transceiver_init.idl",
           "peerconnection/rtc_rtp_send_parameters.idl",
           "peerconnection/rtc_session_description_init.idl",
           "peerconnection/rtc_track_event_init.idl",
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 6de5e60..1506e6e 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -57,6 +57,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
+#include "third_party/blink/renderer/bindings/modules/v8/media_stream_track_or_string.h"
 #include "third_party/blink/renderer/bindings/modules/v8/rtc_ice_candidate_init_or_rtc_ice_candidate.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_certificate.h"
@@ -91,6 +92,7 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_init.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_session_description.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_init.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_request_impl.h"
@@ -120,6 +122,11 @@
     "The RTCPeerConnection's signalingState is 'closed'.";
 const char kModifiedSdpMessage[] =
     "The SDP does not match the previously generated SDP for this type";
+const char kOnlySupportedInUnifiedPlanMessage[] =
+    "This operation is only supported in 'unified-plan'. 'unified-plan' will "
+    "become the default behavior in the future, but it is currently "
+    "experimental. To try it out, construct the RTCPeerConnection with "
+    "sdpSemantics:'unified-plan' present in the RTCConfiguration argument.";
 
 // The maximum number of PeerConnections that can exist simultaneously.
 const long kMaxPeerConnections = 500;
@@ -1494,6 +1501,50 @@
   return rtp_receivers_;
 }
 
+RTCRtpTransceiver* RTCPeerConnection::addTransceiver(
+    const MediaStreamTrackOrString& track_or_kind,
+    const RTCRtpTransceiverInit& init,
+    ExceptionState& exception_state) {
+  if (sdp_semantics_ != WebRTCSdpSemantics::kUnifiedPlan) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+                                      kOnlySupportedInUnifiedPlanMessage);
+    return nullptr;
+  }
+  if (ThrowExceptionIfSignalingStateClosed(signaling_state_, exception_state))
+    return nullptr;
+  auto webrtc_init = ToRtpTransceiverInit(init);
+  webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>> result =
+      webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
+  if (track_or_kind.IsMediaStreamTrack()) {
+    MediaStreamTrack* track = track_or_kind.GetAsMediaStreamTrack();
+    RegisterTrack(track);
+    result = peer_handler_->AddTransceiverWithTrack(track->Component(),
+                                                    std::move(webrtc_init));
+  } else {
+    const String& kind_string = track_or_kind.GetAsString();
+    // TODO(hbos): Make cricket::MediaType an allowed identifier in
+    // rtc_peer_connection.cc and use that instead of a boolean.
+    std::string kind;
+    if (kind_string == "audio") {
+      kind = webrtc::MediaStreamTrackInterface::kAudioKind;
+    } else if (kind_string == "video") {
+      kind = webrtc::MediaStreamTrackInterface::kVideoKind;
+    } else {
+      exception_state.ThrowTypeError(
+          "The argument provided as parameter 1 is not a valid "
+          "MediaStreamTrack kind ('audio' or 'video').");
+      return nullptr;
+    }
+    result = peer_handler_->AddTransceiverWithKind(std::move(kind),
+                                                   std::move(webrtc_init));
+  }
+  if (!result.ok()) {
+    ThrowExceptionFromRTCError(result.error(), exception_state);
+    return nullptr;
+  }
+  return CreateOrUpdateTransceiver(result.MoveValue());
+}
+
 RTCRtpSender* RTCPeerConnection::addTrack(MediaStreamTrack* track,
                                           MediaStreamVector streams,
                                           ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
index 4cb1f0f..0c170bb7 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -53,6 +53,7 @@
 
 class ExceptionState;
 class MediaStreamTrack;
+class MediaStreamTrackOrString;
 class RTCAnswerOptions;
 class RTCConfiguration;
 class RTCDTMFSender;
@@ -63,6 +64,7 @@
 class RTCPeerConnectionTest;
 class RTCRtpReceiver;
 class RTCRtpSender;
+class RTCRtpTransceiverInit;
 class RTCSessionDescription;
 class RTCSessionDescriptionInit;
 class ScriptState;
@@ -178,6 +180,9 @@
   const HeapVector<Member<RTCRtpTransceiver>>& getTransceivers() const;
   const HeapVector<Member<RTCRtpSender>>& getSenders() const;
   const HeapVector<Member<RTCRtpReceiver>>& getReceivers() const;
+  RTCRtpTransceiver* addTransceiver(const MediaStreamTrackOrString&,
+                                    const RTCRtpTransceiverInit&,
+                                    ExceptionState&);
   RTCRtpSender* addTrack(MediaStreamTrack*, MediaStreamVector, ExceptionState&);
   void removeTrack(RTCRtpSender*, ExceptionState&);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(track);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
index 39ac5949..761b827d 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
@@ -138,6 +138,9 @@
     [Measure] sequence<RTCRtpSender> getSenders();
     // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-getreceivers
     [Measure] sequence<RTCRtpReceiver> getReceivers();
+    // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver
+    [RaisesException] RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) track_or_kind,
+                                                       optional RTCRtpTransceiverInit init);
     // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtrack
     [Measure, RaisesException] RTCRtpSender addTrack(MediaStreamTrack track, MediaStream... streams);
     // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-removetrack
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
index b8ebccb7..74d6428 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
@@ -223,14 +223,7 @@
     encodings.reserve(parameters.encodings().size());
 
     for (const auto& encoding : parameters.encodings()) {
-      // TODO(orphis): Forward missing fields from the WebRTC library:
-      // codecPayloadType, dtx, ptime, maxFramerate, scaleResolutionDownBy,
-      // rid
-      encodings.push_back({});
-      encodings.back().active = encoding.active();
-      encodings.back().bitrate_priority = PriorityToDouble(encoding.priority());
-      if (encoding.hasMaxBitrate())
-        encodings.back().max_bitrate_bps = clampTo<int>(encoding.maxBitrate());
+      encodings.push_back(ToRtpEncodingParameters(encoding));
     }
   }
 
@@ -241,6 +234,19 @@
 
 }  // namespace
 
+webrtc::RtpEncodingParameters ToRtpEncodingParameters(
+    const RTCRtpEncodingParameters& encoding) {
+  // TODO(orphis): Forward missing fields from the WebRTC library:
+  // codecPayloadType, dtx, ptime, maxFramerate, scaleResolutionDownBy,
+  // rid
+  webrtc::RtpEncodingParameters webrtc_encoding;
+  webrtc_encoding.active = encoding.active();
+  webrtc_encoding.bitrate_priority = PriorityToDouble(encoding.priority());
+  if (encoding.hasMaxBitrate())
+    webrtc_encoding.max_bitrate_bps = clampTo<int>(encoding.maxBitrate());
+  return webrtc_encoding;
+}
+
 RTCRtpSender::RTCRtpSender(RTCPeerConnection* pc,
                            std::unique_ptr<WebRTCRtpSender> sender,
                            String kind,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
index 6b39859..6803a213 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
@@ -8,12 +8,14 @@
 #include "third_party/blink/public/platform/web_rtc_rtp_sender.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_encoding_parameters.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_send_parameters.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/webrtc/api/rtptransceiverinterface.h"
 
 namespace blink {
 
@@ -22,6 +24,9 @@
 class RTCPeerConnection;
 class RTCRtpCapabilities;
 
+webrtc::RtpEncodingParameters ToRtpEncodingParameters(
+    const RTCRtpEncodingParameters&);
+
 // https://w3c.github.io/webrtc-pc/#rtcrtpsender-interface
 class RTCRtpSender final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
index 44f52f7d..789a24c 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
@@ -65,6 +65,26 @@
 
 }  // namespace
 
+webrtc::RtpTransceiverInit ToRtpTransceiverInit(
+    const RTCRtpTransceiverInit& init) {
+  webrtc::RtpTransceiverInit webrtc_init;
+  base::Optional<webrtc::RtpTransceiverDirection> direction;
+  if (init.hasDirection() &&
+      TransceiverDirectionFromString(init.direction(), &direction) &&
+      direction) {
+    webrtc_init.direction = *direction;
+  }
+  DCHECK(init.hasStreams());
+  for (const auto& stream : init.streams()) {
+    webrtc_init.stream_ids.push_back(stream->id().Utf8().data());
+  }
+  DCHECK(init.hasSendEncodings());
+  // TODO(orphis,hbos): Pass the encodings down to the lower layer using
+  // ToRtpEncodingParameters() once implemented in third_party/webrtc.
+  // https://crbug.com/803494
+  return webrtc_init;
+}
+
 RTCRtpTransceiver::RTCRtpTransceiver(
     RTCPeerConnection* pc,
     std::unique_ptr<WebRTCRtpTransceiver> web_transceiver,
@@ -140,6 +160,7 @@
   receiver_->track()->Component()->Source()->SetReadyState(
       MediaStreamSource::kReadyStateMuted);
   stopped_ = true;
+  current_direction_ = String();  // null
 }
 
 WebRTCRtpTransceiver* RTCRtpTransceiver::web_transceiver() const {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
index d321baf..c123616 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
@@ -7,6 +7,7 @@
 
 #include "base/optional.h"
 #include "third_party/blink/public/platform/web_rtc_rtp_transceiver.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_init.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -21,6 +22,8 @@
 class RTCRtpReceiver;
 class RTCRtpSender;
 
+webrtc::RtpTransceiverInit ToRtpTransceiverInit(const RTCRtpTransceiverInit&);
+
 class RTCRtpTransceiver final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_init.idl b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_init.idl
new file mode 100644
index 0000000..6c7b886b
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_init.idl
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit
+dictionary RTCRtpTransceiverInit {
+    // RTCRtpTransceiverDirection is defined in rtc_rtp_transceiver.idl.
+    RTCRtpTransceiverDirection direction = "sendrecv";
+    sequence<MediaStream> streams = [];
+    sequence<RTCRtpEncodingParameters> sendEncodings = [];
+};
diff --git a/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl b/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl
index 555bbcc..9985ad45 100644
--- a/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl
+++ b/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl
@@ -5,7 +5,7 @@
 // https://wicg.github.io/webusb/#enumeration
 
 [
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers),
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers),
     ImplementedAs=WorkerNavigatorUSB,
     SecureContext
 ] partial interface WorkerNavigator {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
index 829faff..70f352861 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -127,14 +127,9 @@
 }
 
 void CanvasResourceDispatcher::DispatchFrameSync(
-    scoped_refptr<StaticBitmapImage> image,
+    scoped_refptr<CanvasResource> canvas_resource,
     base::TimeTicks commit_start_time,
     const SkIRect& damage_rect) {
-  scoped_refptr<CanvasResource> canvas_resource = CanvasResourceBitmap::Create(
-      std::move(image),
-      nullptr,  // Resource provider not specified -> recycling will not work
-      kLow_SkFilterQuality, CanvasColorParams());
-
   viz::CompositorFrame frame;
   if (!PrepareFrame(std::move(canvas_resource), commit_start_time, damage_rect,
                     &frame))
@@ -149,14 +144,9 @@
 }
 
 void CanvasResourceDispatcher::DispatchFrame(
-    scoped_refptr<StaticBitmapImage> image,
+    scoped_refptr<CanvasResource> canvas_resource,
     base::TimeTicks commit_start_time,
     const SkIRect& damage_rect) {
-  scoped_refptr<CanvasResource> canvas_resource = CanvasResourceBitmap::Create(
-      std::move(image),
-      nullptr,  // Resource provider not specified -> recycling will not work
-      kLow_SkFilterQuality, CanvasColorParams());
-
   viz::CompositorFrame frame;
   if (!PrepareFrame(std::move(canvas_resource), commit_start_time, damage_rect,
                     &frame))
@@ -229,38 +219,24 @@
     if (SharedGpuContext::IsGpuCompositingEnabled()) {
       // Case 1: both canvas and compositor are gpu accelerated.
       commit_type = kCommitGPUCanvasGPUCompositing;
-      offscreen_canvas_resource_provider_
-          ->SetTransferableResourceToStaticBitmapImage(&resource,
-                                                       canvas_resource);
       yflipped = true;
     } else {
       // Case 2: canvas is accelerated but gpu compositing is disabled.
       commit_type = kCommitGPUCanvasSoftwareCompositing;
-      offscreen_canvas_resource_provider_
-          ->SetTransferableResourceToSharedBitmap(resource,
-                                                  canvas_resource->Bitmap());
     }
   } else {
     if (SharedGpuContext::IsGpuCompositingEnabled()) {
       // Case 3: canvas is not gpu-accelerated, but compositor is.
       commit_type = kCommitSoftwareCanvasGPUCompositing;
-      scoped_refptr<CanvasResource> accelerated_resource =
-          canvas_resource->MakeAccelerated(
-              SharedGpuContext::ContextProviderWrapper());
-      if (!accelerated_resource)
-        return false;
-      offscreen_canvas_resource_provider_
-          ->SetTransferableResourceToStaticBitmapImage(&resource,
-                                                       accelerated_resource);
     } else {
       // Case 4: both canvas and compositor are not gpu accelerated.
       commit_type = kCommitSoftwareCanvasSoftwareCompositing;
-      offscreen_canvas_resource_provider_
-          ->SetTransferableResourceToSharedBitmap(resource,
-                                                  canvas_resource->Bitmap());
     }
   }
 
+  offscreen_canvas_resource_provider_->SetTransferableResource(&resource,
+                                                               canvas_resource);
+
   commit_type_histogram.Count(commit_type);
 
   PostImageToPlaceholderIfNotBlocked(
@@ -477,12 +453,14 @@
 void CanvasResourceDispatcher::DidAllocateSharedBitmap(
     mojo::ScopedSharedBufferHandle buffer,
     ::gpu::mojom::blink::MailboxPtr id) {
-  sink_->DidAllocateSharedBitmap(std::move(buffer), std::move(id));
+  if (sink_)
+    sink_->DidAllocateSharedBitmap(std::move(buffer), std::move(id));
 }
 
 void CanvasResourceDispatcher::DidDeleteSharedBitmap(
     ::gpu::mojom::blink::MailboxPtr id) {
-  sink_->DidDeleteSharedBitmap(std::move(id));
+  if (sink_)
+    sink_->DidDeleteSharedBitmap(std::move(id));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
index d2afb6a..0de60f33 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
@@ -47,11 +47,11 @@
   void SetSuspendAnimation(bool);
   bool NeedsBeginFrame() const { return needs_begin_frame_; }
   bool IsAnimationSuspended() const { return suspend_animation_; }
-  void DispatchFrame(scoped_refptr<StaticBitmapImage>,
+  void DispatchFrame(scoped_refptr<CanvasResource>,
                      base::TimeTicks commit_start_time,
                      const SkIRect& damage_rect);
   void ReclaimResource(viz::ResourceId);
-  void DispatchFrameSync(scoped_refptr<StaticBitmapImage>,
+  void DispatchFrameSync(scoped_refptr<CanvasResource>,
                          base::TimeTicks commit_start_time,
                          const SkIRect& damage_rect);
 
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher_test.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher_test.cc
index 86812fc..eea63df 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher_test.cc
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher_test.cc
@@ -10,6 +10,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
 using testing::_;
@@ -48,6 +49,13 @@
  protected:
   CanvasResourceDispatcherTest() {
     dispatcher_ = std::make_unique<MockCanvasResourceDispatcher>();
+    resource_provider_ = CanvasResourceProvider::Create(
+        IntSize(10, 10),
+        CanvasResourceProvider::kSoftwareCompositedResourceUsage,
+        nullptr,  // context_provider_wrapper
+        0,        // msaa_sample_count
+        CanvasColorParams(), CanvasResourceProvider::kDefaultPresentationMode,
+        dispatcher_->GetWeakPtr());
   }
 
   MockCanvasResourceDispatcher* Dispatcher() { return dispatcher_.get(); }
@@ -55,13 +63,12 @@
  private:
   scoped_refptr<StaticBitmapImage> PrepareStaticBitmapImage();
   std::unique_ptr<MockCanvasResourceDispatcher> dispatcher_;
+  std::unique_ptr<CanvasResourceProvider> resource_provider_;
 };
 
 void CanvasResourceDispatcherTest::DispatchOneFrame() {
-  sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(10, 10);
-  dispatcher_->DispatchFrame(
-      StaticBitmapImage::Create(surface->makeImageSnapshot()),
-      base::TimeTicks(), SkIRect::MakeEmpty());
+  dispatcher_->DispatchFrame(resource_provider_->ProduceFrame(),
+                             base::TimeTicks(), SkIRect::MakeEmpty());
 }
 
 TEST_F(CanvasResourceDispatcherTest, PlaceholderRunsNormally) {
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc
index a99595fb..6ad642b 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc
@@ -4,28 +4,9 @@
 
 #include "third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.h"
 
-#include "base/memory/shared_memory.h"
-#include "base/numerics/checked_math.h"
-#include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/shared_bitmap.h"
 #include "components/viz/common/resources/single_release_callback.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/common/capabilities.h"
-#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
-#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h"
-#include "third_party/blink/renderer/platform/wtf/typed_arrays/uint8_array.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkImage.h"
-#include "third_party/skia/include/core/SkSwizzle.h"
-#include "third_party/skia/include/gpu/GrContext.h"
 
 namespace blink {
 
@@ -46,68 +27,9 @@
   return std::make_unique<FrameResource>();
 }
 
-void OffscreenCanvasResourceProvider::SetTransferableResourceToSharedBitmap(
-    viz::TransferableResource& resource,
-    scoped_refptr<StaticBitmapImage> image) {
-  std::unique_ptr<FrameResource> frame_resource =
-      CreateOrRecycleFrameResource();
-  if (!frame_resource->shared_memory) {
-    frame_resource->provider = this;
-    frame_resource->shared_bitmap_id = viz::SharedBitmap::GenerateId();
-    frame_resource->shared_memory =
-        viz::bitmap_allocation::AllocateMappedBitmap(gfx::Size(width_, height_),
-                                                     resource.format);
-    frame_dispatcher_->DidAllocateSharedBitmap(
-        viz::bitmap_allocation::DuplicateAndCloseMappedBitmap(
-            frame_resource->shared_memory.get(), gfx::Size(width_, height_),
-            resource.format),
-        SharedBitmapIdToGpuMailboxPtr(frame_resource->shared_bitmap_id));
-  }
-  void* pixels = frame_resource->shared_memory->memory();
-  DCHECK(pixels);
-  // When |image| is texture backed, this function does a GPU readback which is
-  // required.
-  sk_sp<SkImage> sk_image = image->PaintImageForCurrentFrame().GetSkImage();
-  if (sk_image->bounds().isEmpty())
-    return;
-  SkImageInfo image_info = SkImageInfo::Make(
-      width_, height_, kN32_SkColorType,
-      image->IsPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType,
-      sk_image->refColorSpace());
-  if (image_info.isEmpty())
-    return;
-
-  if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
-    image_info = image_info.makeColorType(sk_image->colorType());
-  }
-
-  // TODO(junov): Optimize to avoid copying pixels for non-texture-backed
-  // sk_image. See crbug.com/651456.
-  bool read_pixels_successful =
-      sk_image->readPixels(image_info, pixels, image_info.minRowBytes(), 0, 0);
-  DCHECK(read_pixels_successful);
-  if (!read_pixels_successful)
-    return;
-  resource.mailbox_holder.mailbox = frame_resource->shared_bitmap_id;
-  resource.mailbox_holder.texture_target = 0;
-  resource.is_software = true;
-  resource.id = next_resource_id_;
-  resource.format = viz::ResourceFormat::RGBA_8888;
-  resource.size = gfx::Size(width_, height_);
-  // This indicates the filtering on the resource inherently, not the desired
-  // filtering effect on the quad.
-  resource.filter = GL_NEAREST;
-  // TODO(crbug.com/646022): making this overlay-able.
-  resource.is_overlay_candidate = false;
-
-  resources_.insert(next_resource_id_, std::move(frame_resource));
-}
-
-void OffscreenCanvasResourceProvider::
-    SetTransferableResourceToStaticBitmapImage(
-        viz::TransferableResource* out_resource,
-        scoped_refptr<CanvasResource> image) {
-  DCHECK(image->IsAccelerated());
+void OffscreenCanvasResourceProvider::SetTransferableResource(
+    viz::TransferableResource* out_resource,
+    scoped_refptr<CanvasResource> image) {
   DCHECK(image->IsValid());
 
   std::unique_ptr<FrameResource> frame_resource =
@@ -166,10 +88,6 @@
 OffscreenCanvasResourceProvider::FrameResource::~FrameResource() {
   if (release_callback)
     release_callback->Run(sync_token, is_lost);
-  if (provider && !shared_bitmap_id.IsZero()) {
-    provider->frame_dispatcher_->DidDeleteSharedBitmap(
-        SharedBitmapIdToGpuMailboxPtr(shared_bitmap_id));
-  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.h
index a1615b3..6ef51de 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.h
@@ -9,10 +9,6 @@
 #include "components/viz/common/resources/transferable_resource.h"
 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 
-namespace base {
-class SharedMemory;
-}
-
 namespace viz {
 class SingleReleaseCallback;
 namespace mojom {
@@ -38,11 +34,8 @@
 
   ~OffscreenCanvasResourceProvider();
 
-  void SetTransferableResourceToSharedBitmap(viz::TransferableResource&,
-                                             scoped_refptr<StaticBitmapImage>);
-  void SetTransferableResourceToStaticBitmapImage(
-      viz::TransferableResource* out_resource,
-      scoped_refptr<CanvasResource>);
+  void SetTransferableResource(viz::TransferableResource* out_resource,
+                               scoped_refptr<CanvasResource>);
 
   void ReclaimResource(unsigned resource_id);
   void ReclaimResources(const WTF::Vector<viz::ReturnedResource>& resources);
@@ -63,12 +56,6 @@
     // TODO(junov):  What does this do?
     bool spare_lock = true;
 
-    // Holds the backing for a software-backed resource.
-    std::unique_ptr<base::SharedMemory> shared_memory;
-    // The id given to  the display compositor to display a software-backed
-    // resource.
-    viz::SharedBitmapId shared_bitmap_id;
-
     // Back-pointer to the OffscreenCanvasResourceProvider. FrameResource does
     // not outlive the provider.
     OffscreenCanvasResourceProvider* provider = nullptr;
diff --git a/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc b/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
index 50b795f..2107d3c 100644
--- a/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
+++ b/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
@@ -66,4 +66,7 @@
                    kContentSecurityPolicyHeaderSourceHTTP);
 STATIC_ASSERT_ENUM(kWebContentSecurityPolicySourceMeta,
                    kContentSecurityPolicyHeaderSourceMeta);
+STATIC_ASSERT_ENUM(kWebContentSecurityPolicySourceOriginPolicy,
+                   kContentSecurityPolicyHeaderSourceOriginPolicy);
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/network/content_security_policy_parsers.h b/third_party/blink/renderer/platform/network/content_security_policy_parsers.h
index 0fb0dc5..e352fa9 100644
--- a/third_party/blink/renderer/platform/network/content_security_policy_parsers.h
+++ b/third_party/blink/renderer/platform/network/content_security_policy_parsers.h
@@ -20,7 +20,8 @@
 
 enum ContentSecurityPolicyHeaderSource {
   kContentSecurityPolicyHeaderSourceHTTP,
-  kContentSecurityPolicyHeaderSourceMeta
+  kContentSecurityPolicyHeaderSourceMeta,
+  kContentSecurityPolicyHeaderSourceOriginPolicy
 };
 
 enum ContentSecurityPolicyHashAlgorithm {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 933a133..c3d68ec 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -622,7 +622,7 @@
     },
     {
       name: "InterventionReporting",
-      status: "experimental",
+      status: "stable",
     },
     {
       // Tracks "jank" from layout objects changing their visual location
@@ -840,6 +840,10 @@
       name: "NewRemotePlaybackPipeline",
     },
     {
+      name: "NoIdleEncodingForLayoutTests",
+      status: "test",
+    },
+    {
       name: "NotificationConstructor",
       status: "stable",
     },
@@ -1383,7 +1387,7 @@
     },
     {
       name: "WebUSBOnDedicatedWorkers",
-      status: "experimental",
+      status: "stable",
       depends_on: ["WebUSB"],
     },
     {
diff --git a/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto b/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
index 59f2538..d39f2bb8 100644
--- a/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
+++ b/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
@@ -7,8 +7,9 @@
 message SequenceManagerTestDescription {
   // NEXT ID = 2
 
+  // This should be consistent with TaskQueue::QueuePriority.
   enum QueuePriority {
-    // NEXT ID = 6
+    // NEXT ID = 7
 
     UNDEFINED = 0;
     BEST_EFFORT = 1;
@@ -16,30 +17,35 @@
     NORMAL = 3;
     HIGH = 4;
     HIGHEST = 5;
+    CONTROL = 6;
   }
 
-  // Describes interfaces that can be tested by the fuzzer.
-  // TODO(farahcharab) Add more interfaces here.
   message Action {
-    // NEXT ID = 4
+    // NEXT ID = 9
 
     optional uint64 action_id = 1;
 
     oneof action {
       CreateTaskQueueAction create_task_queue = 2;
       PostDelayedTaskAction post_delayed_task = 3;
+      SetQueuePriorityAction set_queue_priority = 4;
+      SetQueueEnabledAction set_queue_enabled = 5;
+      ShutdownTaskQueueAction shutdown_task_queue = 6;
+      CancelTaskAction cancel_task = 7;
+      CreateQueueVoterAction create_queue_voter = 8;
     }
   }
 
   message Task {
     // NEXT ID = 4
 
+    // Only needed for testing the fuzzer processor.
     optional uint64 task_id = 1;
 
     optional uint64 duration_ms = 2;
 
     // If not set, then this is a no-op task.
-    repeated Action action = 3;
+    repeated Action actions = 3;
   }
 
   // Describes the grammar of SequenceManager::CreateTaskQueue.
@@ -53,15 +59,67 @@
   message PostDelayedTaskAction {
     // NEXT ID = 4
 
-    // Used to identify the queue to post to.
+    // Used to identify the |task_queue_id|'s oldest available queue to post a
+    // task to (modulo the number of available queues).
     optional uint64 task_queue_id = 1;
 
     optional Task task = 2;
 
-    // Delay parameter passed to TaskQueue::PostDelayedTask i.e. the delay is
-    // measured after executing the PostDelayedTaskAction.
+    // Delay parameter passed to TaskQueue::PostDelayedTask.
     optional uint64 delay_ms = 3;
   }
 
+  // Describes the grammar of TaskQueue::SetQueuePriority.
+  message SetQueuePriorityAction {
+    // NEXT ID = 3
+
+    // Used to identify the |task_queue_id|'s oldest available queue (modulo the
+    // number of available queues).
+    optional uint64 task_queue_id = 1;
+
+    optional QueuePriority priority = 2;
+  }
+
+  // Describes the grammar of TaskQueue::CreateQueueEnabledVoter.
+  message CreateQueueVoterAction {
+    // NEXT_ID = 2
+
+    // Used to identify the |task_queue_id|'s oldest available queue to
+    // create a voter for (modulo the number of available queues).
+    optional uint64 task_queue_id = 1;
+  }
+
+  // Describes the grammar of TaskQueue::SetQueueEnabled.
+  message SetQueueEnabledAction {
+    // NEXT ID = 4
+
+    // Used to identify the |task_queue_id|'s oldest available queue to
+    // enable/disable (modulo the number of available queues).
+    optional uint64 task_queue_id = 1;
+
+    // Used to identify the |voter_id|'s oldest available voter (modulo the
+    // number of available voters).
+    optional uint64 voter_id = 2;
+
+    optional bool enabled = 3 [default = true];
+  }
+
+  // Describes the grammar of TaskQueue::ShutDownTaskQueue
+  message ShutdownTaskQueueAction {
+    // NEXT ID = 2
+
+    // Used to identify the |task_queue_id|'s oldest available queue to shutdown
+    // (modulo the number of available queues).
+    optional uint64 task_queue_id = 1;
+  }
+
+  message CancelTaskAction {
+    // NEXT ID = 2
+
+    // Used to identify the |task_id|'s oldest pending task to cancel (modulo
+    // the number of pending tasks).
+    optional uint64 task_id = 1;
+  }
+
   repeated Action initial_actions = 1;
 }
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
index fc78acb..73e7ff74 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
@@ -10,6 +10,29 @@
 namespace base {
 namespace sequence_manager {
 
+namespace {
+
+TaskQueue::QueuePriority ToTaskQueuePriority(
+    SequenceManagerTestDescription::QueuePriority priority) {
+  switch (priority) {
+    case SequenceManagerTestDescription::BEST_EFFORT:
+      return TaskQueue::kBestEffortPriority;
+    case SequenceManagerTestDescription::LOW:
+      return TaskQueue::kLowPriority;
+    case SequenceManagerTestDescription::UNDEFINED:
+    case SequenceManagerTestDescription::NORMAL:
+      return TaskQueue::kNormalPriority;
+    case SequenceManagerTestDescription::HIGH:
+      return TaskQueue::kHighPriority;
+    case SequenceManagerTestDescription::HIGHEST:
+      return TaskQueue::kHighestPriority;
+    case SequenceManagerTestDescription::CONTROL:
+      return TaskQueue::kControlPriority;
+  }
+}
+
+}  // namespace
+
 void SequenceManagerFuzzerProcessor::ParseAndRun(
     const SequenceManagerTestDescription& description) {
   SequenceManagerFuzzerProcessor processor;
@@ -35,7 +58,7 @@
                                      test_task_runner_->GetMockTickClock());
 
   TaskQueue::Spec spec = TaskQueue::Spec("default_task_queue");
-  task_queues_.push_back(manager_->CreateTaskQueue<TestTaskQueue>(spec));
+  task_queues_.emplace_back(manager_->CreateTaskQueue<TestTaskQueue>(spec));
 }
 
 void SequenceManagerFuzzerProcessor::RunTest(
@@ -50,15 +73,29 @@
 void SequenceManagerFuzzerProcessor::RunAction(
     const SequenceManagerTestDescription::Action& action) {
   if (action.has_create_task_queue()) {
-    return CreateTaskQueueFromAction(action.action_id(),
-                                     action.create_task_queue());
+    ExecuteCreateTaskQueueAction(action.action_id(),
+                                 action.create_task_queue());
+  } else if (action.has_set_queue_priority()) {
+    ExecuteSetQueuePriorityAction(action.action_id(),
+                                  action.set_queue_priority());
+  } else if (action.has_set_queue_enabled()) {
+    ExecuteSetQueueEnabledAction(action.action_id(),
+                                 action.set_queue_enabled());
+  } else if (action.has_create_queue_voter()) {
+    ExecuteCreateQueueVoterAction(action.action_id(),
+                                  action.create_queue_voter());
+  } else if (action.has_shutdown_task_queue()) {
+    ExecuteShutdownTaskQueueAction(action.action_id(),
+                                   action.shutdown_task_queue());
+  } else if (action.has_cancel_task()) {
+    ExecuteCancelTaskAction(action.action_id(), action.cancel_task());
+  } else {
+    ExecutePostDelayedTaskAction(action.action_id(),
+                                 action.post_delayed_task());
   }
-
-  return PostDelayedTaskFromAction(action.action_id(),
-                                   action.post_delayed_task());
 }
 
-void SequenceManagerFuzzerProcessor::PostDelayedTaskFromAction(
+void SequenceManagerFuzzerProcessor::ExecutePostDelayedTaskAction(
     uint64_t action_id,
     const SequenceManagerTestDescription::PostDelayedTaskAction& action) {
   DCHECK(!task_queues_.empty());
@@ -66,27 +103,114 @@
   LogActionForTesting(action_id, ActionForTest::ActionType::kPostDelayedTask,
                       test_task_runner_->GetMockTickClock()->NowTicks());
 
-  size_t index = action.task_queue_id() % task_queues_.size();
-  TestTaskQueue* chosen_task_queue = task_queues_[index].get();
+  size_t queue_index = action.task_queue_id() % task_queues_.size();
+  TestTaskQueue* chosen_task_queue = task_queues_[queue_index].queue.get();
+
+  std::unique_ptr<Task> pending_task = std::make_unique<Task>(this);
 
   // TODO(farahcharab) After adding non-nestable/nestable tasks, fix this to
-  // PostNonnestableDelayedTask for the former and PostDelayedTask for the
+  // PostNonNestableDelayedTask for the former and PostDelayedTask for the
   // latter.
   chosen_task_queue->PostDelayedTask(
       FROM_HERE,
-      BindOnce(&SequenceManagerFuzzerProcessor::ExecuteTask, Unretained(this),
+      BindOnce(&Task::Execute, pending_task->weak_ptr_factory_.GetWeakPtr(),
                action.task()),
       TimeDelta::FromMilliseconds(action.delay_ms()));
+
+  pending_tasks_.push_back(std::move(pending_task));
 }
 
-void SequenceManagerFuzzerProcessor::CreateTaskQueueFromAction(
+void SequenceManagerFuzzerProcessor::ExecuteCreateTaskQueueAction(
     uint64_t action_id,
     const SequenceManagerTestDescription::CreateTaskQueueAction& action) {
   LogActionForTesting(action_id, ActionForTest::ActionType::kCreateTaskQueue,
                       test_task_runner_->GetMockTickClock()->NowTicks());
 
   TaskQueue::Spec spec = TaskQueue::Spec("test_task_queue");
-  task_queues_.push_back(manager_->CreateTaskQueue<TestTaskQueue>(spec));
+  task_queues_.emplace_back(manager_->CreateTaskQueue<TestTaskQueue>(spec));
+  task_queues_.back().queue->SetQueuePriority(
+      ToTaskQueuePriority(action.initial_priority()));
+}
+
+void SequenceManagerFuzzerProcessor::ExecuteSetQueuePriorityAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::SetQueuePriorityAction& action) {
+  DCHECK(!task_queues_.empty());
+
+  LogActionForTesting(action_id, ActionForTest::ActionType::kSetQueuePriority,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  size_t queue_index = action.task_queue_id() % task_queues_.size();
+  TestTaskQueue* chosen_task_queue = task_queues_[queue_index].queue.get();
+
+  chosen_task_queue->SetQueuePriority(ToTaskQueuePriority(action.priority()));
+}
+
+void SequenceManagerFuzzerProcessor::ExecuteSetQueueEnabledAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::SetQueueEnabledAction& action) {
+  DCHECK(!task_queues_.empty());
+
+  LogActionForTesting(action_id, ActionForTest::ActionType::kSetQueueEnabled,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  size_t queue_index = action.task_queue_id() % task_queues_.size();
+  TestTaskQueue* chosen_task_queue = task_queues_[queue_index].queue.get();
+
+  if (task_queues_[queue_index].voters.empty()) {
+    task_queues_[queue_index].voters.push_back(
+        chosen_task_queue->CreateQueueEnabledVoter());
+  }
+
+  size_t voter_index =
+      action.voter_id() % task_queues_[queue_index].voters.size();
+  task_queues_[queue_index].voters[voter_index]->SetQueueEnabled(
+      action.enabled());
+}
+
+void SequenceManagerFuzzerProcessor::ExecuteCreateQueueVoterAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::CreateQueueVoterAction& action) {
+  LogActionForTesting(action_id, ActionForTest::ActionType::kCreateQueueVoter,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  size_t queue_index = action.task_queue_id() % task_queues_.size();
+  TestTaskQueue* chosen_task_queue = task_queues_[queue_index].queue.get();
+
+  task_queues_[queue_index].voters.push_back(
+      chosen_task_queue->CreateQueueEnabledVoter());
+}
+
+void SequenceManagerFuzzerProcessor::ExecuteShutdownTaskQueueAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::ShutdownTaskQueueAction& action) {
+  LogActionForTesting(action_id, ActionForTest::ActionType::kShutdownTaskQueue,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  // We always want to have a default task queue.
+  if (task_queues_.size() > 1) {
+    size_t queue_index = action.task_queue_id() % task_queues_.size();
+    task_queues_[queue_index].queue.get()->ShutdownTaskQueue();
+    task_queues_.erase(task_queues_.begin() + queue_index);
+  }
+}
+
+void SequenceManagerFuzzerProcessor::ExecuteCancelTaskAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::CancelTaskAction& action) {
+  LogActionForTesting(action_id, ActionForTest::ActionType::kCancelTask,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  if (!pending_tasks_.empty()) {
+    size_t queue_index = action.task_id() % pending_tasks_.size();
+    pending_tasks_[queue_index]->weak_ptr_factory_.InvalidateWeakPtrs();
+
+    // If it is already running, it is a parent task and will be deleted when
+    // it is done.
+    if (!pending_tasks_[queue_index]->is_running) {
+      pending_tasks_.erase(pending_tasks_.begin() + queue_index);
+    }
+  }
 }
 
 void SequenceManagerFuzzerProcessor::ExecuteTask(
@@ -95,7 +219,7 @@
 
   // We can limit the depth of the nested post delayed action when processing
   // the proto.
-  for (const auto& task_action : task.action()) {
+  for (const auto& task_action : task.actions()) {
     // TODO(farahcharab) Add run loop to deal with nested tasks later. So far,
     // we are assuming tasks are non-nestable.
     RunAction(task_action);
@@ -111,6 +235,14 @@
                     test_task_runner_->GetMockTickClock()->NowTicks());
 }
 
+void SequenceManagerFuzzerProcessor::DeleteTask(Task* task) {
+  size_t i = 0;
+  while (i < pending_tasks_.size() && task != pending_tasks_[i].get()) {
+    i++;
+  }
+  pending_tasks_.erase(pending_tasks_.begin() + i);
+}
+
 void SequenceManagerFuzzerProcessor::LogTaskForTesting(uint64_t task_id,
                                                        TimeTicks start_time,
                                                        TimeTicks end_time) {
@@ -144,6 +276,17 @@
   return ordered_actions_;
 }
 
+SequenceManagerFuzzerProcessor::Task::Task(
+    SequenceManagerFuzzerProcessor* processor)
+    : is_running(false), processor_(processor), weak_ptr_factory_(this) {}
+
+void SequenceManagerFuzzerProcessor::Task::Execute(
+    const SequenceManagerTestDescription::Task& task) {
+  is_running = true;
+  processor_->ExecuteTask(task);
+  processor_->DeleteTask(this);
+}
+
 SequenceManagerFuzzerProcessor::TaskForTest::TaskForTest(uint64_t id,
                                                          uint64_t start,
                                                          uint64_t end)
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
index 07140f8d..fcd2502 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <vector>
 
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
 #include "base/task/sequence_manager/test/test_task_queue.h"
 #include "base/test/test_mock_time_task_runner.h"
@@ -37,7 +39,15 @@
   };
 
   struct ActionForTest {
-    enum class ActionType { kCreateTaskQueue, kPostDelayedTask };
+    enum class ActionType {
+      kCreateTaskQueue,
+      kPostDelayedTask,
+      kSetQueuePriority,
+      kSetQueueEnabled,
+      kCreateQueueVoter,
+      kCancelTask,
+      kShutdownTaskQueue,
+    };
 
     ActionForTest(uint64_t id, ActionType type, uint64_t start);
     bool operator==(const ActionForTest& rhs) const;
@@ -59,16 +69,52 @@
   const std::vector<ActionForTest>& ordered_actions() const;
 
  private:
-  void CreateTaskQueueFromAction(
+  class Task {
+   public:
+    Task(SequenceManagerFuzzerProcessor* processor);
+    ~Task() = default;
+
+    void Execute(const SequenceManagerTestDescription::Task& task);
+
+    bool is_running;
+    SequenceManagerFuzzerProcessor* processor_;
+    base::WeakPtrFactory<Task> weak_ptr_factory_;
+  };
+
+  struct TaskQueueWithVoters {
+    TaskQueueWithVoters(scoped_refptr<TestTaskQueue> task_queue)
+        : queue(std::move(task_queue)){};
+
+    scoped_refptr<TestTaskQueue> queue;
+    std::vector<std::unique_ptr<TaskQueue::QueueEnabledVoter>> voters;
+  };
+
+  void ExecuteCreateTaskQueueAction(
       uint64_t action_id,
       const SequenceManagerTestDescription::CreateTaskQueueAction& action);
-
-  void PostDelayedTaskFromAction(
+  void ExecutePostDelayedTaskAction(
       uint64_t action_id,
       const SequenceManagerTestDescription::PostDelayedTaskAction& action);
+  void ExecuteSetQueuePriorityAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::SetQueuePriorityAction& action);
+  void ExecuteSetQueueEnabledAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::SetQueueEnabledAction& action);
+  void ExecuteCreateQueueVoterAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::CreateQueueVoterAction& action);
+  void ExecuteShutdownTaskQueueAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::ShutdownTaskQueueAction& action);
+  void ExecuteCancelTaskAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::CancelTaskAction& action);
 
   void ExecuteTask(const SequenceManagerTestDescription::Task& task);
 
+  void DeleteTask(Task* task);
+
   void LogTaskForTesting(uint64_t task_id,
                          TimeTicks start_time,
                          TimeTicks end_time);
@@ -83,7 +129,14 @@
   // manager.
   scoped_refptr<TestMockTimeTaskRunner> test_task_runner_;
 
-  std::vector<scoped_refptr<TestTaskQueue>> task_queues_;
+  // For testing purposes, this should follow the order in which the queues were
+  // created.
+  std::vector<TaskQueueWithVoters> task_queues_;
+
+  // Used to be able to cancel pending tasks from the sequence manager. For
+  // testing purposes, this should follow the order in which the tasks were
+  // posted.
+  std::vector<std::unique_ptr<Task>> pending_tasks_;
 
   const bool log_for_testing_;
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
index 00aed913..aba61e4 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
@@ -16,6 +16,7 @@
 namespace sequence_manager {
 
 using testing::ContainerEq;
+using testing::IsEmpty;
 
 class SequenceManagerFuzzerProcessorForTest
     : public SequenceManagerFuzzerProcessor {
@@ -51,11 +52,27 @@
 
 TEST(SequenceManagerFuzzerProcessorTest, CreateTaskQueue) {
   std::vector<ActionForTest> executed_actions;
+
+  // Describes a test that creates a task queue and posts a task to create a
+  // task queue.
   SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
        initial_actions {
-          action_id : 1
-          create_task_queue {
-          }
+         action_id : 1
+         create_task_queue {
+         }
+       }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           task {
+             task_id : 1
+             actions {
+               action_id : 3
+               create_task_queue {
+               }
+             }
+           }
+         }
        })",
                                                      nullptr,
                                                      &executed_actions);
@@ -63,7 +80,48 @@
   std::vector<ActionForTest> expected_actions;
   expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateTaskQueue,
                                 0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kCreateTaskQueue,
+                                0);
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+}
 
+TEST(SequenceManagerFuzzerProcessorTest, CreateQueueVoter) {
+  std::vector<ActionForTest> executed_actions;
+
+  // Describes a test that creates a voter and posts a task to create a queue
+  // voter.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+         action_id : 1
+         create_queue_voter {
+           task_queue_id : 1
+         }
+       }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           task {
+             task_id : 1
+             actions {
+               action_id : 3
+               create_queue_voter {
+               }
+             }
+           }
+         }
+       })",
+                                                     nullptr,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateQueueVoter,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kCreateQueueVoter,
+                                0);
   EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
 }
 
@@ -97,6 +155,549 @@
   EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
 }
 
+TEST(SequenceManagerFuzzerProcessorTest, SetQueuePriority) {
+  std::vector<ActionForTest> executed_actions;
+
+  // Describes a test that sets the priority of queue and posts a task to set
+  // the priority of a queue.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+          action_id : 1
+          set_queue_priority {
+            task_queue_id: 2
+            priority: CONTROL
+          }
+       }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           task {
+             task_id : 1
+             actions {
+               action_id : 3
+               set_queue_priority {
+                 task_queue_id : 1
+                 priority : LOW
+               }
+             }
+           }
+         }
+       })",
+                                                     nullptr,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kSetQueuePriority,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kSetQueuePriority,
+                                0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, SetQueueEnabled) {
+  std::vector<ActionForTest> executed_actions;
+  std::vector<TaskForTest> executed_tasks;
+
+  // Describes a test that posts a number of tasks to a certain queue, disable
+  // that queue, and post some more tasks to the same queue.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+         action_id : 1
+         post_delayed_task {
+           task_queue_id: 1
+           task {
+             task_id : 1
+           }
+         }
+       }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           delay_ms : 10
+           task_queue_id: 1
+           task {
+             task_id : 2
+           }
+         }
+       }
+       initial_actions {
+         action_id : 3
+         set_queue_enabled {
+           task_queue_id: 1
+           enabled: false
+         }
+       }
+      initial_actions {
+        action_id : 4
+        post_delayed_task {
+          task_queue_id: 1
+          task {
+            task_id : 3
+          }
+        }
+      })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kSetQueueEnabled,
+                                0);
+  expected_actions.emplace_back(4, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  // All the tasks posted to the task queue with id 1 do not get executed since
+  // this task queue is disabled.
+  EXPECT_THAT(executed_tasks, IsEmpty());
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, SetQueueEnabledWithDelays) {
+  std::vector<TaskForTest> executed_tasks;
+
+  // Describes a test that posts two tasks to disable and enable a queue after
+  // 10ms and 20ms, respectively; and other no-op tasks in the different
+  // intervals to verify that the queue is indeed being disabled/enabled
+  // properly.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+         action_id : 1
+         create_task_queue {
+         }
+       }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           task_queue_id: 1
+           task {
+             task_id : 1
+           }
+         }
+       }
+       initial_actions {
+         action_id : 3
+         post_delayed_task {
+           delay_ms : 15
+           task_queue_id: 1
+           task {
+             task_id : 2
+           }
+         }
+       }
+       initial_actions {
+         action_id : 4
+         post_delayed_task {
+           delay_ms : 10
+           task_queue_id: 1
+           task {
+             task_id : 3
+             actions {
+               action_id : 5
+               set_queue_enabled {
+                 task_queue_id: 1
+                 enabled: false
+               }
+             }
+           }
+         }
+       }
+       initial_actions {
+         action_id : 6
+         post_delayed_task {
+           delay_ms : 20
+           task_queue_id: 0
+           task {
+             task_id : 4
+             actions {
+               action_id : 7
+               set_queue_enabled {
+                 task_queue_id: 1
+                 enabled: true
+               }
+             }
+           }
+         }
+       }
+       initial_actions {
+         action_id : 8
+         post_delayed_task {
+           task_queue_id: 1
+           delay_ms : 20
+           task {
+             task_id : 5
+           }
+         }
+       })",
+                                                     &executed_tasks, nullptr);
+
+  std::vector<TaskForTest> expected_tasks;
+
+  expected_tasks.emplace_back(1, 0, 0);
+
+  // Task that disables the queue.
+  expected_tasks.emplace_back(3, 10, 10);
+
+  // Task that enable the queue.
+  expected_tasks.emplace_back(4, 20, 20);
+
+  // Task couldn't execute at scheduled time i.e. 15ms since its queue was
+  // disabled at that time.
+  expected_tasks.emplace_back(2, 20, 20);
+  expected_tasks.emplace_back(5, 20, 20);
+
+  EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, MultipleVoters) {
+  std::vector<ActionForTest> executed_actions;
+  std::vector<TaskForTest> executed_tasks;
+
+  // Describes a test that creates two voters for a queue, where one voter
+  // enables the queue, and the other disables it.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+      initial_actions {
+         action_id : 1
+         create_queue_voter {
+           task_queue_id : 1
+         }
+       }
+       initial_actions {
+         action_id : 2
+         create_queue_voter {
+           task_queue_id : 1
+         }
+       }
+       initial_actions {
+         action_id : 3
+         set_queue_enabled {
+           voter_id : 1
+           task_queue_id : 1
+           enabled : true
+         }
+       }
+       initial_actions {
+         action_id : 4
+         set_queue_enabled {
+           voter_id : 2
+           task_queue_id : 1
+           enabled : false
+         }
+       }
+       initial_actions {
+         action_id : 5
+         post_delayed_task {
+           task_queue_id: 1
+           task {
+             task_id : 1
+           }
+         }
+       })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateQueueVoter,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kCreateQueueVoter,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kSetQueueEnabled,
+                                0);
+  expected_actions.emplace_back(4, ActionForTest::ActionType::kSetQueueEnabled,
+                                0);
+  expected_actions.emplace_back(5, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  std::vector<TaskForTest> expected_tasks;
+
+  // Queue is enabled only if all voters enable it.
+  EXPECT_THAT(executed_tasks, IsEmpty());
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, ShutdownTaskQueue) {
+  std::vector<ActionForTest> executed_actions;
+  std::vector<TaskForTest> executed_tasks;
+
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+         action_id : 1
+         create_task_queue {
+         }
+       }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           task_queue_id: 1
+           task {
+             task_id : 1
+           }
+         }
+        }
+        initial_actions {
+          action_id :3
+          post_delayed_task {
+            delay_ms : 10
+            task_queue_id: 1
+            task {
+              task_id : 2
+            }
+          }
+        }
+        initial_actions {
+          action_id : 4
+          post_delayed_task {
+            task_queue_id: 0
+            delay_ms : 10
+            task {
+              task_id : 3
+            }
+          }
+        }
+        initial_actions {
+          action_id : 5
+          shutdown_task_queue {
+            task_queue_id: 1
+          }
+        }
+        initial_actions {
+          action_id : 6
+          post_delayed_task {
+            task_queue_id: 1
+            task {
+              task_id : 4
+            }
+          }
+        })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateTaskQueue,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(4, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(
+      5, ActionForTest::ActionType::kShutdownTaskQueue, 0);
+  expected_actions.emplace_back(6, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  std::vector<TaskForTest> expected_tasks;
+
+  // Note that the task with id 4 isn't posted to the queue that was shutdown,
+  // since that was posted to the first available queue (Check
+  // sequence_manager_test_description.proto for more details).
+  expected_tasks.emplace_back(4, 0, 0);
+  expected_tasks.emplace_back(3, 10, 10);
+
+  EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest,
+     ShutdownTaskQueueWhenOneQueueAvailable) {
+  std::vector<TaskForTest> executed_tasks;
+  std::vector<ActionForTest> executed_actions;
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+        initial_actions {
+          action_id : 1
+          post_delayed_task {
+            task {
+              task_id : 1
+            }
+          }
+        }
+        initial_actions {
+          action_id : 2
+          shutdown_task_queue {
+            task_queue_id: 1
+          }
+        })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(
+      2, ActionForTest::ActionType::kShutdownTaskQueue, 0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  std::vector<TaskForTest> expected_tasks;
+
+  // We always want to have a default task queue in the fuzzer processor. So, if
+  // we have only one queue, the shutdown action is effectively a no-op.
+  expected_tasks.emplace_back(1, 0, 0);
+
+  EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, ShutdownPostingTaskQueue) {
+  std::vector<TaskForTest> executed_tasks;
+  std::vector<ActionForTest> executed_actions;
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+        initial_actions {
+          action_id : 1
+          create_task_queue {
+          }
+        }
+        initial_actions {
+          action_id : 2
+          post_delayed_task {
+            task_queue_id : 0
+            task{
+              task_id : 1
+              actions {
+                action_id : 3
+                shutdown_task_queue {
+                  task_queue_id : 0
+                }
+              }
+            }
+          }
+        })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateTaskQueue,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(
+      3, ActionForTest::ActionType::kShutdownTaskQueue, 0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  std::vector<TaskForTest> expected_tasks;
+  expected_tasks.emplace_back(1, 0, 0);
+
+  EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, CancelParentTask) {
+  std::vector<ActionForTest> executed_actions;
+  std::vector<TaskForTest> executed_tasks;
+
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+    initial_actions {
+      action_id : 1
+      post_delayed_task {
+        task {
+          task_id : 0
+          actions {
+            action_id : 2
+            post_delayed_task {
+              task {
+                task_id : 1
+              }
+            }
+          }
+          actions {
+            action_id : 3
+            cancel_task {
+              task_id : 0
+            }
+          }
+          actions {
+            action_id : 4
+            post_delayed_task {
+              task {
+                task_id : 2
+              }
+            }
+          }
+        }
+      }
+    })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kCancelTask, 0);
+  expected_actions.emplace_back(4, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  std::vector<TaskForTest> expected_tasks;
+
+  expected_tasks.emplace_back(0, 0, 0);
+  expected_tasks.emplace_back(1, 0, 0);
+  expected_tasks.emplace_back(2, 0, 0);
+
+  EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, CancelTask) {
+  std::vector<TaskForTest> executed_tasks;
+  std::vector<ActionForTest> executed_actions;
+
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+    initial_actions {
+      action_id : 1
+      post_delayed_task {
+        task {
+          task_id : 1
+        }
+      }
+    }
+    initial_actions {
+      action_id : 2
+      cancel_task {
+        task_id : 1
+      }
+    }
+  )",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kCancelTask, 0);
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  EXPECT_THAT(executed_tasks, IsEmpty());
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, CancelTaskWhenNoneArePending) {
+  std::vector<ActionForTest> executed_actions;
+
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+    initial_actions {
+      action_id : 1
+      cancel_task {
+        task_id : 1
+      }
+    }
+  )",
+                                                     nullptr,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kCancelTask, 0);
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+}
+
 TEST(SequenceManagerFuzzerProcessorTest,
      TaskDurationBlocksOtherPendingTasksPostedFromOutsideOfTask) {
   std::vector<TaskForTest> executed_tasks;
@@ -153,7 +754,7 @@
             task {
               task_id : 1
               duration_ms : 40
-              action {
+              actions {
                 post_delayed_task {
                   task {
                     task_id : 2
@@ -191,12 +792,12 @@
           task {
             task_id : 1
             duration_ms : 40
-            action {
+            actions {
               action_id : 2
               create_task_queue {
               }
             }
-            action {
+            actions {
               action_id : 3
               post_delayed_task {
                 delay_ms : 4
@@ -205,7 +806,7 @@
                 }
               }
             }
-            action {
+            actions {
               action_id: 4
               post_delayed_task {
                 task {
@@ -213,12 +814,12 @@
                 }
               }
             }
-            action {
+            actions {
               action_id : 5
               create_task_queue {
               }
             }
-            action {
+            actions {
               action_id : 6
               post_delayed_task {
                delay_ms : 40
@@ -278,7 +879,7 @@
           delay_ms : 10
           task {
             task_id : 1
-            action {
+            actions {
               action_id : 3
               create_task_queue {
               }
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
index 76eb0e7..9ca45e2 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
@@ -141,6 +141,24 @@
     std::unique_ptr<WebRTCStatsReportCallback>) {}
 
 webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
+MockWebRTCPeerConnectionHandler::AddTransceiverWithTrack(
+    const WebMediaStreamTrack& track,
+    const webrtc::RtpTransceiverInit&) {
+  std::unique_ptr<WebRTCRtpTransceiver> transceiver =
+      std::make_unique<DummyRTCRtpTransceiver>(track);
+  return transceiver;
+}
+
+webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
+MockWebRTCPeerConnectionHandler::AddTransceiverWithKind(
+    std::string kind,
+    const webrtc::RtpTransceiverInit&) {
+  std::unique_ptr<WebRTCRtpTransceiver> transceiver =
+      std::make_unique<DummyRTCRtpTransceiver>(WebMediaStreamTrack());
+  return transceiver;
+}
+
+webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
 MockWebRTCPeerConnectionHandler::AddTrack(const WebMediaStreamTrack& track,
                                           const WebVector<WebMediaStream>&) {
   std::unique_ptr<WebRTCRtpTransceiver> transceiver =
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
index 9e26e6b..091f79d 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
@@ -37,6 +37,12 @@
   webrtc::RTCErrorType SetConfiguration(const WebRTCConfiguration&) override;
   void GetStats(const WebRTCStatsRequest&) override;
   void GetStats(std::unique_ptr<WebRTCStatsReportCallback>) override;
+  webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
+  AddTransceiverWithTrack(const WebMediaStreamTrack&,
+                          const webrtc::RtpTransceiverInit&) override;
+  webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
+  AddTransceiverWithKind(std::string kind,
+                         const webrtc::RtpTransceiverInit&) override;
   webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>> AddTrack(
       const WebMediaStreamTrack&,
       const WebVector<WebMediaStream>&) override;
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js
index eff6321..54311a8 100644
--- a/third_party/closure_compiler/externs/developer_private.js
+++ b/third_party/closure_compiler/externs/developer_private.js
@@ -225,7 +225,6 @@
 
 /**
  * @enum {string}
- * @see https://developer.chrome.com/extensions/developerPrivate#type-HostAccess
  */
 chrome.developerPrivate.HostAccess = {
   ON_CLICK: 'ON_CLICK',
@@ -275,7 +274,6 @@
  *   hostAccess: (!chrome.developerPrivate.HostAccess|undefined),
  *   runtimeHostPermissions: (!Array<string>|undefined)
  * }}
- * @see https://developer.chrome.com/extensions/developerPrivate#type-Permissions
  */
 chrome.developerPrivate.Permissions;
 
@@ -459,6 +457,7 @@
   WARNINGS_CHANGED: 'WARNINGS_CHANGED',
   COMMAND_ADDED: 'COMMAND_ADDED',
   COMMAND_REMOVED: 'COMMAND_REMOVED',
+  PERMISSIONS_CHANGED: 'PERMISSIONS_CHANGED',
 };
 
 /**
diff --git a/third_party/feed/OWNERS b/third_party/feed/OWNERS
index ba0283b8..74086c2 100644
--- a/third_party/feed/OWNERS
+++ b/third_party/feed/OWNERS
@@ -1,5 +1,6 @@
 fgorski@chromium.org
 pavely@chromium.org
+skym@chromium.org
 zea@chromium.org
 
 # Team: chrome-jardin-team@google.com
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index 6bcc6a8..fef1dbd 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -2,9 +2,9 @@
 Short Name: libaom
 URL: https://aomedia.googlesource.com/aom/
 Version: 0
-Date: Wednesday July 18 2018
+Date: Thursday July 19 2018
 Branch: master
-Commit: 369ab2088d3f20df1b653c970151d2c654167334
+Commit: 88e4b0a4ee32d39371e15040fa0a1ee7c9d8a19d
 License: BSD
 License File: source/libaom/LICENSE
 Security Critical: yes
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h
index 19cc9eb1..1f1f3e5 100644
--- a/third_party/libaom/source/config/config/aom_version.h
+++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 0
 #define VERSION_PATCH 0
-#define VERSION_EXTRA "167-g369ab2088"
+#define VERSION_EXTRA "173-g88e4b0a4e"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "1.0.0-167-g369ab2088"
-#define VERSION_STRING " 1.0.0-167-g369ab2088"
+#define VERSION_STRING_NOSP "1.0.0-173-g88e4b0a4e"
+#define VERSION_STRING " 1.0.0-173-g88e4b0a4e"
diff --git a/tools/android/native_lib_memory/process_residency.py b/tools/android/native_lib_memory/process_residency.py
index bc2d981..08f4b58 100755
--- a/tools/android/native_lib_memory/process_residency.py
+++ b/tools/android/native_lib_memory/process_residency.py
@@ -27,7 +27,7 @@
 
 
 def ParseDump(filename):
-  """Parses a residency dump, as generated from lightweight_cygprofile.cc.
+  """Parses a residency dump, as generated from orderfile_instrumentation.cc.
 
   Args:
     filename: (str) dump filename.
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index fe8c3dd..e6bbb0e1 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -118,6 +118,9 @@
   main_symbols = dex_symbols + ordered_symbols[:symbol_count]
   extra_symbols = ordered_symbols[symbol_count:]
 
+  logging.info('Found %d large symbols, %s small symbols',
+               len(main_symbols), len(extra_symbols))
+
   # Bundle symbols by the file they belong to,
   # and add all the file buckets into file_nodes
   for symbol in main_symbols:
diff --git a/tools/binary_size/libsupersize/start_server.py b/tools/binary_size/libsupersize/start_server.py
index 23ef088..05178d84 100644
--- a/tools/binary_size/libsupersize/start_server.py
+++ b/tools/binary_size/libsupersize/start_server.py
@@ -38,7 +38,7 @@
 
 def Run(args, _parser):
   logging.info('Starting server')
-  server_addr = ('', args.port)
+  server_addr = (args.address, args.port)
 
   static_files = os.path.join(os.path.dirname(__file__), 'static')
 
diff --git a/tools/binary_size/libsupersize/static/index.html b/tools/binary_size/libsupersize/static/index.html
index 3a29bf0..eb6187e 100644
--- a/tools/binary_size/libsupersize/static/index.html
+++ b/tools/binary_size/libsupersize/static/index.html
@@ -94,6 +94,7 @@
         }
         .subhead,
         .subhead-2 {
+            margin-bottom: 0.5em;
             font-family: "Google Sans", Arial, sans-serif;
             font-weight: 500;
             font-size: 16px;
@@ -199,7 +200,7 @@
         }
 
         .diff .size-header::after {
-            content: ' diff';
+            content: " diff";
         }
     </style>
     <link rel="stylesheet" href="options.css">
@@ -224,9 +225,9 @@
                     -->
                     <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm6 7l-4 4h3v4h2v-4h3l-4-4z" />
                 </svg>
-                Upload data
+                <span class="label-text">Upload data</span>
             </label>
-            <a href="https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/html_report_faq.md" class="icon-button" title="FAQ">
+            <a href="https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/html_report_faq.md" class="icon-button" title="FAQ" id="faq">
                 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#5f6368">
                     <path d="M11,18h2v-2h-2V18z M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8
                             s3.59-8,8-8s8,3.59,8,8S16.41,20,12,20z M12,6c-2.21,0-4,1.79-4,4h2c0-1.1,0.9-2,2-2s2,0.9,2,2c0,2-3,1.75-3,5h2c0-2.25,3-2.5,3-5
@@ -266,20 +267,28 @@
             </button>
         </header>
 
-        <h2 class="subhead">Size options</h2>
-        <p class="select-wrapper">
-            <select id="byteunit" name="byteunit">
-                <option value="B">B - bytes</option>
-                <option value="KiB">KiB - kilibytes</option>
-                <option value="MiB" selected>MiB - megabytes</option>
-                <option value="GiB">GiB - gigabytes</option>
-            </select>
-            <label class="select-label" for="byteunit">Byte unit</label>
-        </p>
-        <p class="checkbox-wrapper">
-            <input type="checkbox" id="methodcount" name="method_count" value="on">
-            <label class="checkbox-label" for="methodcount">Show dex method count rather than size</label>
-        </p>
+        <fieldset>
+            <legend class="subhead">Size options</legend>
+            <div class="checkbox-wrapper">
+                <input type="checkbox" id="methodcount" name="method_count" value="on">
+                <label class="checkbox-label" for="methodcount">Show dex method count rather than size</label>
+            </div>
+            <p class="select-wrapper">
+                <select id="byteunit" name="byteunit">
+                    <option value="B">B - bytes</option>
+                    <option value="KiB">KiB - kilibytes</option>
+                    <option value="MiB" selected>MiB - megabytes</option>
+                    <option value="GiB">GiB - gigabytes</option>
+                </select>
+                <label class="select-label" for="byteunit">Byte unit</label>
+            </p>
+            <p class="input-wrapper">
+                <input type="number" id="minsize" name="min_size" value="0" min="0">
+                <label class="input-label" for="minsize">
+                    Minimum size (bytes)
+                </label>
+            </p>
+        </fieldset>
 
         <fieldset>
             <legend class="subhead">Group symbols by</legend>
@@ -293,6 +302,24 @@
             </div>
         </fieldset>
 
+        <fieldset>
+            <legend class="subhead">Search by regex</legend>
+            <div class="input-wrapper">
+                <input class="input-regex" type="text" id="includeregex" name="include" placeholder=".+@.+" aria-describedby="include-error">
+                <label class="input-label" for="includeregex">
+                    Symbols must contain
+                </label>
+                <p class="input-error" id="include-error"></p>
+            </div>
+            <div class="input-wrapper">
+                <input class="input-regex" type="text" id="excluderegex" name="exclude" placeholder="\(.+\)"  aria-describedby="exclude-error">
+                <label class="input-label" for="excluderegex">
+                        Symbols must exclude
+                </label>
+                <p class="input-error" id="exclude-error"></p>
+            </div>
+        </fieldset>
+
         <fieldset id="types-filter">
             <legend class="subhead">Symbol types to show</legend>
             <div class="checkbox-wrapper">
@@ -364,31 +391,6 @@
             <button type="button" class="text-button" id="type-all">Select all</button>
             <button type="button" class="text-button" id="type-none">Select none</button>
         </fieldset>
-
-        <fieldset>
-            <legend class="subhead">Advanced filters</legend>
-            <p class="input-wrapper">
-                <input type="number" id="minsize" name="min_size" value="0" min="0">
-                <label class="input-label" for="minsize">
-                    Minimum size (bytes)
-                </label>
-            </p>
-            <fieldset>
-                <legend class="subhead-2">Regular expressions</legend>
-                <div class="input-wrapper">
-                    <input class="input-regex" type="text" id="includeregex" name="include" placeholder=".+@.+">
-                    <label class="input-label" for="includeregex">
-                        Symbols must contain
-                    </label>
-                </div>
-                <div class="input-wrapper">
-                    <input class="input-regex" type="text" id="excluderegex" name="exclude" placeholder="\(.+\)">
-                    <label class="input-label" for="excluderegex">
-                            Symbols must exclude
-                    </label>
-                </div>
-            </fieldset>
-        </fieldset>
     </form>
     <div class="symbols">
         <div hidden id="icons">
@@ -397,7 +399,7 @@
                 <path d="M9.17,6l2,2H20v10L4,18V6H9.17 M10,4H4C2.9,4,2.01,4.9,2.01,6L2,18c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8c0-1.1-0.9-2-2-2
                             h-8L10,4L10,4z" />
             </svg>
-            <svg class='icon componenticon' height='24' width='24' fill='#5f6368'>
+            <svg class="icon componenticon" height="24" width="24" fill="#5f6368">
                 <title>Component</title>
                 <path d="M9,13.75c-2.34,0-7,1.17-7,3.5V19h14v-1.75C16,14.92,11.34,13.75,9,13.75z M4.34,17c0.84-0.58,2.87-1.25,4.66-1.25
                          s3.82,0.67,4.66,1.25H4.34z" />
diff --git a/tools/binary_size/libsupersize/static/infocard.css b/tools/binary_size/libsupersize/static/infocard.css
index b810584..86f139b 100644
--- a/tools/binary_size/libsupersize/static/infocard.css
+++ b/tools/binary_size/libsupersize/static/infocard.css
@@ -20,7 +20,8 @@
   transition: 0.3s ease transform, 0.3s ease opacity, 0.3s ease visibility;
 }
 .tree-container:hover ~ .infocards,
-.tree-container.focused ~ .infocards {
+.tree-container.focused ~ .infocards,
+.infocards:hover {
   visibility: visible;
   opacity: 1;
   transform: none;
diff --git a/tools/binary_size/libsupersize/static/options.css b/tools/binary_size/libsupersize/static/options.css
index 20b15235..f627327 100644
--- a/tools/binary_size/libsupersize/static/options.css
+++ b/tools/binary_size/libsupersize/static/options.css
@@ -43,7 +43,7 @@
 fieldset {
   border: 0;
   padding: 0;
-  margin: 2em 0 1em;
+  margin: 1em 0;
 }
 .options fieldset:first-of-type {
   margin-top: 1em;
@@ -83,7 +83,7 @@
 
 .text-button {
   padding: 0 8px;
-  line-height: 36px;
+  height: 36px;
   border-radius: 4px;
   color: #1a73e8;
   font-family: 'Google Sans', Arial, sans-serif;
@@ -136,8 +136,6 @@
   position: relative;
   border-top-left-radius: 4px;
   border-top-right-radius: 4px;
-  background: rgba(0, 0, 0, 0.04);
-  margin-bottom: 1em;
 }
 input[type='text'],
 input[type='number'],
@@ -158,14 +156,15 @@
   position: absolute;
   z-index: -1;
   top: 0;
-  bottom: -1px;
   left: 0;
   right: 0;
-  font-size: 12px;
+  height: 52px;
   line-height: 20px;
   padding: 0 12px;
+  font-size: 12px;
   color: #5f6368;
   border-bottom: 1px solid currentColor;
+  background: rgba(0, 0, 0, 0.04);
 }
 .select-label::after {
   content: '';
@@ -189,6 +188,26 @@
   transform: rotate(180deg);
 }
 
+.input-error {
+  margin: 4px 0;
+  min-height: 2.5em;
+  opacity: 0;
+  color: #d93025;
+  font-size: 12px;
+}
+.input-regex:invalid,
+.input-regex[aria-invalid='true'] {
+  caret-color: #d93025;
+}
+.input-regex:invalid + .input-label,
+.input-regex[aria-invalid='true'] + .input-label {
+  color: #d93025;
+}
+.input-regex:invalid ~ .input-error,
+.input-regex[aria-invalid='true'] ~ .input-error {
+  opacity: 1;
+}
+
 /** <input type='checkbox' or 'radio'> elements */
 input[type='checkbox'],
 input[type='radio'] {
@@ -269,6 +288,8 @@
 }
 
 input[type='file'] {
+  position: absolute;
+  top: -100%;
   opacity: 0;
 }
 
@@ -280,7 +301,8 @@
   .show-options .scrim {
     display: block;
   }
-  .appbar,
+
+  .appbar-inner,
   .symbols {
     padding: 0 16px;
   }
@@ -288,4 +310,11 @@
     margin: 0 -16px;
     width: calc(100% + 32px);
   }
+
+  .filled-button {
+    padding-right: 6px;
+  }
+  .filled-button .label-text {
+    display: none;
+  }
 }
diff --git a/tools/binary_size/libsupersize/static/state.js b/tools/binary_size/libsupersize/static/state.js
index 0b34bdce..f0f1abf 100644
--- a/tools/binary_size/libsupersize/static/state.js
+++ b/tools/binary_size/libsupersize/static/state.js
@@ -242,6 +242,29 @@
   setMethodCountModeUI();
   methodCountInput.addEventListener('change', setMethodCountModeUI);
 
+  /**
+   * Display error text on blur for regex inputs, if the input is invalid.
+   * @param {Event} event
+   */
+  function checkForRegExError(event) {
+    const input = /** @type {HTMLInputElement} */ (event.currentTarget);
+    const errorBox = document.getElementById(
+      input.getAttribute('aria-describedby')
+    );
+    try {
+      new RegExp(input.value);
+      errorBox.textContent = '';
+      input.setAttribute('aria-invalid', 'false');
+    } catch (err) {
+      errorBox.textContent = err.message;
+      input.setAttribute('aria-invalid', 'true');
+    }
+  }
+  for (const input of document.getElementsByClassName('input-regex')) {
+    input.addEventListener('blur', checkForRegExError);
+    input.dispatchEvent(new Event('blur'));
+  }
+
   document.getElementById('type-all').addEventListener('click', () => {
     for (const checkbox of typeCheckboxes) {
       checkbox.checked = true;
@@ -335,7 +358,7 @@
   function getSizeContents(node) {
     if (state.has('method_count')) {
       const {count: methodCount = 0} =
-          node.childStats[_DEX_METHOD_SYMBOL_TYPE] || {};
+        node.childStats[_DEX_METHOD_SYMBOL_TYPE] || {};
       const methodStr = methodCount.toLocaleString(_LOCALE, {
         useGrouping: true,
       });
diff --git a/tools/binary_size/libsupersize/static/tree-ui.js b/tools/binary_size/libsupersize/static/tree-ui.js
index 5e8d614..4ace63c 100644
--- a/tools/binary_size/libsupersize/static/tree-ui.js
+++ b/tools/binary_size/libsupersize/static/tree-ui.js
@@ -11,7 +11,7 @@
  * Binary Size Analysis HTML report.
  */
 
-{
+const newTreeElement = (() => {
   /** Capture one of: "::", "../", "./", "/", "#" */
   const _SPECIAL_CHAR_REGEX = /(::|(?:\.*\/)+|#)/g;
   /** Insert zero-width space after capture group */
@@ -107,7 +107,7 @@
   }
 
   /**
-   * Keydown event handler to move focus for the given element
+   * Tree view keydown event handler to move focus for the given element.
    * @param {KeyboardEvent} event
    */
   function _handleKeyNavigation(event) {
@@ -163,11 +163,10 @@
         break;
       // If closed tree, open tree. Otherwise, move to first child.
       case 'ArrowRight': {
-        const data = _uiNodeData.get(link);
-        if (!data.children || data.children.length !== 0) {
-          const isExpanded =
-            link.parentElement.getAttribute('aria-expanded') === 'true';
-          if (isExpanded) {
+        const expanded = link.parentElement.getAttribute('aria-expanded');
+        if (expanded != null) {
+          // Leafs do not have the aria-expanded property
+          if (expanded === 'true') {
             _focusNext();
           } else {
             _toggle();
@@ -213,6 +212,10 @@
           }
         }
         break;
+      // Remove focus from the tree view.
+      case 'Escape':
+        link.blur();
+        break;
       // If a letter was pressed, find a node starting with that character.
       default:
         if (event.key.length === 1 && event.key.match(/\S/)) {
@@ -228,6 +231,18 @@
   }
 
   /**
+   * Display the infocard when a node is hovered over, unless a node is
+   * currently focused.
+   * @param {MouseEvent} event
+   */
+  function _handleMouseOver(event) {
+    const active = document.activeElement;
+    if (!active || !active.classList.contains('node')) {
+      displayInfocard(_uiNodeData.get(event.currentTarget));
+    }
+  }
+
+  /**
    * Replace the contents of the size element for a tree node.
    * @param {HTMLElement} sizeElement Element that should display the size
    * @param {TreeNode} node
@@ -288,9 +303,7 @@
     // Set the byte size and hover text
     _setSize(element.querySelector('.size'), data);
 
-    link.addEventListener('mouseover', event =>
-      displayInfocard(_uiNodeData.get(event.currentTarget))
-    );
+    link.addEventListener('mouseover', _handleMouseOver);
     if (!isLeaf) {
       link.addEventListener('click', _toggleTreeElement);
     }
@@ -317,9 +330,15 @@
   _symbolTree.addEventListener('focusout', event =>
     event.currentTarget.parentElement.classList.remove('focused')
   );
+  window.addEventListener('keydown', event => {
+    if (event.key === '?' && event.target.tagName !== 'INPUT') {
+      // Open help when "?" is pressed
+      document.getElementById('faq').click();
+    }
+  });
 
-  self.newTreeElement = newTreeElement;
-}
+  return newTreeElement
+})();
 
 {
   class ProgressBar {
diff --git a/tools/binary_size/libsupersize/static/tree-worker.js b/tools/binary_size/libsupersize/static/tree-worker.js
index 46aa5323..0597776 100644
--- a/tools/binary_size/libsupersize/static/tree-worker.js
+++ b/tools/binary_size/libsupersize/static/tree-worker.js
@@ -583,12 +583,20 @@
   }
 
   if (includeRegex) {
-    const regex = new RegExp(includeRegex);
-    filters.push(s => regex.test(s.idPath));
+    try {
+      const regex = new RegExp(includeRegex);
+      filters.push(s => regex.test(s.idPath));
+    } catch (err) {
+      if (err.name !== 'SyntaxError') throw err;
+    }
   }
   if (excludeRegex) {
-    const regex = new RegExp(excludeRegex);
-    filters.push(s => !regex.test(s.idPath));
+    try {
+      const regex = new RegExp(excludeRegex);
+      filters.push(s => !regex.test(s.idPath));
+    } catch (err) {
+      if (err.name !== 'SyntaxError') throw err;
+    }
   }
 
   /**
diff --git a/tools/cygprofile/phased_orderfile.py b/tools/cygprofile/phased_orderfile.py
index aee4c422..73bb234 100755
--- a/tools/cygprofile/phased_orderfile.py
+++ b/tools/cygprofile/phased_orderfile.py
@@ -5,8 +5,7 @@
 
 """Utilities for creating a phased orderfile.
 
-This kind of orderfile is based on cygprofile lightweight instrumentation. The
-profile dump format is described in process_profiles.py. These tools assume
+The profile dump format is described in process_profiles.py. These tools assume
 profiling has been done with two phases.
 
 The first phase, labeled 0 in the filename, is called "startup" and the second,
diff --git a/tools/cygprofile/process_profiles.py b/tools/cygprofile/process_profiles.py
index 12b3003..a436ead 100755
--- a/tools/cygprofile/process_profiles.py
+++ b/tools/cygprofile/process_profiles.py
@@ -42,8 +42,8 @@
 
   In the function names below, "dump" is used to refer to arbitrary offsets in a
   binary (eg, from a profiling run), while "offset" refers to a symbol
-  offset. The dump offsets are relative to the start of text, as returned by
-  lightweight_cygprofile.cc.
+  offset. The dump offsets are relative to the start of text, as produced by
+  orderfile_instrumentation.cc.
 
   This class manages expensive operations like extracting symbols, so that
   higher-level operations can be done in different orders without the caller
@@ -206,9 +206,6 @@
 class ProfileManager(object):
   """Manipulates sets of profiles.
 
-  The manager supports only lightweight-style profiles (see
-  lightweight_cygprofile.cc) and not the older cygprofile offset lists.
-
   A "profile set" refers to a set of data from an instrumented version of chrome
   that will be processed together, usually to produce a single orderfile. A
   "run" refers to a session of chrome, visiting several pages and thus
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 075c7be..0596c82 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4089,6 +4089,11 @@
   <int value="1" label="Lacks Form Manager"/>
 </enum>
 
+<enum name="BooleanFound">
+  <int value="0" label="Not found"/>
+  <int value="1" label="Found"/>
+</enum>
+
 <enum name="BooleanFrameAsOverlay">
   <int value="0" label="Frame was not allow_overlay"/>
   <int value="1" label="Frame was allow_overlay"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index bb4a9ec..c3d9756 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -103455,6 +103455,14 @@
   </summary>
 </histogram>
 
+<histogram name="ThirdPartyModules.GetDriveLetterPathFound" enum="BooleanFound">
+  <owner>pmonette@chromium.org</owner>
+  <summary>
+    Records whether an equivalent driver letter path was found for a device
+    path.
+  </summary>
+</histogram>
+
 <histogram name="ThirdPartyModules.InputMethodEditorsCount" units="counts">
   <owner>pmonette@chromium.org</owner>
   <summary>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 23f2581..bdf1621 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -240,8 +240,6 @@
 # Benchmark: system_health.common_desktop
 crbug.com/828917 [ Mac ] system_health.common_desktop/multitab:misc:typical24 [ Skip ]
 crbug.com/853188 [ Win ] system_health.common_desktop/browse:news:cnn [ Skip ]
-crbug.com/865465 [ Win ] system_health.common_desktop/browse:news:hackernews [ Skip ]
-crbug.com/865465 [ Mac ] system_health.common_desktop/browse:news:hackernews [ Skip ]
 crbug.com/649392 [ Win ] system_health.common_desktop/play:media:soundcloud [ Skip ]
 crbug.com/649392 [ All ] system_health.common_desktop/play:media:google_play_music [ Skip ]
 crbug.com/773084 [ Mac ] system_health.common_desktop/browse:tools:maps [ Skip ]
@@ -331,7 +329,6 @@
 crbug.com/676336 [ Win ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
 crbug.com/676336 [ Mac ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
 [ Mac ] v8.browsing_desktop/browse:news:cnn [ Skip ]
-crbug.com/865887 [ Mac ] v8.browsing_desktop/browse:media:tumblr [ Skip ]
 crbug.com/798465 [ Mac ] v8.browsing_desktop/browse:news:flipboard [ Skip ]
 crbug.com/798465 [ Win ] v8.browsing_desktop/browse:news:flipboard [ Skip ]
 crbug.com/813165 [ Win ] v8.browsing_desktop/browse:media:flickr_infinite_scroll [ Skip ]
diff --git a/tools/perf/page_sets/data/rendering_mobile.json b/tools/perf/page_sets/data/rendering_mobile.json
index 00662ef8..c83c3a8 100644
--- a/tools/perf/page_sets/data/rendering_mobile.json
+++ b/tools/perf/page_sets/data/rendering_mobile.json
@@ -690,151 +690,151 @@
 	"accu_weather_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "accu_weather_2018_desktop_gpu_raster": {
+        "accu_weather_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "twitch_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "twitch_2018_desktop_gpu_raster": {
+        "twitch_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
 	"google_docs_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "google_docs_2018_desktop_gpu_raster": {
+        "google_docs_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "facebook_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "facebook_2018_desktop_gpu_raster": {
+        "facebook_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "wikipedia_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "wikipedia_2018_desktop_gpu_raster": {
+        "wikipedia_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "yahoo_answers_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "yahoo_answers_2018_desktop_gpu_raster": {
+        "yahoo_answers_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "booking.com_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "booking.com_2018_desktop_gpu_raster": {
+        "booking.com_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "wordpress_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "wordpress_2018_desktop_gpu_raster": {
+        "wordpress_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "espn_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "espn_2018_desktop_gpu_raster": {
+        "espn_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "blogspot_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "blogspot_2018_desktop_gpu_raster": {
+        "blogspot_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "yahoo_news_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "yahoo_news_2018_desktop_gpu_raster": {
+        "yahoo_news_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "pinterest_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "pinterest_2018_desktop_gpu_raster": {
+        "pinterest_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "yahoo_sports_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "yahoo_sports_2018_desktop_gpu_raster": {
+        "yahoo_sports_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "techcrunch_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "techcrunch_2018_desktop_gpu_raster": {
+        "techcrunch_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "amazon_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "amazon_2018_desktop_gpu_raster": {
+        "amazon_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "cnn_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "cnn_2018_desktop_gpu_raster": {
+        "cnn_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "ebay_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "ebay_2018_desktop_gpu_raster": {
+        "ebay_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "linkedin_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "linkedin_2018_desktop_gpu_raster": {
+        "linkedin_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "youtube_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "youtube_2018_desktop_gpu_raster": {
+        "youtube_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "gmail_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "gmail_2018_desktop_gpu_raster": {
+        "gmail_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "google_plus_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "google_plus_2018_desktop_gpu_raster": {
+        "google_plus_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "twitter_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "twitter_2018_desktop_gpu_raster": {
+        "twitter_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "google_web_search_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "google_web_search_2018_desktop_gpu_raster": {
+        "google_web_search_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "google_calendar_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "google_calendar_2018_desktop_gpu_raster": {
+        "google_calendar_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
         "google_image_search_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
-        "google_image_search_2018_desktop_gpu_raster": {
+        "google_image_search_desktop_gpu_raster_2018": {
             "DEFAULT": "top_25_012.wprgo"
         },
 	"filter_terrain_svg": {
diff --git a/tools/perf/page_sets/rendering/top_real_world_desktop.py b/tools/perf/page_sets/rendering/top_real_world_desktop.py
index bd6429e2..fe485a6 100644
--- a/tools/perf/page_sets/rendering/top_real_world_desktop.py
+++ b/tools/perf/page_sets/rendering/top_real_world_desktop.py
@@ -57,7 +57,8 @@
 
 class GoogleWebSearch2018Page(TopRealWorldDesktopPage):
   """ Why: top google property; a google tab is often open """
-  BASE_NAME = 'google_web_search_2018'
+  BASE_NAME = 'google_web_search'
+  YEAR = '2018'
   URL = 'https://www.google.com/#hl=en&q=barack+obama'
 
   def __init__(self,
@@ -99,7 +100,8 @@
 
 class GoogleImageSearch2018Page(TopRealWorldDesktopPage):
   """ Why: tough image case; top google properties """
-  BASE_NAME = 'google_image_search_2018'
+  BASE_NAME = 'google_image_search'
+  YEAR = '2018'
   URL = 'https://www.google.com/search?q=cats&tbm=isch'
 
   def __init__(self,
@@ -221,7 +223,8 @@
 
 class GooglePlus2018Page(TopRealWorldDesktopPage):
   """ Why: social; top google property; Public profile; infinite scrolls """
-  BASE_NAME = 'google_plus_2018'
+  BASE_NAME = 'google_plus'
+  YEAR = '2018'
   URL = 'https://plus.google.com/110031535020051778989/posts'
 
   def __init__(self,
@@ -264,7 +267,8 @@
 
 class Youtube2018Page(TopRealWorldDesktopPage):
   """ Why: #3 (Alexa global) """
-  BASE_NAME = 'youtube_2018'
+  BASE_NAME = 'youtube'
+  YEAR = '2018'
   URL = 'http://www.youtube.com'
 
   def __init__(self,
@@ -308,7 +312,8 @@
 class Blogspot2018Page(TopRealWorldDesktopPage):
   """ Why: #11 (Alexa global), google property; some blogger layouts have
   infinite scroll but more interesting """
-  BASE_NAME = 'blogspot_2018'
+  BASE_NAME = 'blogspot'
+  YEAR = '2018'
   URL = 'http://googlewebmastercentral.blogspot.com/'
 
   def __init__(self,
@@ -354,7 +359,8 @@
 
 class Wordpress2018Page(TopRealWorldDesktopPage):
   """ Why: #18 (Alexa global), Picked an interesting post """
-  BASE_NAME = 'wordpress_2018'
+  BASE_NAME = 'wordpress'
+  YEAR = '2018'
   # pylint: disable=line-too-long
   URL = 'http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/'
 
@@ -400,7 +406,8 @@
 
 class Facebook2018Page(TopRealWorldDesktopPage):
   """ Why: top social,Public profile """
-  BASE_NAME = 'facebook_2018'
+  BASE_NAME = 'facebook'
+  YEAR = '2018'
   URL = 'https://www.facebook.com/barackobama'
 
   def __init__(self,
@@ -438,7 +445,8 @@
 
 class Linkedin2018Page(TopRealWorldDesktopPage):
   """ Why: #12 (Alexa global), Public profile. """
-  BASE_NAME = 'linkedin_2018'
+  BASE_NAME = 'linkedin'
+  YEAR = '2018'
   URL = 'http://www.linkedin.com/in/linustorvalds'
 
   def __init__(self,
@@ -476,7 +484,8 @@
 
 class Wikipedia2018Page(TopRealWorldDesktopPage):
   """ Why: #6 (Alexa) most visited worldwide,Picked an interesting page. """
-  BASE_NAME = 'wikipedia_2018'
+  BASE_NAME = 'wikipedia'
+  YEAR = '2018'
   URL = 'http://en.wikipedia.org/wiki/Wikipedia'
 
   def __init__(self,
@@ -514,7 +523,8 @@
 
 class Twitter2018Page(TopRealWorldDesktopPage):
   """ Why: #8 (Alexa global),Picked an interesting page """
-  BASE_NAME = 'twitter_2018'
+  BASE_NAME = 'twitter'
+  YEAR = '2018'
   URL = 'https://twitter.com/katyperry'
 
   def __init__(self,
@@ -552,7 +562,8 @@
 
 class Pinterest2018Page(TopRealWorldDesktopPage):
   """ Why: #37 (Alexa global) """
-  BASE_NAME = 'pinterest_2018'
+  BASE_NAME = 'pinterest'
+  YEAR = '2018'
   URL = 'https://www.pinterest.com/search/pins/?q=flowers&rs=typed'
 
   def __init__(self,
@@ -603,7 +614,8 @@
 
 class AccuWeather2018Page(TopRealWorldDesktopPage):
   """ Why: #2 weather according to Alexa """
-  BASE_NAME = 'accu_weather_2018'
+  BASE_NAME = 'accu_weather'
+  YEAR = '2018'
   URL = 'https://www.accuweather.com/en/us/new-york-ny/10017/weather-forecast/349727'
 
   def __init__(self,
@@ -641,7 +653,8 @@
 
 class Twitch2018Page(TopRealWorldDesktopPage):
   """ Why: #1 games according to Alexa  """
-  BASE_NAME = 'twitch_2018'
+  BASE_NAME = 'twitch'
+  YEAR = '2018'
   URL = 'https://www.twitch.tv'
 
   def __init__(self,
@@ -692,7 +705,8 @@
 
 class Gmail2018SmoothPage(TopRealWorldDesktopPage):
   """ Why: productivity, top google properties """
-  BASE_NAME = 'gmail_2018'
+  BASE_NAME = 'gmail'
+  YEAR = '2018'
   URL = 'https://mail.google.com/mail/'
 
   def RunNavigateSteps(self, action_runner):
@@ -732,7 +746,8 @@
 
 class GoogleCalendar2018SmoothPage(TopRealWorldDesktopPage):
   """ Why: productivity, top google properties """
-  BASE_NAME='google_calendar_2018'
+  BASE_NAME='google_calendar'
+  YEAR = '2018'
   URL='https://www.google.com/calendar/'
 
   def RunNavigateSteps(self, action_runner):
@@ -781,7 +796,8 @@
   """ Why: productivity, top google properties; Sample doc in the link """
   # pylint: disable=line-too-long
   URL = 'https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view'
-  BASE_NAME='google_docs_2018'
+  BASE_NAME='google_docs'
+  YEAR = '2018'
 
   def RunNavigateSteps(self, action_runner):
     super(GoogleDoc2018SmoothPage, self).RunNavigateSteps(action_runner)
@@ -816,7 +832,8 @@
 
 class ESPN2018SmoothPage(TopRealWorldDesktopPage):
   """ Why: #1 sports """
-  BASE_NAME='espn_2018'
+  BASE_NAME='espn'
+  YEAR = '2018'
   URL = 'http://espn.go.com'
 
   def RunPageInteractions(self, action_runner):
@@ -837,7 +854,8 @@
 
 class YahooNews2018Page(TopRealWorldDesktopPage):
   """Why: #1 news worldwide (Alexa global)"""
-  BASE_NAME = 'yahoo_news_2018'
+  BASE_NAME = 'yahoo_news'
+  YEAR = '2018'
   URL = 'http://news.yahoo.com'
 
 
@@ -849,7 +867,8 @@
 
 class CNNNews2018Page(TopRealWorldDesktopPage):
   """Why: #2 news worldwide"""
-  BASE_NAME = 'cnn_2018'
+  BASE_NAME = 'cnn'
+  YEAR = '2018'
   URL = 'http://www.cnn.com'
 
 
@@ -863,7 +882,8 @@
 class Amazon2018Page(TopRealWorldDesktopPage):
   # Why: #1 world commerce website by visits; #3 commerce in the US by
   # time spent
-  BASE_NAME = 'amazon_2018'
+  BASE_NAME = 'amazon'
+  YEAR = '2018'
   URL = 'http://www.amazon.com'
 
 
@@ -875,7 +895,8 @@
 
 class Ebay2018Page(TopRealWorldDesktopPage):
   # Why: #1 commerce website by time spent by users in US
-  BASE_NAME = 'ebay_2018'
+  BASE_NAME = 'ebay'
+  YEAR = '2018'
   URL = 'http://www.ebay.com'
 
 
@@ -887,7 +908,8 @@
 
 class Booking2018Page(TopRealWorldDesktopPage):
   # Why: #1 Alexa recreation
-  BASE_NAME = 'booking.com_2018'
+  BASE_NAME = 'booking.com'
+  YEAR = '2018'
   URL = 'http://booking.com'
 
 
@@ -899,7 +921,8 @@
 
 class YahooAnswers2018Page(TopRealWorldDesktopPage):
   # Why: #1 Alexa reference
-  BASE_NAME = 'yahoo_answers_2018'
+  BASE_NAME = 'yahoo_answers'
+  YEAR = '2018'
   URL = 'http://answers.yahoo.com'
 
 
@@ -911,7 +934,8 @@
 
 class YahooSports2018Page(TopRealWorldDesktopPage):
   # Why: #1 Alexa sports
-  BASE_NAME = 'yahoo_sports_2018'
+  BASE_NAME = 'yahoo_sports'
+  YEAR = '2018'
   URL = 'http://sports.yahoo.com/'
 
 
@@ -923,5 +947,6 @@
 
 class TechCrunch2018Page(TopRealWorldDesktopPage):
   # Why: top tech blog
-  BASE_NAME = 'techcrunch_2018'
+  BASE_NAME = 'techcrunch'
+  YEAR = '2018'
   URL = 'http://techcrunch.com'
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index 823c2e3..376bb94 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -22,12 +22,12 @@
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher_observer.h"
 #include "ui/aura/window_port_for_shutdown.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/events/event_target_iterator.h"
 #include "ui/events/platform/platform_event_source.h"
 
 #if defined(USE_OZONE)
 #include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/ozone_switches.h"
 #endif
 
 namespace aura {
@@ -223,7 +223,7 @@
   // instead of checking flags here.
   params.single_process = command_line->HasSwitch("single-process") ||
                           command_line->HasSwitch("in-process-gpu");
-  params.using_mojo = command_line->HasSwitch(switches::kEnableDrmMojo);
+  params.using_mojo = features::IsOzoneDrmMojo();
 
   if (connector) {
     // Supplying a connector implies this process is hosting Viz.
diff --git a/ui/base/accelerators/accelerator_manager_delegate.h b/ui/base/accelerators/accelerator_manager_delegate.h
index 4cbd0ed5..7056be1 100644
--- a/ui/base/accelerators/accelerator_manager_delegate.h
+++ b/ui/base/accelerators/accelerator_manager_delegate.h
@@ -11,6 +11,7 @@
 
 class Accelerator;
 
+// TODO: this should no longer be necessary, remove. https://crbug.com/842365
 class UI_BASE_EXPORT AcceleratorManagerDelegate {
  public:
   // Called when new accelerators are registered. This is only called with
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index ff8e986f..fa44ab1 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -167,4 +167,12 @@
 #endif  //  BUILDFLAG(MAC_VIEWS_BROWSER)
 #endif  //  defined(OS_MACOSX)
 
+const base::Feature kEnableOzoneDrmMojo = {"OzoneDrmMojo",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsOzoneDrmMojo() {
+  return base::FeatureList::IsEnabled(kEnableOzoneDrmMojo) ||
+         IsAshInBrowserProcess();
+}
+
 }  // namespace features
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index c1e1e278..ce8a71f 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -72,6 +72,13 @@
 #endif  //  BUILDFLAG(MAC_VIEWS_BROWSER)
 #endif  //  defined(OS_MACOSX)
 
+// Use mojo communication in the drm platform instead of paramtraits. Remove
+// this switch (and associated code) when the drm platform always uses mojo
+// communication.
+// TODO(rjkroege): Remove in http://crbug.com/806092.
+UI_BASE_EXPORT extern const base::Feature kEnableOzoneDrmMojo;
+UI_BASE_EXPORT bool IsOzoneDrmMojo();
+
 }  // namespace features
 
 #endif  // UI_BASE_UI_BASE_FEATURES_H_
diff --git a/ui/events/gestures/gesture_provider_aura.cc b/ui/events/gestures/gesture_provider_aura.cc
index fd0912c..b2a4d79 100644
--- a/ui/events/gestures/gesture_provider_aura.cc
+++ b/ui/events/gestures/gesture_provider_aura.cc
@@ -45,11 +45,12 @@
     return false;
 
   auto result = filtered_gesture_provider_.OnTouchEvent(pointer_state_);
+  pointer_state_.CleanupRemovedTouchPoints(*event);
+
   if (!result.succeeded)
     return false;
 
   event->set_may_cause_scrolling(result.moved_beyond_slop_region);
-  pointer_state_.CleanupRemovedTouchPoints(*event);
   return true;
 }
 
diff --git a/ui/events/gestures/gesture_provider_aura_unittest.cc b/ui/events/gestures/gesture_provider_aura_unittest.cc
index 0b263dc6..1eaa215 100644
--- a/ui/events/gestures/gesture_provider_aura_unittest.cc
+++ b/ui/events/gestures/gesture_provider_aura_unittest.cc
@@ -78,6 +78,45 @@
   EXPECT_FALSE(provider()->OnTouchEvent(&move1));
 }
 
+TEST_F(GestureProviderAuraTest, DoesntStallOnCancelAndRelease) {
+  base::TimeTicks time = ui::EventTimeForNow();
+
+  TouchEvent touch_press(
+      ET_TOUCH_PRESSED, gfx::Point(10, 10), time,
+      PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+  EXPECT_TRUE(provider()->OnTouchEvent(&touch_press));
+  time += base::TimeDelta::FromMilliseconds(10);
+
+  TouchEvent pen_press1(
+      ET_TOUCH_PRESSED, gfx::Point(20, 20), time,
+      PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 1));
+  EXPECT_TRUE(provider()->OnTouchEvent(&pen_press1));
+  time += base::TimeDelta::FromMilliseconds(10);
+
+  TouchEvent touch_cancel(
+      ET_TOUCH_CANCELLED, gfx::Point(30, 30), time,
+      PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+  EXPECT_TRUE(provider()->OnTouchEvent(&touch_cancel));
+  time += base::TimeDelta::FromMilliseconds(10);
+
+  TouchEvent pen_release1(
+      ET_TOUCH_RELEASED, gfx::Point(40, 40), time,
+      PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 1));
+  EXPECT_FALSE(provider()->OnTouchEvent(&pen_release1));
+  time += base::TimeDelta::FromMilliseconds(10);
+
+  TouchEvent pen_press2(
+      ET_TOUCH_PRESSED, gfx::Point(10, 10), time,
+      PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 0));
+  EXPECT_TRUE(provider()->OnTouchEvent(&pen_press2));
+  time += base::TimeDelta::FromMilliseconds(10);
+
+  TouchEvent pen_release2(
+      ET_TOUCH_RELEASED, gfx::Point(10, 10), time,
+      PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 0));
+  EXPECT_TRUE(provider()->OnTouchEvent(&pen_release2));
+}
+
 TEST_F(GestureProviderAuraTest, IgnoresIdenticalMoveEvents) {
   const float kRadiusX = 20.f;
   const float kRadiusY = 30.f;
diff --git a/ui/gl/angle_platform_impl.h b/ui/gl/angle_platform_impl.h
index 927850cc..21f101a7 100644
--- a/ui/gl/angle_platform_impl.h
+++ b/ui/gl/angle_platform_impl.h
@@ -18,7 +18,7 @@
 GL_EXPORT void ResetPlatform(EGLDisplay display);
 
 using CacheProgramCallback =
-    base::RepeatingCallback<void(const std::string&, const std::string&)>;
+    ::base::RepeatingCallback<void(const std::string&, const std::string&)>;
 GL_EXPORT void SetCacheProgramCallback(CacheProgramCallback callback);
 GL_EXPORT void ResetCacheProgramCallback();
 
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index d90aab3..695970b 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -101,6 +101,10 @@
       'GLuint program, GLuint colorNumber, GLuint index, const char* name',
 },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glBindFragmentInputLocationCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
+  'arguments': 'GLuint program, GLint location, const char* name', },
+{ 'return_type': 'void',
   'names': ['glBindFramebufferEXT', 'glBindFramebuffer'],
   'arguments': 'GLenum target, GLuint framebuffer', },
 { 'return_type': 'void',
@@ -317,22 +321,42 @@
       'GLboolean unpackUnmultiplyAlpha', },
 { 'return_type': 'void',
   'names': ['glCoverageModulationNV'],
+  'versions': [{ 'name': 'glCoverageModulationNV',
+                 'extensions': ['GL_NV_framebuffer_mixed_samples'] },
+               { 'name': 'glCoverageModulationCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_framebuffer_mixed_samples'] }],
   'arguments': 'GLenum components'},
 { 'return_type': 'void',
   'names': ['glCoverFillPathInstancedNV'],
+  'versions': [{ 'name': 'glCoverFillPathInstancedNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glCoverFillPathInstancedCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei numPaths, GLenum pathNameType, const void* paths, '
   'GLuint pathBase, GLenum coverMode, GLenum transformType, '
   'const GLfloat* transformValues' },
 { 'return_type': 'void',
   'names': ['glCoverFillPathNV'],
+  'versions': [{ 'name': 'glCoverFillPathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glCoverFillPathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLenum coverMode' },
 { 'return_type': 'void',
   'names': ['glCoverStrokePathInstancedNV'],
+  'versions': [{ 'name': 'glCoverStrokePathInstancedNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glCoverStrokePathInstancedCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei numPaths, GLenum pathNameType, const void* paths, '
   'GLuint pathBase, GLenum coverMode, GLenum transformType, '
   'const GLfloat* transformValues' },
 { 'return_type': 'void',
   'names': ['glCoverStrokePathNV'],
+  'versions': [{ 'name': 'glCoverStrokePathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glCoverStrokePathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint name, GLenum coverMode' },
 { 'return_type': 'GLuint',
   'names': ['glCreateProgram'],
@@ -379,6 +403,10 @@
   'arguments': 'GLsizei n, const GLuint* framebuffers', },
 { 'return_type': 'void',
   'names': ['glDeletePathsNV'],
+  'versions': [{ 'name': 'glDeletePathsNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glDeletePathsCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLsizei range' },
 { 'return_type': 'void',
   'names': ['glDeleteProgram'],
@@ -563,6 +591,10 @@
   'arguments': 'GLsizei n, GLuint* framebuffers', },
 { 'return_type': 'GLuint',
   'names': ['glGenPathsNV'],
+  'versions': [{ 'name': 'glGenPathsNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glGenPathsCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei range' },
 { 'return_type': 'void',
   'versions': [{ 'name': 'glGenQueries' },
@@ -1160,6 +1192,10 @@
   'arguments': 'GLuint framebuffer', },
 { 'return_type': 'GLboolean',
   'names': ['glIsPathNV'],
+  'versions': [{ 'name': 'glIsPathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glIsPathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path' },
 { 'return_type': 'GLboolean',
   'names': ['glIsProgram'],
@@ -1221,13 +1257,17 @@
   'known_as': 'glMatrixLoadfEXT',
   'versions': [{ 'name': 'glMatrixLoadfEXT',
                  'extensions': ['GL_EXT_direct_state_access',
-                                'GL_NV_path_rendering'] }],
+                                'GL_NV_path_rendering'] },
+               { 'name': 'glMatrixLoadfCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLenum matrixMode, const GLfloat* m' },
 { 'return_type': 'void',
   'known_as': 'glMatrixLoadIdentityEXT',
   'versions': [{ 'name': 'glMatrixLoadIdentityEXT',
                  'extensions': ['GL_EXT_direct_state_access',
-                                'GL_NV_path_rendering'] },],
+                                'GL_NV_path_rendering'] },
+               { 'name': 'glMatrixLoadIdentityCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLenum matrixMode' },
 { 'return_type': 'void',
   'known_as': 'glMemoryBarrierEXT',
@@ -1249,16 +1289,32 @@
   'arguments': 'void* ptr, GLsizei length, const char* label', },
 { 'return_type': 'void',
   'names': ['glPathCommandsNV'],
+  'versions': [{ 'name': 'glPathCommandsNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glPathCommandsCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLsizei numCommands, const GLubyte* commands, '
   'GLsizei numCoords, GLenum coordType, const GLvoid* coords' },
 { 'return_type': 'void',
   'names': ['glPathParameterfNV'],
+  'versions': [{ 'name': 'glPathParameterfNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glPathParameterfCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLenum pname, GLfloat value' },
 { 'return_type': 'void',
   'names': ['glPathParameteriNV'],
+  'versions': [{ 'name': 'glPathParameteriNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glPathParameteriCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLenum pname, GLint value' },
 { 'return_type': 'void',
   'names': ['glPathStencilFuncNV'],
+  'versions': [{ 'name': 'glPathStencilFuncNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glPathStencilFuncCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLenum func, GLint ref, GLuint mask' },
 { 'return_type': 'void',
   'versions': [{ 'name': 'glPauseTransformFeedback',
@@ -1300,6 +1356,10 @@
   'arguments': 'GLuint program, GLenum pname, GLint value' },
 { 'return_type': 'void',
   'names': ['glProgramPathFragmentInputGenNV'],
+  'versions': [{ 'name': 'glProgramPathFragmentInputGenNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glProgramPathFragmentInputGenCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint program, GLint location, GLenum genMode, '
   'GLint components, const GLfloat* coeffs',
   'is_optional': True, },
@@ -1446,11 +1506,19 @@
 """, },
 { 'return_type': 'void',
   'names': ['glStencilFillPathInstancedNV'],
+  'versions': [{ 'name': 'glStencilFillPathInstancedNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilFillPathInstancedCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei numPaths, GLenum pathNameType, const void* paths, '
   'GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, '
   'const GLfloat* transformValues' },
 { 'return_type': 'void',
   'names': ['glStencilFillPathNV'],
+  'versions': [{ 'name': 'glStencilFillPathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilFillPathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLenum fillMode, GLuint mask' },
 { 'return_type': 'void',
   'names': ['glStencilFunc'],
@@ -1472,30 +1540,54 @@
   'arguments': 'GLenum face, GLenum fail, GLenum zfail, GLenum zpass', },
 { 'return_type': 'void',
   'names': ['glStencilStrokePathInstancedNV'],
+  'versions': [{ 'name': 'glStencilStrokePathInstancedNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilStrokePathInstancedCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei numPaths, GLenum pathNameType, const void* paths, '
   'GLuint pathBase, GLint ref, GLuint mask, GLenum transformType, '
   'const GLfloat* transformValues' },
 { 'return_type': 'void',
   'names': ['glStencilStrokePathNV'],
+  'versions': [{ 'name': 'glStencilStrokePathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilStrokePathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLint reference, GLuint mask' },
 { 'return_type': 'void',
   'names': ['glStencilThenCoverFillPathInstancedNV'],
+  'versions': [{ 'name': 'glStencilThenCoverFillPathInstancedNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilThenCoverFillPathInstancedCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei numPaths, GLenum pathNameType, const void* paths, '
   'GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, '
   'GLenum transformType, const GLfloat* transformValues',
   'is_optional': True, },
 { 'return_type': 'void',
   'names': ['glStencilThenCoverFillPathNV'],
+  'versions': [{ 'name': 'glStencilThenCoverFillPathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilThenCoverFillPathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode',
   'is_optional': True, },
 { 'return_type': 'void',
   'names': ['glStencilThenCoverStrokePathInstancedNV'],
+  'versions': [{ 'name': 'glStencilThenCoverStrokePathInstancedNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilThenCoverStrokePathInstancedCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLsizei numPaths, GLenum pathNameType, const void* paths, '
   'GLuint pathBase, GLint ref, GLuint mask, GLenum coverMode, '
   'GLenum transformType, const GLfloat* transformValues',
   'is_optional': True, },
 { 'return_type': 'void',
   'names': ['glStencilThenCoverStrokePathNV'],
+  'versions': [{ 'name': 'glStencilThenCoverStrokePathNV',
+                 'extensions': ['GL_NV_path_rendering'] },
+               { 'name': 'glStencilThenCoverStrokePathCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_path_rendering'] }],
   'arguments': 'GLuint path, GLint reference, GLuint mask, GLenum coverMode',
   'is_optional': True, },
 { 'return_type': 'GLboolean',
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index 2aeddbf6..97cc537 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -30,6 +30,9 @@
                                      GLuint colorNumber,
                                      GLuint index,
                                      const char* name) override;
+void glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                           GLint location,
+                                           const char* name) override;
 void glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) override;
 void glBindImageTextureEXTFn(GLuint index,
                              GLuint texture,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index f6447f7..e71f785 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -338,10 +338,14 @@
       gfx::HasExtension(extensions, "GL_CHROMIUM_copy_compressed_texture");
   ext.b_GL_CHROMIUM_copy_texture =
       gfx::HasExtension(extensions, "GL_CHROMIUM_copy_texture");
+  ext.b_GL_CHROMIUM_framebuffer_mixed_samples =
+      gfx::HasExtension(extensions, "GL_CHROMIUM_framebuffer_mixed_samples");
   ext.b_GL_CHROMIUM_gles_depth_binding_hack =
       gfx::HasExtension(extensions, "GL_CHROMIUM_gles_depth_binding_hack");
   ext.b_GL_CHROMIUM_glgetstringi_hack =
       gfx::HasExtension(extensions, "GL_CHROMIUM_glgetstringi_hack");
+  ext.b_GL_CHROMIUM_path_rendering =
+      gfx::HasExtension(extensions, "GL_CHROMIUM_path_rendering");
   ext.b_GL_EXT_blend_func_extended =
       gfx::HasExtension(extensions, "GL_EXT_blend_func_extended");
   ext.b_GL_EXT_debug_marker =
@@ -473,6 +477,12 @@
             GetGLProcAddress("glBindFragDataLocationIndexedEXT"));
   }
 
+  if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glBindFragmentInputLocationCHROMIUMFn =
+        reinterpret_cast<glBindFragmentInputLocationCHROMIUMProc>(
+            GetGLProcAddress("glBindFragmentInputLocationCHROMIUM"));
+  }
+
   if (ver->IsAtLeastGL(3u, 0u) || ver->is_es) {
     fn.glBindFramebufferEXTFn = reinterpret_cast<glBindFramebufferEXTProc>(
         GetGLProcAddress("glBindFramebuffer"));
@@ -656,28 +666,45 @@
   if (ext.b_GL_NV_framebuffer_mixed_samples) {
     fn.glCoverageModulationNVFn = reinterpret_cast<glCoverageModulationNVProc>(
         GetGLProcAddress("glCoverageModulationNV"));
+  } else if (ext.b_GL_CHROMIUM_framebuffer_mixed_samples) {
+    fn.glCoverageModulationNVFn = reinterpret_cast<glCoverageModulationNVProc>(
+        GetGLProcAddress("glCoverageModulationCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glCoverFillPathInstancedNVFn =
         reinterpret_cast<glCoverFillPathInstancedNVProc>(
             GetGLProcAddress("glCoverFillPathInstancedNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glCoverFillPathInstancedNVFn =
+        reinterpret_cast<glCoverFillPathInstancedNVProc>(
+            GetGLProcAddress("glCoverFillPathInstancedCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glCoverFillPathNVFn = reinterpret_cast<glCoverFillPathNVProc>(
         GetGLProcAddress("glCoverFillPathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glCoverFillPathNVFn = reinterpret_cast<glCoverFillPathNVProc>(
+        GetGLProcAddress("glCoverFillPathCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glCoverStrokePathInstancedNVFn =
         reinterpret_cast<glCoverStrokePathInstancedNVProc>(
             GetGLProcAddress("glCoverStrokePathInstancedNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glCoverStrokePathInstancedNVFn =
+        reinterpret_cast<glCoverStrokePathInstancedNVProc>(
+            GetGLProcAddress("glCoverStrokePathInstancedCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glCoverStrokePathNVFn = reinterpret_cast<glCoverStrokePathNVProc>(
         GetGLProcAddress("glCoverStrokePathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glCoverStrokePathNVFn = reinterpret_cast<glCoverStrokePathNVProc>(
+        GetGLProcAddress("glCoverStrokePathCHROMIUM"));
   }
 
   if (ver->IsAtLeastGL(4u, 3u) || ver->IsAtLeastGLES(3u, 2u)) {
@@ -727,6 +754,9 @@
   if (ext.b_GL_NV_path_rendering) {
     fn.glDeletePathsNVFn = reinterpret_cast<glDeletePathsNVProc>(
         GetGLProcAddress("glDeletePathsNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glDeletePathsNVFn = reinterpret_cast<glDeletePathsNVProc>(
+        GetGLProcAddress("glDeletePathsCHROMIUM"));
   }
 
   if (!ver->is_es || ver->IsAtLeastGLES(3u, 0u)) {
@@ -969,6 +999,9 @@
   if (ext.b_GL_NV_path_rendering) {
     fn.glGenPathsNVFn =
         reinterpret_cast<glGenPathsNVProc>(GetGLProcAddress("glGenPathsNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glGenPathsNVFn = reinterpret_cast<glGenPathsNVProc>(
+        GetGLProcAddress("glGenPathsCHROMIUM"));
   }
 
   if (!ver->is_es || ver->IsAtLeastGLES(3u, 0u)) {
@@ -1617,6 +1650,9 @@
   if (ext.b_GL_NV_path_rendering) {
     fn.glIsPathNVFn =
         reinterpret_cast<glIsPathNVProc>(GetGLProcAddress("glIsPathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glIsPathNVFn =
+        reinterpret_cast<glIsPathNVProc>(GetGLProcAddress("glIsPathCHROMIUM"));
   }
 
   if (!ver->is_es || ver->IsAtLeastGLES(3u, 0u)) {
@@ -1689,12 +1725,19 @@
   if (ext.b_GL_EXT_direct_state_access || ext.b_GL_NV_path_rendering) {
     fn.glMatrixLoadfEXTFn = reinterpret_cast<glMatrixLoadfEXTProc>(
         GetGLProcAddress("glMatrixLoadfEXT"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glMatrixLoadfEXTFn = reinterpret_cast<glMatrixLoadfEXTProc>(
+        GetGLProcAddress("glMatrixLoadfCHROMIUM"));
   }
 
   if (ext.b_GL_EXT_direct_state_access || ext.b_GL_NV_path_rendering) {
     fn.glMatrixLoadIdentityEXTFn =
         reinterpret_cast<glMatrixLoadIdentityEXTProc>(
             GetGLProcAddress("glMatrixLoadIdentityEXT"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glMatrixLoadIdentityEXTFn =
+        reinterpret_cast<glMatrixLoadIdentityEXTProc>(
+            GetGLProcAddress("glMatrixLoadIdentityCHROMIUM"));
   }
 
   if (ver->IsAtLeastGL(4u, 2u) || ver->IsAtLeastGLES(3u, 1u) ||
@@ -1725,21 +1768,33 @@
   if (ext.b_GL_NV_path_rendering) {
     fn.glPathCommandsNVFn = reinterpret_cast<glPathCommandsNVProc>(
         GetGLProcAddress("glPathCommandsNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glPathCommandsNVFn = reinterpret_cast<glPathCommandsNVProc>(
+        GetGLProcAddress("glPathCommandsCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glPathParameterfNVFn = reinterpret_cast<glPathParameterfNVProc>(
         GetGLProcAddress("glPathParameterfNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glPathParameterfNVFn = reinterpret_cast<glPathParameterfNVProc>(
+        GetGLProcAddress("glPathParameterfCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glPathParameteriNVFn = reinterpret_cast<glPathParameteriNVProc>(
         GetGLProcAddress("glPathParameteriNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glPathParameteriNVFn = reinterpret_cast<glPathParameteriNVProc>(
+        GetGLProcAddress("glPathParameteriCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glPathStencilFuncNVFn = reinterpret_cast<glPathStencilFuncNVProc>(
         GetGLProcAddress("glPathStencilFuncNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glPathStencilFuncNVFn = reinterpret_cast<glPathStencilFuncNVProc>(
+        GetGLProcAddress("glPathStencilFuncCHROMIUM"));
   }
 
   if (ver->IsAtLeastGLES(3u, 0u) || ver->IsAtLeastGL(4u, 0u) ||
@@ -1797,6 +1852,10 @@
     fn.glProgramPathFragmentInputGenNVFn =
         reinterpret_cast<glProgramPathFragmentInputGenNVProc>(
             GetGLProcAddress("glProgramPathFragmentInputGenNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glProgramPathFragmentInputGenNVFn =
+        reinterpret_cast<glProgramPathFragmentInputGenNVProc>(
+            GetGLProcAddress("glProgramPathFragmentInputGenCHROMIUM"));
   }
 
   if (ver->IsAtLeastGL(4u, 3u) || ver->IsAtLeastGLES(3u, 2u)) {
@@ -1958,46 +2017,76 @@
     fn.glStencilFillPathInstancedNVFn =
         reinterpret_cast<glStencilFillPathInstancedNVProc>(
             GetGLProcAddress("glStencilFillPathInstancedNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilFillPathInstancedNVFn =
+        reinterpret_cast<glStencilFillPathInstancedNVProc>(
+            GetGLProcAddress("glStencilFillPathInstancedCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilFillPathNVFn = reinterpret_cast<glStencilFillPathNVProc>(
         GetGLProcAddress("glStencilFillPathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilFillPathNVFn = reinterpret_cast<glStencilFillPathNVProc>(
+        GetGLProcAddress("glStencilFillPathCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilStrokePathInstancedNVFn =
         reinterpret_cast<glStencilStrokePathInstancedNVProc>(
             GetGLProcAddress("glStencilStrokePathInstancedNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilStrokePathInstancedNVFn =
+        reinterpret_cast<glStencilStrokePathInstancedNVProc>(
+            GetGLProcAddress("glStencilStrokePathInstancedCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilStrokePathNVFn = reinterpret_cast<glStencilStrokePathNVProc>(
         GetGLProcAddress("glStencilStrokePathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilStrokePathNVFn = reinterpret_cast<glStencilStrokePathNVProc>(
+        GetGLProcAddress("glStencilStrokePathCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilThenCoverFillPathInstancedNVFn =
         reinterpret_cast<glStencilThenCoverFillPathInstancedNVProc>(
             GetGLProcAddress("glStencilThenCoverFillPathInstancedNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilThenCoverFillPathInstancedNVFn =
+        reinterpret_cast<glStencilThenCoverFillPathInstancedNVProc>(
+            GetGLProcAddress("glStencilThenCoverFillPathInstancedCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilThenCoverFillPathNVFn =
         reinterpret_cast<glStencilThenCoverFillPathNVProc>(
             GetGLProcAddress("glStencilThenCoverFillPathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilThenCoverFillPathNVFn =
+        reinterpret_cast<glStencilThenCoverFillPathNVProc>(
+            GetGLProcAddress("glStencilThenCoverFillPathCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilThenCoverStrokePathInstancedNVFn =
         reinterpret_cast<glStencilThenCoverStrokePathInstancedNVProc>(
             GetGLProcAddress("glStencilThenCoverStrokePathInstancedNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilThenCoverStrokePathInstancedNVFn =
+        reinterpret_cast<glStencilThenCoverStrokePathInstancedNVProc>(
+            GetGLProcAddress("glStencilThenCoverStrokePathInstancedCHROMIUM"));
   }
 
   if (ext.b_GL_NV_path_rendering) {
     fn.glStencilThenCoverStrokePathNVFn =
         reinterpret_cast<glStencilThenCoverStrokePathNVProc>(
             GetGLProcAddress("glStencilThenCoverStrokePathNV"));
+  } else if (ext.b_GL_CHROMIUM_path_rendering) {
+    fn.glStencilThenCoverStrokePathNVFn =
+        reinterpret_cast<glStencilThenCoverStrokePathNVProc>(
+            GetGLProcAddress("glStencilThenCoverStrokePathCHROMIUM"));
   }
 
   if (ext.b_GL_APPLE_fence) {
@@ -2314,6 +2403,12 @@
                                               name);
 }
 
+void GLApiBase::glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                                      GLint location,
+                                                      const char* name) {
+  driver_->fn.glBindFragmentInputLocationCHROMIUMFn(program, location, name);
+}
+
 void GLApiBase::glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) {
   driver_->fn.glBindFramebufferEXTFn(target, framebuffer);
 }
@@ -4938,6 +5033,14 @@
   gl_api_->glBindFragDataLocationIndexedFn(program, colorNumber, index, name);
 }
 
+void TraceGLApi::glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                                       GLint location,
+                                                       const char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0(
+      "gpu", "TraceGLAPI::glBindFragmentInputLocationCHROMIUM")
+  gl_api_->glBindFragmentInputLocationCHROMIUMFn(program, location, name);
+}
+
 void TraceGLApi::glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindFramebufferEXT")
   gl_api_->glBindFramebufferEXTFn(target, framebuffer);
@@ -8024,6 +8127,14 @@
   gl_api_->glBindFragDataLocationIndexedFn(program, colorNumber, index, name);
 }
 
+void DebugGLApi::glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                                       GLint location,
+                                                       const char* name) {
+  GL_SERVICE_LOG("glBindFragmentInputLocationCHROMIUM"
+                 << "(" << program << ", " << location << ", " << name << ")");
+  gl_api_->glBindFragmentInputLocationCHROMIUMFn(program, location, name);
+}
+
 void DebugGLApi::glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) {
   GL_SERVICE_LOG("glBindFramebufferEXT"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << framebuffer
@@ -12077,6 +12188,12 @@
   NoContextHelper("glBindFragDataLocationIndexed");
 }
 
+void NoContextGLApi::glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                                           GLint location,
+                                                           const char* name) {
+  NoContextHelper("glBindFragmentInputLocationCHROMIUM");
+}
+
 void NoContextGLApi::glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) {
   NoContextHelper("glBindFramebufferEXT");
 }
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index 353ab36..4629e3a 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -44,6 +44,10 @@
     GLuint colorNumber,
     GLuint index,
     const char* name);
+typedef void(GL_BINDING_CALL* glBindFragmentInputLocationCHROMIUMProc)(
+    GLuint program,
+    GLint location,
+    const char* name);
 typedef void(GL_BINDING_CALL* glBindFramebufferEXTProc)(GLenum target,
                                                         GLuint framebuffer);
 typedef void(GL_BINDING_CALL* glBindImageTextureEXTProc)(GLuint index,
@@ -1539,8 +1543,10 @@
   bool b_GL_CHROMIUM_compressed_copy_texture;
   bool b_GL_CHROMIUM_copy_compressed_texture;
   bool b_GL_CHROMIUM_copy_texture;
+  bool b_GL_CHROMIUM_framebuffer_mixed_samples;
   bool b_GL_CHROMIUM_gles_depth_binding_hack;
   bool b_GL_CHROMIUM_glgetstringi_hack;
+  bool b_GL_CHROMIUM_path_rendering;
   bool b_GL_EXT_blend_func_extended;
   bool b_GL_EXT_debug_marker;
   bool b_GL_EXT_direct_state_access;
@@ -1593,6 +1599,7 @@
   glBindBufferRangeProc glBindBufferRangeFn;
   glBindFragDataLocationProc glBindFragDataLocationFn;
   glBindFragDataLocationIndexedProc glBindFragDataLocationIndexedFn;
+  glBindFragmentInputLocationCHROMIUMProc glBindFragmentInputLocationCHROMIUMFn;
   glBindFramebufferEXTProc glBindFramebufferEXTFn;
   glBindImageTextureEXTProc glBindImageTextureEXTFn;
   glBindRenderbufferEXTProc glBindRenderbufferEXTFn;
@@ -2024,6 +2031,9 @@
                                                GLuint colorNumber,
                                                GLuint index,
                                                const char* name) = 0;
+  virtual void glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                                     GLint location,
+                                                     const char* name) = 0;
   virtual void glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) = 0;
   virtual void glBindImageTextureEXTFn(GLuint index,
                                        GLuint texture,
@@ -3343,6 +3353,8 @@
   ::gl::g_current_gl_context->glBindFragDataLocationFn
 #define glBindFragDataLocationIndexed \
   ::gl::g_current_gl_context->glBindFragDataLocationIndexedFn
+#define glBindFragmentInputLocationCHROMIUM \
+  ::gl::g_current_gl_context->glBindFragmentInputLocationCHROMIUMFn
 #define glBindFramebufferEXT ::gl::g_current_gl_context->glBindFramebufferEXTFn
 #define glBindImageTextureEXT \
   ::gl::g_current_gl_context->glBindImageTextureEXTFn
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index cb8e0ed..9a93ba8 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -152,6 +152,14 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glBindFragmentInputLocationCHROMIUM(GLuint program,
+                                                          GLint location,
+                                                          const char* name) {
+  MakeFunctionUnique("glBindFragmentInputLocationCHROMIUM");
+  interface_->BindFragmentInputLocationCHROMIUM(program, location, name);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glBindFramebuffer(GLenum target, GLuint framebuffer) {
   MakeFunctionUnique("glBindFramebuffer");
   interface_->BindFramebufferEXT(target, framebuffer);
@@ -671,6 +679,26 @@
       destType, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glCoverFillPathCHROMIUM(GLuint path, GLenum coverMode) {
+  MakeFunctionUnique("glCoverFillPathCHROMIUM");
+  interface_->CoverFillPathNV(path, coverMode);
+}
+
+void GL_BINDING_CALL MockGLInterface::Mock_glCoverFillPathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLenum coverMode,
+    GLenum transformType,
+    const GLfloat* transformValues) {
+  MakeFunctionUnique("glCoverFillPathInstancedCHROMIUM");
+  interface_->CoverFillPathInstancedNV(numPaths, pathNameType, paths, pathBase,
+                                       coverMode, transformType,
+                                       transformValues);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glCoverFillPathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -691,6 +719,26 @@
   interface_->CoverFillPathNV(path, coverMode);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glCoverStrokePathCHROMIUM(GLuint name, GLenum coverMode) {
+  MakeFunctionUnique("glCoverStrokePathCHROMIUM");
+  interface_->CoverStrokePathNV(name, coverMode);
+}
+
+void GL_BINDING_CALL MockGLInterface::Mock_glCoverStrokePathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLenum coverMode,
+    GLenum transformType,
+    const GLfloat* transformValues) {
+  MakeFunctionUnique("glCoverStrokePathInstancedCHROMIUM");
+  interface_->CoverStrokePathInstancedNV(numPaths, pathNameType, paths,
+                                         pathBase, coverMode, transformType,
+                                         transformValues);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glCoverStrokePathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -712,6 +760,12 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glCoverageModulationCHROMIUM(GLenum components) {
+  MakeFunctionUnique("glCoverageModulationCHROMIUM");
+  interface_->CoverageModulationNV(components);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glCoverageModulationNV(GLenum components) {
   MakeFunctionUnique("glCoverageModulationNV");
   interface_->CoverageModulationNV(components);
@@ -822,6 +876,12 @@
   interface_->DeleteFramebuffersEXT(n, framebuffers);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glDeletePathsCHROMIUM(GLuint path, GLsizei range) {
+  MakeFunctionUnique("glDeletePathsCHROMIUM");
+  interface_->DeletePathsNV(path, range);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glDeletePathsNV(GLuint path,
                                                            GLsizei range) {
   MakeFunctionUnique("glDeletePathsNV");
@@ -1270,6 +1330,11 @@
   interface_->GenFramebuffersEXT(n, framebuffers);
 }
 
+GLuint GL_BINDING_CALL MockGLInterface::Mock_glGenPathsCHROMIUM(GLsizei range) {
+  MakeFunctionUnique("glGenPathsCHROMIUM");
+  return interface_->GenPathsNV(range);
+}
+
 GLuint GL_BINDING_CALL MockGLInterface::Mock_glGenPathsNV(GLsizei range) {
   MakeFunctionUnique("glGenPathsNV");
   return interface_->GenPathsNV(range);
@@ -2589,6 +2654,11 @@
   return interface_->IsFramebufferEXT(framebuffer);
 }
 
+GLboolean GL_BINDING_CALL MockGLInterface::Mock_glIsPathCHROMIUM(GLuint path) {
+  MakeFunctionUnique("glIsPathCHROMIUM");
+  return interface_->IsPathNV(path);
+}
+
 GLboolean GL_BINDING_CALL MockGLInterface::Mock_glIsPathNV(GLuint path) {
   MakeFunctionUnique("glIsPathNV");
   return interface_->IsPathNV(path);
@@ -2710,11 +2780,24 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glMatrixLoadIdentityCHROMIUM(GLenum matrixMode) {
+  MakeFunctionUnique("glMatrixLoadIdentityCHROMIUM");
+  interface_->MatrixLoadIdentityEXT(matrixMode);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glMatrixLoadIdentityEXT(GLenum matrixMode) {
   MakeFunctionUnique("glMatrixLoadIdentityEXT");
   interface_->MatrixLoadIdentityEXT(matrixMode);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glMatrixLoadfCHROMIUM(GLenum matrixMode,
+                                            const GLfloat* m) {
+  MakeFunctionUnique("glMatrixLoadfCHROMIUM");
+  interface_->MatrixLoadfEXT(matrixMode, m);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glMatrixLoadfEXT(GLenum matrixMode,
                                                             const GLfloat* m) {
   MakeFunctionUnique("glMatrixLoadfEXT");
@@ -2765,6 +2848,18 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glPathCommandsCHROMIUM(GLuint path,
+                                             GLsizei numCommands,
+                                             const GLubyte* commands,
+                                             GLsizei numCoords,
+                                             GLenum coordType,
+                                             const GLvoid* coords) {
+  MakeFunctionUnique("glPathCommandsCHROMIUM");
+  interface_->PathCommandsNV(path, numCommands, commands, numCoords, coordType,
+                             coords);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glPathCommandsNV(GLuint path,
                                        GLsizei numCommands,
                                        const GLubyte* commands,
@@ -2776,6 +2871,14 @@
                              coords);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glPathParameterfCHROMIUM(GLuint path,
+                                               GLenum pname,
+                                               GLfloat value) {
+  MakeFunctionUnique("glPathParameterfCHROMIUM");
+  interface_->PathParameterfNV(path, pname, value);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glPathParameterfNV(GLuint path,
                                                               GLenum pname,
                                                               GLfloat value) {
@@ -2783,6 +2886,14 @@
   interface_->PathParameterfNV(path, pname, value);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glPathParameteriCHROMIUM(GLuint path,
+                                               GLenum pname,
+                                               GLint value) {
+  MakeFunctionUnique("glPathParameteriCHROMIUM");
+  interface_->PathParameteriNV(path, pname, value);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glPathParameteriNV(GLuint path,
                                                               GLenum pname,
                                                               GLint value) {
@@ -2790,6 +2901,14 @@
   interface_->PathParameteriNV(path, pname, value);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glPathStencilFuncCHROMIUM(GLenum func,
+                                                GLint ref,
+                                                GLuint mask) {
+  MakeFunctionUnique("glPathStencilFuncCHROMIUM");
+  interface_->PathStencilFuncNV(func, ref, mask);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glPathStencilFuncNV(GLenum func,
                                                                GLint ref,
                                                                GLuint mask) {
@@ -2872,6 +2991,18 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glProgramPathFragmentInputGenCHROMIUM(
+    GLuint program,
+    GLint location,
+    GLenum genMode,
+    GLint components,
+    const GLfloat* coeffs) {
+  MakeFunctionUnique("glProgramPathFragmentInputGenCHROMIUM");
+  interface_->ProgramPathFragmentInputGenNV(program, location, genMode,
+                                            components, coeffs);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glProgramPathFragmentInputGenNV(GLuint program,
                                                       GLint location,
                                                       GLenum genMode,
@@ -3156,6 +3287,29 @@
   interface_->ShaderSource(shader, count, str, length);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glStencilFillPathCHROMIUM(GLuint path,
+                                                GLenum fillMode,
+                                                GLuint mask) {
+  MakeFunctionUnique("glStencilFillPathCHROMIUM");
+  interface_->StencilFillPathNV(path, fillMode, mask);
+}
+
+void GL_BINDING_CALL MockGLInterface::Mock_glStencilFillPathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLenum fillMode,
+    GLuint mask,
+    GLenum transformType,
+    const GLfloat* transformValues) {
+  MakeFunctionUnique("glStencilFillPathInstancedCHROMIUM");
+  interface_->StencilFillPathInstancedNV(numPaths, pathNameType, paths,
+                                         pathBase, fillMode, mask,
+                                         transformType, transformValues);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glStencilFillPathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -3219,6 +3373,29 @@
   interface_->StencilOpSeparate(face, fail, zfail, zpass);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glStencilStrokePathCHROMIUM(GLuint path,
+                                                  GLint reference,
+                                                  GLuint mask) {
+  MakeFunctionUnique("glStencilStrokePathCHROMIUM");
+  interface_->StencilStrokePathNV(path, reference, mask);
+}
+
+void GL_BINDING_CALL MockGLInterface::Mock_glStencilStrokePathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLint ref,
+    GLuint mask,
+    GLenum transformType,
+    const GLfloat* transformValues) {
+  MakeFunctionUnique("glStencilStrokePathInstancedCHROMIUM");
+  interface_->StencilStrokePathInstancedNV(numPaths, pathNameType, paths,
+                                           pathBase, ref, mask, transformType,
+                                           transformValues);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glStencilStrokePathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -3243,6 +3420,32 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glStencilThenCoverFillPathCHROMIUM(GLuint path,
+                                                         GLenum fillMode,
+                                                         GLuint mask,
+                                                         GLenum coverMode) {
+  MakeFunctionUnique("glStencilThenCoverFillPathCHROMIUM");
+  interface_->StencilThenCoverFillPathNV(path, fillMode, mask, coverMode);
+}
+
+void GL_BINDING_CALL
+MockGLInterface::Mock_glStencilThenCoverFillPathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLenum fillMode,
+    GLuint mask,
+    GLenum coverMode,
+    GLenum transformType,
+    const GLfloat* transformValues) {
+  MakeFunctionUnique("glStencilThenCoverFillPathInstancedCHROMIUM");
+  interface_->StencilThenCoverFillPathInstancedNV(
+      numPaths, pathNameType, paths, pathBase, fillMode, mask, coverMode,
+      transformType, transformValues);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glStencilThenCoverFillPathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -3269,6 +3472,32 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glStencilThenCoverStrokePathCHROMIUM(GLuint path,
+                                                           GLint reference,
+                                                           GLuint mask,
+                                                           GLenum coverMode) {
+  MakeFunctionUnique("glStencilThenCoverStrokePathCHROMIUM");
+  interface_->StencilThenCoverStrokePathNV(path, reference, mask, coverMode);
+}
+
+void GL_BINDING_CALL
+MockGLInterface::Mock_glStencilThenCoverStrokePathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLint ref,
+    GLuint mask,
+    GLenum coverMode,
+    GLenum transformType,
+    const GLfloat* transformValues) {
+  MakeFunctionUnique("glStencilThenCoverStrokePathInstancedCHROMIUM");
+  interface_->StencilThenCoverStrokePathInstancedNV(
+      numPaths, pathNameType, paths, pathBase, ref, mask, coverMode,
+      transformType, transformValues);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glStencilThenCoverStrokePathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -4083,6 +4312,9 @@
   if (strcmp(name, "glBindFragDataLocationIndexedEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glBindFragDataLocationIndexedEXT);
+  if (strcmp(name, "glBindFragmentInputLocationCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glBindFragmentInputLocationCHROMIUM);
   if (strcmp(name, "glBindFramebuffer") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glBindFramebuffer);
   if (strcmp(name, "glBindFramebufferEXT") == 0)
@@ -4204,16 +4436,31 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glCopyTexSubImage3D);
   if (strcmp(name, "glCopyTextureCHROMIUM") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glCopyTextureCHROMIUM);
+  if (strcmp(name, "glCoverFillPathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glCoverFillPathCHROMIUM);
+  if (strcmp(name, "glCoverFillPathInstancedCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glCoverFillPathInstancedCHROMIUM);
   if (strcmp(name, "glCoverFillPathInstancedNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glCoverFillPathInstancedNV);
   if (strcmp(name, "glCoverFillPathNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glCoverFillPathNV);
+  if (strcmp(name, "glCoverStrokePathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glCoverStrokePathCHROMIUM);
+  if (strcmp(name, "glCoverStrokePathInstancedCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glCoverStrokePathInstancedCHROMIUM);
   if (strcmp(name, "glCoverStrokePathInstancedNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glCoverStrokePathInstancedNV);
   if (strcmp(name, "glCoverStrokePathNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glCoverStrokePathNV);
+  if (strcmp(name, "glCoverageModulationCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glCoverageModulationCHROMIUM);
   if (strcmp(name, "glCoverageModulationNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glCoverageModulationNV);
   if (strcmp(name, "glCreateProgram") == 0)
@@ -4248,6 +4495,8 @@
   if (strcmp(name, "glDeleteFramebuffersEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glDeleteFramebuffersEXT);
+  if (strcmp(name, "glDeletePathsCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glDeletePathsCHROMIUM);
   if (strcmp(name, "glDeletePathsNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glDeletePathsNV);
   if (strcmp(name, "glDeleteProgram") == 0)
@@ -4401,6 +4650,8 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glGenFramebuffers);
   if (strcmp(name, "glGenFramebuffersEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glGenFramebuffersEXT);
+  if (strcmp(name, "glGenPathsCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glGenPathsCHROMIUM);
   if (strcmp(name, "glGenPathsNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glGenPathsNV);
   if (strcmp(name, "glGenQueries") == 0)
@@ -4780,6 +5031,8 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glIsFramebuffer);
   if (strcmp(name, "glIsFramebufferEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glIsFramebufferEXT);
+  if (strcmp(name, "glIsPathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glIsPathCHROMIUM);
   if (strcmp(name, "glIsPathNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glIsPathNV);
   if (strcmp(name, "glIsProgram") == 0)
@@ -4822,9 +5075,14 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glMapBufferRange);
   if (strcmp(name, "glMapBufferRangeEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glMapBufferRangeEXT);
+  if (strcmp(name, "glMatrixLoadIdentityCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glMatrixLoadIdentityCHROMIUM);
   if (strcmp(name, "glMatrixLoadIdentityEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glMatrixLoadIdentityEXT);
+  if (strcmp(name, "glMatrixLoadfCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glMatrixLoadfCHROMIUM);
   if (strcmp(name, "glMatrixLoadfEXT") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glMatrixLoadfEXT);
   if (strcmp(name, "glMemoryBarrier") == 0)
@@ -4839,12 +5097,23 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glObjectPtrLabel);
   if (strcmp(name, "glObjectPtrLabelKHR") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glObjectPtrLabelKHR);
+  if (strcmp(name, "glPathCommandsCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glPathCommandsCHROMIUM);
   if (strcmp(name, "glPathCommandsNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glPathCommandsNV);
+  if (strcmp(name, "glPathParameterfCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glPathParameterfCHROMIUM);
   if (strcmp(name, "glPathParameterfNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glPathParameterfNV);
+  if (strcmp(name, "glPathParameteriCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glPathParameteriCHROMIUM);
   if (strcmp(name, "glPathParameteriNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glPathParameteriNV);
+  if (strcmp(name, "glPathStencilFuncCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glPathStencilFuncCHROMIUM);
   if (strcmp(name, "glPathStencilFuncNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glPathStencilFuncNV);
   if (strcmp(name, "glPauseTransformFeedback") == 0)
@@ -4873,6 +5142,9 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glProgramBinaryOES);
   if (strcmp(name, "glProgramParameteri") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glProgramParameteri);
+  if (strcmp(name, "glProgramPathFragmentInputGenCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glProgramPathFragmentInputGenCHROMIUM);
   if (strcmp(name, "glProgramPathFragmentInputGenNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glProgramPathFragmentInputGenNV);
@@ -4954,6 +5226,12 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glShaderBinary);
   if (strcmp(name, "glShaderSource") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glShaderSource);
+  if (strcmp(name, "glStencilFillPathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilFillPathCHROMIUM);
+  if (strcmp(name, "glStencilFillPathInstancedCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilFillPathInstancedCHROMIUM);
   if (strcmp(name, "glStencilFillPathInstancedNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glStencilFillPathInstancedNV);
@@ -4971,17 +5249,35 @@
     return reinterpret_cast<GLFunctionPointerType>(Mock_glStencilOp);
   if (strcmp(name, "glStencilOpSeparate") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glStencilOpSeparate);
+  if (strcmp(name, "glStencilStrokePathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilStrokePathCHROMIUM);
+  if (strcmp(name, "glStencilStrokePathInstancedCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilStrokePathInstancedCHROMIUM);
   if (strcmp(name, "glStencilStrokePathInstancedNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glStencilStrokePathInstancedNV);
   if (strcmp(name, "glStencilStrokePathNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glStencilStrokePathNV);
+  if (strcmp(name, "glStencilThenCoverFillPathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilThenCoverFillPathCHROMIUM);
+  if (strcmp(name, "glStencilThenCoverFillPathInstancedCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilThenCoverFillPathInstancedCHROMIUM);
   if (strcmp(name, "glStencilThenCoverFillPathInstancedNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glStencilThenCoverFillPathInstancedNV);
   if (strcmp(name, "glStencilThenCoverFillPathNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glStencilThenCoverFillPathNV);
+  if (strcmp(name, "glStencilThenCoverStrokePathCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilThenCoverStrokePathCHROMIUM);
+  if (strcmp(name, "glStencilThenCoverStrokePathInstancedCHROMIUM") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(
+        Mock_glStencilThenCoverStrokePathInstancedCHROMIUM);
   if (strcmp(name, "glStencilThenCoverStrokePathInstancedNV") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glStencilThenCoverStrokePathInstancedNV);
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index edfa300..03b9186 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -53,6 +53,10 @@
                                       GLuint colorNumber,
                                       GLuint index,
                                       const char* name);
+static void GL_BINDING_CALL
+Mock_glBindFragmentInputLocationCHROMIUM(GLuint program,
+                                         GLint location,
+                                         const char* name);
 static void GL_BINDING_CALL Mock_glBindFramebuffer(GLenum target,
                                                    GLuint framebuffer);
 static void GL_BINDING_CALL Mock_glBindFramebufferEXT(GLenum target,
@@ -309,6 +313,16 @@
                            GLboolean unpackFlipY,
                            GLboolean unpackPremultiplyAlpha,
                            GLboolean unpackUnmultiplyAlpha);
+static void GL_BINDING_CALL Mock_glCoverFillPathCHROMIUM(GLuint path,
+                                                         GLenum coverMode);
+static void GL_BINDING_CALL
+Mock_glCoverFillPathInstancedCHROMIUM(GLsizei numPaths,
+                                      GLenum pathNameType,
+                                      const void* paths,
+                                      GLuint pathBase,
+                                      GLenum coverMode,
+                                      GLenum transformType,
+                                      const GLfloat* transformValues);
 static void GL_BINDING_CALL
 Mock_glCoverFillPathInstancedNV(GLsizei numPaths,
                                 GLenum pathNameType,
@@ -319,6 +333,16 @@
                                 const GLfloat* transformValues);
 static void GL_BINDING_CALL Mock_glCoverFillPathNV(GLuint path,
                                                    GLenum coverMode);
+static void GL_BINDING_CALL Mock_glCoverStrokePathCHROMIUM(GLuint name,
+                                                           GLenum coverMode);
+static void GL_BINDING_CALL
+Mock_glCoverStrokePathInstancedCHROMIUM(GLsizei numPaths,
+                                        GLenum pathNameType,
+                                        const void* paths,
+                                        GLuint pathBase,
+                                        GLenum coverMode,
+                                        GLenum transformType,
+                                        const GLfloat* transformValues);
 static void GL_BINDING_CALL
 Mock_glCoverStrokePathInstancedNV(GLsizei numPaths,
                                   GLenum pathNameType,
@@ -329,6 +353,8 @@
                                   const GLfloat* transformValues);
 static void GL_BINDING_CALL Mock_glCoverStrokePathNV(GLuint name,
                                                      GLenum coverMode);
+static void GL_BINDING_CALL
+Mock_glCoverageModulationCHROMIUM(GLenum components);
 static void GL_BINDING_CALL Mock_glCoverageModulationNV(GLenum components);
 static GLuint GL_BINDING_CALL Mock_glCreateProgram(void);
 static GLuint GL_BINDING_CALL Mock_glCreateShader(GLenum type);
@@ -371,6 +397,8 @@
 Mock_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
 static void GL_BINDING_CALL
 Mock_glDeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers);
+static void GL_BINDING_CALL Mock_glDeletePathsCHROMIUM(GLuint path,
+                                                       GLsizei range);
 static void GL_BINDING_CALL Mock_glDeletePathsNV(GLuint path, GLsizei range);
 static void GL_BINDING_CALL Mock_glDeleteProgram(GLuint program);
 static void GL_BINDING_CALL Mock_glDeleteQueries(GLsizei n, const GLuint* ids);
@@ -524,6 +552,7 @@
                                                    GLuint* framebuffers);
 static void GL_BINDING_CALL Mock_glGenFramebuffersEXT(GLsizei n,
                                                       GLuint* framebuffers);
+static GLuint GL_BINDING_CALL Mock_glGenPathsCHROMIUM(GLsizei range);
 static GLuint GL_BINDING_CALL Mock_glGenPathsNV(GLsizei range);
 static void GL_BINDING_CALL Mock_glGenQueries(GLsizei n, GLuint* ids);
 static void GL_BINDING_CALL Mock_glGenQueriesARB(GLsizei n, GLuint* ids);
@@ -1114,6 +1143,7 @@
 static GLboolean GL_BINDING_CALL Mock_glIsFenceNV(GLuint fence);
 static GLboolean GL_BINDING_CALL Mock_glIsFramebuffer(GLuint framebuffer);
 static GLboolean GL_BINDING_CALL Mock_glIsFramebufferEXT(GLuint framebuffer);
+static GLboolean GL_BINDING_CALL Mock_glIsPathCHROMIUM(GLuint path);
 static GLboolean GL_BINDING_CALL Mock_glIsPathNV(GLuint path);
 static GLboolean GL_BINDING_CALL Mock_glIsProgram(GLuint program);
 static GLboolean GL_BINDING_CALL Mock_glIsQuery(GLuint query);
@@ -1141,7 +1171,11 @@
                                                       GLintptr offset,
                                                       GLsizeiptr length,
                                                       GLbitfield access);
+static void GL_BINDING_CALL
+Mock_glMatrixLoadIdentityCHROMIUM(GLenum matrixMode);
 static void GL_BINDING_CALL Mock_glMatrixLoadIdentityEXT(GLenum matrixMode);
+static void GL_BINDING_CALL Mock_glMatrixLoadfCHROMIUM(GLenum matrixMode,
+                                                       const GLfloat* m);
 static void GL_BINDING_CALL Mock_glMatrixLoadfEXT(GLenum matrixMode,
                                                   const GLfloat* m);
 static void GL_BINDING_CALL Mock_glMemoryBarrier(GLbitfield barriers);
@@ -1160,18 +1194,33 @@
 static void GL_BINDING_CALL Mock_glObjectPtrLabelKHR(void* ptr,
                                                      GLsizei length,
                                                      const char* label);
+static void GL_BINDING_CALL Mock_glPathCommandsCHROMIUM(GLuint path,
+                                                        GLsizei numCommands,
+                                                        const GLubyte* commands,
+                                                        GLsizei numCoords,
+                                                        GLenum coordType,
+                                                        const GLvoid* coords);
 static void GL_BINDING_CALL Mock_glPathCommandsNV(GLuint path,
                                                   GLsizei numCommands,
                                                   const GLubyte* commands,
                                                   GLsizei numCoords,
                                                   GLenum coordType,
                                                   const GLvoid* coords);
+static void GL_BINDING_CALL Mock_glPathParameterfCHROMIUM(GLuint path,
+                                                          GLenum pname,
+                                                          GLfloat value);
 static void GL_BINDING_CALL Mock_glPathParameterfNV(GLuint path,
                                                     GLenum pname,
                                                     GLfloat value);
+static void GL_BINDING_CALL Mock_glPathParameteriCHROMIUM(GLuint path,
+                                                          GLenum pname,
+                                                          GLint value);
 static void GL_BINDING_CALL Mock_glPathParameteriNV(GLuint path,
                                                     GLenum pname,
                                                     GLint value);
+static void GL_BINDING_CALL Mock_glPathStencilFuncCHROMIUM(GLenum func,
+                                                           GLint ref,
+                                                           GLuint mask);
 static void GL_BINDING_CALL Mock_glPathStencilFuncNV(GLenum func,
                                                      GLint ref,
                                                      GLuint mask);
@@ -1196,6 +1245,12 @@
                                                      GLenum pname,
                                                      GLint value);
 static void GL_BINDING_CALL
+Mock_glProgramPathFragmentInputGenCHROMIUM(GLuint program,
+                                           GLint location,
+                                           GLenum genMode,
+                                           GLint components,
+                                           const GLfloat* coeffs);
+static void GL_BINDING_CALL
 Mock_glProgramPathFragmentInputGenNV(GLuint program,
                                      GLint location,
                                      GLenum genMode,
@@ -1327,6 +1382,18 @@
                                                 GLsizei count,
                                                 const char* const* str,
                                                 const GLint* length);
+static void GL_BINDING_CALL Mock_glStencilFillPathCHROMIUM(GLuint path,
+                                                           GLenum fillMode,
+                                                           GLuint mask);
+static void GL_BINDING_CALL
+Mock_glStencilFillPathInstancedCHROMIUM(GLsizei numPaths,
+                                        GLenum pathNameType,
+                                        const void* paths,
+                                        GLuint pathBase,
+                                        GLenum fillMode,
+                                        GLuint mask,
+                                        GLenum transformType,
+                                        const GLfloat* transformValues);
 static void GL_BINDING_CALL
 Mock_glStencilFillPathInstancedNV(GLsizei numPaths,
                                   GLenum pathNameType,
@@ -1356,6 +1423,18 @@
                                                      GLenum fail,
                                                      GLenum zfail,
                                                      GLenum zpass);
+static void GL_BINDING_CALL Mock_glStencilStrokePathCHROMIUM(GLuint path,
+                                                             GLint reference,
+                                                             GLuint mask);
+static void GL_BINDING_CALL
+Mock_glStencilStrokePathInstancedCHROMIUM(GLsizei numPaths,
+                                          GLenum pathNameType,
+                                          const void* paths,
+                                          GLuint pathBase,
+                                          GLint ref,
+                                          GLuint mask,
+                                          GLenum transformType,
+                                          const GLfloat* transformValues);
 static void GL_BINDING_CALL
 Mock_glStencilStrokePathInstancedNV(GLsizei numPaths,
                                     GLenum pathNameType,
@@ -1369,6 +1448,21 @@
                                                        GLint reference,
                                                        GLuint mask);
 static void GL_BINDING_CALL
+Mock_glStencilThenCoverFillPathCHROMIUM(GLuint path,
+                                        GLenum fillMode,
+                                        GLuint mask,
+                                        GLenum coverMode);
+static void GL_BINDING_CALL Mock_glStencilThenCoverFillPathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLenum fillMode,
+    GLuint mask,
+    GLenum coverMode,
+    GLenum transformType,
+    const GLfloat* transformValues);
+static void GL_BINDING_CALL
 Mock_glStencilThenCoverFillPathInstancedNV(GLsizei numPaths,
                                            GLenum pathNameType,
                                            const void* paths,
@@ -1383,6 +1477,21 @@
                                                               GLuint mask,
                                                               GLenum coverMode);
 static void GL_BINDING_CALL
+Mock_glStencilThenCoverStrokePathCHROMIUM(GLuint path,
+                                          GLint reference,
+                                          GLuint mask,
+                                          GLenum coverMode);
+static void GL_BINDING_CALL Mock_glStencilThenCoverStrokePathInstancedCHROMIUM(
+    GLsizei numPaths,
+    GLenum pathNameType,
+    const void* paths,
+    GLuint pathBase,
+    GLint ref,
+    GLuint mask,
+    GLenum coverMode,
+    GLenum transformType,
+    const GLfloat* transformValues);
+static void GL_BINDING_CALL
 Mock_glStencilThenCoverStrokePathInstancedNV(GLsizei numPaths,
                                              GLenum pathNameType,
                                              const void* paths,
diff --git a/ui/gl/gl_enums_implementation_autogen.h b/ui/gl/gl_enums_implementation_autogen.h
index aad18bf..9a8be38 100644
--- a/ui/gl/gl_enums_implementation_autogen.h
+++ b/ui/gl/gl_enums_implementation_autogen.h
@@ -1411,6 +1411,9 @@
         0x84F7, "GL_COMMANDS_COMPLETED_CHROMIUM",
     },
     {
+        0x84F8, "GL_READBACK_SHADOW_COPIES_UPDATED_CHROMIUM",
+    },
+    {
         0x84F9, "GL_DEPTH_STENCIL_OES",
     },
     {
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index 002a1fe..3d62e876 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -28,6 +28,8 @@
 MOCK_METHOD4(
     BindFragDataLocationIndexed,
     void(GLuint program, GLuint colorNumber, GLuint index, const char* name));
+MOCK_METHOD3(BindFragmentInputLocationCHROMIUM,
+             void(GLuint program, GLint location, const char* name));
 MOCK_METHOD2(BindFramebufferEXT, void(GLenum target, GLuint framebuffer));
 MOCK_METHOD7(BindImageTextureEXT,
              void(GLuint index,
diff --git a/ui/gl/gl_stub_autogen_gl.h b/ui/gl/gl_stub_autogen_gl.h
index 32160fa..0a97968 100644
--- a/ui/gl/gl_stub_autogen_gl.h
+++ b/ui/gl/gl_stub_autogen_gl.h
@@ -30,6 +30,9 @@
                                      GLuint colorNumber,
                                      GLuint index,
                                      const char* name) override {}
+void glBindFragmentInputLocationCHROMIUMFn(GLuint program,
+                                           GLint location,
+                                           const char* name) override {}
 void glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) override {}
 void glBindImageTextureEXTFn(GLuint index,
                              GLuint texture,
diff --git a/ui/gl/init/create_gr_gl_interface.cc b/ui/gl/init/create_gr_gl_interface.cc
index 7028839..7bbf552 100644
--- a/ui/gl/init/create_gr_gl_interface.cc
+++ b/ui/gl/init/create_gr_gl_interface.cc
@@ -293,6 +293,8 @@
       gl->glStencilThenCoverStrokePathInstancedNVFn;
   functions->fProgramPathFragmentInputGen =
       gl->glProgramPathFragmentInputGenNVFn;
+  functions->fBindFragmentInputLocation =
+      gl->glBindFragmentInputLocationCHROMIUMFn;
 
   functions->fCoverageModulation = gl->glCoverageModulationNVFn;
 
diff --git a/ui/ozone/public/ozone_switches.cc b/ui/ozone/public/ozone_switches.cc
index 7cb8a31..0a9b3ab32 100644
--- a/ui/ozone/public/ozone_switches.cc
+++ b/ui/ozone/public/ozone_switches.cc
@@ -12,9 +12,4 @@
 // Specify location for image dumps.
 const char kOzoneDumpFile[] = "ozone-dump-file";
 
-// Use mojo communication in the drm platform instead of paramtraits. Remove
-// this switch (and associated code) when the drm platform always uses mojo
-// communication.
-const char kEnableDrmMojo[] = "enable-drm-mojo";
-
 }  // namespace switches
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h
index 7720c37..b062e67 100644
--- a/ui/ozone/public/ozone_switches.h
+++ b/ui/ozone/public/ozone_switches.h
@@ -14,8 +14,6 @@
 
 OZONE_BASE_EXPORT extern const char kOzoneDumpFile[];
 
-OZONE_BASE_EXPORT extern const char kEnableDrmMojo[];
-
 }  // namespace switches
 
 #endif  // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_